@wirecat/cli-core 0.551.0 → 0.552.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 (67) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +1 -1
  3. package/dist/background/schedules.d.ts +12 -1
  4. package/dist/background/schedules.js +65 -24
  5. package/dist/background/units.d.ts +16 -9
  6. package/dist/background/units.js +26 -11
  7. package/dist/cli/context.d.ts +2 -0
  8. package/dist/cli/meeting-preparation-answer.d.ts +3 -0
  9. package/dist/cli/meeting-preparation-projects.d.ts +3 -0
  10. package/dist/cli/meeting-preparation-read.d.ts +3 -0
  11. package/dist/cli/messenger/search-answers.js +8 -1
  12. package/dist/cli/messenger/serve-catch-up.d.ts +43 -0
  13. package/dist/cli/messenger/serve-catch-up.js +90 -0
  14. package/dist/cli/messenger/serve-command.js +54 -1
  15. package/dist/cli/messenger/server-command.d.ts +4 -3
  16. package/dist/cli/messenger/server-command.js +30 -12
  17. package/dist/cli/program.js +9 -4
  18. package/dist/cli/schedule/schedule-command.js +5 -1
  19. package/dist/entities/hit.d.ts +5 -0
  20. package/dist/entities/hit.js +5 -0
  21. package/dist/entities/index.d.ts +27 -0
  22. package/dist/entities/listener.d.ts +6 -0
  23. package/dist/entities/listener.js +1 -0
  24. package/dist/entities/meeting-preparation.d.ts +3 -0
  25. package/dist/errors/reasons.js +1 -0
  26. package/dist/mcp/meeting-preparation.d.ts +3 -0
  27. package/dist/meetings/answers.d.ts +5 -0
  28. package/dist/meetings/answers.js +8 -0
  29. package/dist/meetings/cli/index.js +14 -0
  30. package/dist/meetings/index.d.ts +2 -1
  31. package/dist/meetings/index.js +1 -0
  32. package/dist/meetings/ingest.js +2 -1
  33. package/dist/meetings/language.d.ts +5 -0
  34. package/dist/meetings/language.js +57 -0
  35. package/dist/meetings/mcp/search.d.ts +3 -0
  36. package/dist/meetings/project-evidence-answer.d.ts +3 -0
  37. package/dist/meetings/result-items.d.ts +9 -0
  38. package/dist/meetings/result-items.js +7 -0
  39. package/dist/meetings/store.d.ts +22 -0
  40. package/dist/meetings/testing/memory.js +3 -0
  41. package/dist/meetings/transcription.d.ts +2 -0
  42. package/dist/meetings/transcription.js +5 -1
  43. package/dist/search/lucene/types.d.ts +7 -0
  44. package/dist/search/lucene/types.js +11 -1
  45. package/dist/services/messages-archive-search.js +3 -2
  46. package/dist/services/messages-combined.js +2 -2
  47. package/dist/services/messages-discovery.js +2 -2
  48. package/dist/services/notes-search.js +4 -5
  49. package/dist/services/search-all-meetings.d.ts +3 -0
  50. package/dist/services/search-all-meetings.js +6 -1
  51. package/dist/speech/local.d.ts +2 -0
  52. package/dist/speech/local.js +8 -1
  53. package/dist/speech/models.d.ts +2 -0
  54. package/dist/speech/models.js +2 -0
  55. package/dist/store/driver.d.ts +11 -0
  56. package/dist/store/driver.js +13 -0
  57. package/dist/store/drivers/node-sqlite.d.ts +1 -1
  58. package/dist/store/drivers/node-sqlite.js +3 -0
  59. package/dist/store/sqlite/lucene.d.ts +1 -1
  60. package/dist/store/sqlite/lucene.js +33 -7
  61. package/dist/store/sqlite/meeting-hit-search.js +10 -3
  62. package/dist/store/sqlite/meeting-languages.d.ts +4 -0
  63. package/dist/store/sqlite/meeting-languages.js +36 -0
  64. package/dist/store/sqlite/meetings.d.ts +2 -1
  65. package/dist/store/sqlite/meetings.js +9 -3
  66. package/dist/store/sqlite/note-search.js +2 -2
  67. package/package.json +1 -1
@@ -2,7 +2,9 @@ import { CliError } from "@wirecat/cli-base";
2
2
  import { annotate } from "@wirecat/cli-base/commands";
3
3
  import { Command } from "commander";
4
4
  import { holdLock, lockPath, releaseLock, takeLock } from "../../background/lock.js";
5
+ import { parseDuration } from "../../domain/duration.js";
5
6
  import { failureKey } from "../../errors/failures.js";
7
+ import { capability } from "../../ports/messenger.js";
6
8
  import { senderFacts } from "../../replies/dry-run.js";
7
9
  import { replyRenderer } from "../../replies/rendering.js";
8
10
  import { audienceWarnings, readReplies, repliesPathFor } from "../../replies/rules.js";
@@ -10,14 +12,17 @@ import { NO_RULES, replyTo } from "../../replies/serve.js";
10
12
  import { repliesStatePathFor } from "../../replies/state.js";
11
13
  import { levelFor } from "../../sends/permissions.js";
12
14
  import { newSendId } from "../../sends/send-id.js";
15
+ import { FETCHING } from "../../services/archive.js";
13
16
  import { onlineDeps } from "../../services/deps.js";
14
17
  import { servicesFor } from "../../services/index.js";
18
+ import { patiently } from "../../services/patience.js";
15
19
  import { applyTaskRulesOnArrival, openRequestTask } from "../../services/task-rules.js";
16
20
  import { environmentOf } from "../context.js";
17
21
  import { REMOTE_WRITE } from "../effects.js";
18
22
  import { itemOf, renderAnswer } from "../envelope.js";
19
23
  import { recalledAccount } from "./accounts.js";
20
24
  import { messengerContext } from "./context.js";
25
+ import { START_SYNC_PER_CHAT, startSync } from "./serve-catch-up.js";
21
26
  import { memberFetches } from "./serve-members.js";
22
27
  import { noticeFor, recordDiagnostics } from "./serve-notice.js";
23
28
  import { serveRelay } from "./serve-relay.js";
@@ -75,7 +80,7 @@ export const serveCommand = (messenger) => {
75
80
  const counts = {};
76
81
  const rules = replying(context, messenger, Date.parse(startedAt));
77
82
  const tasks = tasking(context, warn);
78
- const { handled } = environmentOf(this);
83
+ const { handled, startSyncDelayMs } = environmentOf(this);
79
84
  const count = (event) => {
80
85
  counts[event.event] = (counts[event.event] ?? 0) + 1;
81
86
  if (event.event === "message") {
@@ -99,6 +104,50 @@ export const serveCommand = (messenger) => {
99
104
  }).chats.fetchMembers(chatId, {}),
100
105
  warn,
101
106
  });
107
+ const fetching = messenger.fetching ?? FETCHING;
108
+ const catchingUp = startSync({
109
+ chats: async (stop) => {
110
+ const list = capability(connection, "chats", "list its chats");
111
+ const all = [];
112
+ for (let offset = 0;;) {
113
+ const page = await patiently(() => list({ offset, limit: 100 }), context.renderer.note, stop);
114
+ for (const chat of page.items)
115
+ all.push(chat);
116
+ offset += page.items.length;
117
+ if (!page.hasMore || page.items.length === 0)
118
+ return all;
119
+ }
120
+ },
121
+ newestHeld: (chatId) => context.withStore(async (store, account) => {
122
+ // What this serve stored itself would hide the gap before it.
123
+ const [newest] = await store.messages.messagesWindow(account, chatId, {
124
+ at: startedAt,
125
+ before: 1,
126
+ after: 0,
127
+ });
128
+ return newest ? Date.parse(newest.timestamp) : undefined;
129
+ }, { name: "serve catch-up" }),
130
+ fetch: (chatId, sinceMs, stop) => context.withStore((store, account) => servicesFor({
131
+ ...onlineDeps(messenger, connection, context.guard, {
132
+ profile: context.profile,
133
+ env: context.env,
134
+ }),
135
+ store: async () => store,
136
+ account: async () => account,
137
+ }).archive.fetch(chatId, {
138
+ limit: START_SYNC_PER_CHAT,
139
+ pageSize: fetching.page,
140
+ pauseMs: parseDuration(fetching.pause, "pause"),
141
+ sinceMs,
142
+ catchUp: false,
143
+ note: context.renderer.note,
144
+ stop,
145
+ onPage: () => { },
146
+ }), { name: "serve catch-up" }),
147
+ note,
148
+ warn,
149
+ ...(startSyncDelayMs === undefined ? {} : { delayMs: startSyncDelayMs }),
150
+ });
102
151
  const stems = stemFills({
103
152
  withStore: (work) => context.withStore((store) => work(store), { name: "serve stems" }),
104
153
  warn,
@@ -113,6 +162,8 @@ export const serveCommand = (messenger) => {
113
162
  rules.connected(open);
114
163
  members.start();
115
164
  stems.start();
165
+ if (messenger.history !== "store" && typeof open.chats === "function")
166
+ catchingUp.start();
116
167
  },
117
168
  });
118
169
  }
@@ -120,6 +171,7 @@ export const serveCommand = (messenger) => {
120
171
  await relaying;
121
172
  await relay?.close();
122
173
  rules.stop();
174
+ await catchingUp.stop();
123
175
  await members.stop();
124
176
  await stems.stop();
125
177
  await rules.settled();
@@ -135,6 +187,7 @@ export const serveCommand = (messenger) => {
135
187
  ...rules.summary(),
136
188
  ...(members.summary().fetched + members.summary().failed > 0 ? { members: members.summary() } : {}),
137
189
  ...(stems.summary().stemmed > 0 ? { stems: stems.summary() } : {}),
190
+ ...(catchingUp.summary() ? { caught_up: catchingUp.summary() } : {}),
138
191
  ...tasks.summary(),
139
192
  }));
140
193
  });
@@ -35,8 +35,9 @@ export interface ServerOptions {
35
35
  /**
36
36
  * `serve` in the background: `start`, `stop`, `restart`, `status`, `logs`. Without a unit, `start`
37
37
  * runs `serve` as a process of its own; with one — `install`, a systemd user unit or a launchd
38
- * agent — it goes through systemd or launchd. **Nothing starts until `start` is typed** (NEED-9):
39
- * `install` only writes the file. What the server does stays each CLI's; `options.process` says how
40
- * to find, start and stop it.
38
+ * agent — it goes through systemd or launchd. **Nothing starts now until `start` is typed** (NEED-9):
39
+ * `install` writes the file and enables it, so it starts with every session from the next login (or boot,
40
+ * under linger) until `uninstall`. What the server does stays each CLI's; `options.process` says how to find,
41
+ * start and stop it.
41
42
  */
42
43
  export declare const serverCommand: (messenger: Messenger, options?: ServerOptions) => Command;
@@ -54,9 +54,10 @@ const lockProcess = (app, marker, serveArgv) => (context, system, logPath) => ({
54
54
  /**
55
55
  * `serve` in the background: `start`, `stop`, `restart`, `status`, `logs`. Without a unit, `start`
56
56
  * runs `serve` as a process of its own; with one — `install`, a systemd user unit or a launchd
57
- * agent — it goes through systemd or launchd. **Nothing starts until `start` is typed** (NEED-9):
58
- * `install` only writes the file. What the server does stays each CLI's; `options.process` says how
59
- * to find, start and stop it.
57
+ * agent — it goes through systemd or launchd. **Nothing starts now until `start` is typed** (NEED-9):
58
+ * `install` writes the file and enables it, so it starts with every session from the next login (or boot,
59
+ * under linger) until `uninstall`. What the server does stays each CLI's; `options.process` says how to find,
60
+ * start and stop it.
60
61
  */
61
62
  export const serverCommand = (messenger, options = {}) => {
62
63
  const { app } = messenger;
@@ -226,8 +227,11 @@ export const serverCommand = (messenger, options = {}) => {
226
227
  : undefined;
227
228
  const gaveUpReason = gaveUp === undefined ? undefined : Object.entries(EXIT_CODES).find(([, code]) => code === gaveUp)?.[0];
228
229
  const flood = new FloodMemory(floodPathFor(app, unit.profile, context.env)).read();
230
+ const startsAtLogin = isInstalled && state.enabled === true;
229
231
  const unitLine = isInstalled
230
- ? `Unit: ${tilde(unit.path, context.env)} — ${state.detail ?? (state.active ? "active" : "inactive")}.`
232
+ ? `Unit: ${tilde(unit.path, context.env)} — ${state.detail ?? (state.active ? "active" : "inactive")}, ${startsAtLogin
233
+ ? "starts at login."
234
+ : `does not start at login — \`${app.command} ${unit.profile} server install\` turns that on.`}`
231
235
  : `No unit installed — \`${app.command} ${unit.profile} server install\` adds one, for starting under systemd or launchd.`;
232
236
  say({
233
237
  profile: unit.profile,
@@ -248,6 +252,7 @@ export const serverCommand = (messenger, options = {}) => {
248
252
  ...(gaveUp !== undefined
249
253
  ? { stopped: { exitCode: gaveUp, reason: gaveUpReason ?? null, restarts: false } }
250
254
  : {}),
255
+ startsAtLogin,
251
256
  unit: { name: unit.name, path: unit.path, installed: isInstalled, ...state },
252
257
  flood: { deadlines: flood.deadlines, sendBlock: flood.sendBlock ?? null },
253
258
  }, [
@@ -293,16 +298,28 @@ export const serverCommand = (messenger, options = {}) => {
293
298
  effects: LOCAL_WRITE,
294
299
  examples: [`${app.command} personal server install`],
295
300
  }))
296
- .description("write a systemd user unit or a launchd agent for this profile; starts nothing")
297
- .action(function () {
298
- const { context, platform, unit, say } = prepare(this);
301
+ .summary("install this profile's background server to start at every login")
302
+ .description("write a systemd user unit or a launchd agent for this profile and have it start at every login; starts nothing now")
303
+ .action(async function () {
304
+ const { context, platform, unit, each, say } = prepare(this);
299
305
  const replaced = existsSync(unit.path);
300
306
  writeSecurely(unit.path, platform.text(unit, app), 0o644);
301
307
  platform.prepare?.(unit);
302
- say({ profile: unit.profile, unit: unit.name, path: unit.path, command: unit.command, replaced }, [
303
- `${replaced ? "Rewrote" : "Wrote"} ${tilde(unit.path, context.env)} — nothing started.`,
308
+ // A unit of moved folders runs a development checkout, which must not start at every login on the owner's keyring.
309
+ const moved = Object.keys(locationVariables(app, context.env)).length > 0;
310
+ if (!moved)
311
+ await each(platform.install(unit));
312
+ say({
313
+ profile: unit.profile,
314
+ unit: unit.name,
315
+ path: unit.path,
316
+ command: unit.command,
317
+ replaced,
318
+ startsAtLogin: !moved,
319
+ }, [
320
+ `${replaced ? "Rewrote" : "Wrote"} ${tilde(unit.path, context.env)} — ${moved ? "with moved folders it does not start at login" : "it starts at every login"}, nothing started now.`,
304
321
  `It runs: ${unit.command.map((word) => tilde(word, context.env)).join(" ")}`,
305
- `Start it now: ${app.command} ${unit.profile} server start · ${platform.atLogin(unit)}`,
322
+ `Start it now: ${app.command} ${unit.profile} server start · never at login: ${app.command} ${unit.profile} server uninstall`,
306
323
  // Suggested, never turned on: an agent reading chats every morning is the owner's choice (NEED-161).
307
324
  `A daily follow-up review is off. To turn it on: ${app.command} ${unit.profile} schedule agent follow-ups claude "${followUpsPrompt(app.command)}" --at 08:30`,
308
325
  ]);
@@ -311,13 +328,14 @@ export const serverCommand = (messenger, options = {}) => {
311
328
  effects: LOCAL_WRITE,
312
329
  examples: [`${app.command} personal server uninstall`],
313
330
  }))
314
- .description("remove this profile's unit; stop it first")
331
+ .description("remove this profile's unit, so it no longer starts at login; stop it first")
315
332
  .action(async function () {
316
- const { context, platform, unit, say } = prepare(this);
333
+ const { context, platform, unit, each, say } = prepare(this);
317
334
  installed(unit);
318
335
  if ((await platform.state(unit)).active) {
319
336
  throw new CliError("validation_error", `the unit is running — \`${app.command} ${unit.profile} server stop\` first`);
320
337
  }
338
+ await each(platform.uninstall(unit));
321
339
  rmSync(unit.path, { force: true });
322
340
  say({ profile: unit.profile, unit: unit.name, path: unit.path, removed: true }, [
323
341
  `Removed ${tilde(unit.path, context.env)}.`,
@@ -192,11 +192,15 @@ const runOnce = async (argv, definition, options) => {
192
192
  };
193
193
  const sigint = () => interrupted("SIGINT");
194
194
  const sigterm = () => interrupted("SIGTERM");
195
+ // A sync, or a one-shot's wait on work it started (`schedule run`), outlives its reader: a desktop that closed the
196
+ // pipe 18 minutes in must not lose the sync, and the run record still says how it ended. Its later lines go
197
+ // nowhere. A listening command's stream is its work, so it still ends.
198
+ let outlivesReader = false;
195
199
  const pipeError = (error) => {
196
- if (error.code === "EPIPE") {
197
- signalExit = 0;
198
- control.abort(error);
199
- }
200
+ if (error.code !== "EPIPE" || outlivesReader || (phased && !listens))
201
+ return;
202
+ signalExit = 0;
203
+ control.abort(error);
200
204
  };
201
205
  const externalAbort = () => {
202
206
  const cancelled = new CliError("cancelled", "command cancelled", { retryable: false });
@@ -343,6 +347,7 @@ const runOnce = async (argv, definition, options) => {
343
347
  const { lifetime, cooperative: stopsAtItsPace, partial: answersPartial } = metaOf(action);
344
348
  const persistent = lifetime === "persistent";
345
349
  listens = persistent;
350
+ outlivesReader = stopsAtItsPace === true;
346
351
  const interactiveLogin = !headless && lifetime === "interactive";
347
352
  const timeout = flags.timeout ?? (commandEnv[envName(definition.app, "TIMEOUT")]?.trim() || undefined);
348
353
  // A background fetch was asked to outlive the shell; only an explicit --timeout bounds it.
@@ -268,7 +268,11 @@ export const scheduleCommandFor = ({ app, context: contextOf }) => {
268
268
  .action(async function (file) {
269
269
  // A timer starts it with no profile named; the schedule's own environment carries the profile.
270
270
  const { context, system, timer } = prepare(this, { needsProfile: false });
271
- const last = await untilChildEnds(this, (signal) => runSchedule(app, system, context.env, file, { timer: timer(), ...(signal ? { signal } : {}) }));
271
+ const last = await untilChildEnds(this, (signal) => runSchedule(app, system, context.env, file, {
272
+ timer: timer(),
273
+ untilUnlocked: true,
274
+ ...(signal ? { signal } : {}),
275
+ }));
272
276
  if (last.exitCode !== 0)
273
277
  setExitCode(this, 1);
274
278
  });
@@ -24,6 +24,11 @@ export declare const hit: v.StrictObjectSchema<{
24
24
  readonly scope: v.OptionalSchema<v.PicklistSchema<["transcript", "chat", "summary"], undefined>, undefined>;
25
25
  /** A meeting transcript hit's cue, which `meetings passage` opens with the lines around it. */
26
26
  readonly cue_ref: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
27
+ /** A meeting transcript hit's transcript language (`ru`, `en`…), `null` when unknown. */
28
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
29
+ /** A meeting transcript hit's line, from 1, of `lines_total` lines in its transcript. */
30
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
31
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
27
32
  /** A meeting passage's stored line, so two passages of one meeting stay apart; `search meetings` gives the same. */
28
33
  readonly id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
29
34
  /** A message's files; absent when it has none. */
@@ -26,6 +26,11 @@ export const hit = v.strictObject({
26
26
  scope: v.optional(v.picklist(["transcript", "chat", "summary"])),
27
27
  /** A meeting transcript hit's cue, which `meetings passage` opens with the lines around it. */
28
28
  cue_ref: v.optional(reference),
29
+ /** A meeting transcript hit's transcript language (`ru`, `en`…), `null` when unknown. */
30
+ language: v.optional(v.nullable(text)),
31
+ /** A meeting transcript hit's line, from 1, of `lines_total` lines in its transcript. */
32
+ line: v.optional(v.pipe(count, v.minValue(1))),
33
+ lines_total: v.optional(count),
29
34
  /** A meeting passage's stored line, so two passages of one meeting stay apart; `search meetings` gives the same. */
30
35
  id: v.optional(v.pipe(v.string(), v.minLength(1))),
31
36
  /** A message's files; absent when it has none. */
@@ -214,6 +214,15 @@ export declare const ENTITIES: {
214
214
  readonly next_transcript_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
215
215
  }, undefined>;
216
216
  }, undefined>], undefined>;
217
+ readonly meeting_repair: v.StrictObjectSchema<{
218
+ readonly account_id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
219
+ readonly applied: v.BooleanSchema<undefined>;
220
+ readonly transcripts: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
221
+ readonly languages: v.ArraySchema<v.StrictObjectSchema<{
222
+ readonly language: v.NullableSchema<v.StringSchema<undefined>, undefined>;
223
+ readonly transcripts: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
224
+ }, undefined>, undefined>;
225
+ }, undefined>;
217
226
  readonly sync_progress: v.StrictObjectSchema<{
218
227
  readonly job: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
219
228
  readonly profile: v.StringSchema<undefined>;
@@ -4575,6 +4584,9 @@ export declare const ENTITIES: {
4575
4584
  readonly offset_ms: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
4576
4585
  readonly scope: v.OptionalSchema<v.PicklistSchema<["transcript", "chat", "summary"], undefined>, undefined>;
4577
4586
  readonly cue_ref: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
4587
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
4588
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
4589
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
4578
4590
  readonly id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
4579
4591
  readonly attachments: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
4580
4592
  readonly position: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
@@ -5625,6 +5637,9 @@ export declare const ENTITIES: {
5625
5637
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
5626
5638
  readonly excerpt: v.StringSchema<undefined>;
5627
5639
  readonly offset_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
5640
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
5641
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
5642
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
5628
5643
  readonly match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
5629
5644
  readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
5630
5645
  readonly from: v.StringSchema<undefined>;
@@ -5790,6 +5805,9 @@ export declare const ENTITIES: {
5790
5805
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
5791
5806
  readonly excerpt: v.StringSchema<undefined>;
5792
5807
  readonly offset_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
5808
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
5809
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
5810
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
5793
5811
  readonly match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
5794
5812
  readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
5795
5813
  readonly from: v.StringSchema<undefined>;
@@ -6161,6 +6179,9 @@ export declare const ENTITIES: {
6161
6179
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
6162
6180
  readonly excerpt: v.StringSchema<undefined>;
6163
6181
  readonly offset_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
6182
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
6183
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
6184
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
6164
6185
  readonly match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
6165
6186
  readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
6166
6187
  readonly from: v.StringSchema<undefined>;
@@ -8812,6 +8833,12 @@ export declare const ENTITIES: {
8812
8833
  readonly stems: v.OptionalSchema<v.StrictObjectSchema<{
8813
8834
  readonly stemmed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
8814
8835
  }, undefined>, undefined>;
8836
+ readonly caught_up: v.OptionalSchema<v.StrictObjectSchema<{
8837
+ readonly chats: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
8838
+ readonly fetched: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
8839
+ readonly failed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
8840
+ readonly stopped: v.BooleanSchema<undefined>;
8841
+ }, undefined>, undefined>;
8815
8842
  readonly tasks: v.OptionalSchema<v.StrictObjectSchema<{
8816
8843
  readonly added: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
8817
8844
  readonly closed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
@@ -2266,6 +2266,12 @@ export declare const serveSummary: v.StrictObjectSchema<{
2266
2266
  readonly stems: v.OptionalSchema<v.StrictObjectSchema<{
2267
2267
  readonly stemmed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
2268
2268
  }, undefined>, undefined>;
2269
+ readonly caught_up: v.OptionalSchema<v.StrictObjectSchema<{
2270
+ readonly chats: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
2271
+ readonly fetched: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
2272
+ readonly failed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
2273
+ readonly stopped: v.BooleanSchema<undefined>;
2274
+ }, undefined>, undefined>;
2269
2275
  readonly tasks: v.OptionalSchema<v.StrictObjectSchema<{
2270
2276
  readonly added: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
2271
2277
  readonly closed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
@@ -42,5 +42,6 @@ export const serveSummary = v.strictObject({
42
42
  replies: v.optional(v.strictObject({ sent: totals, skipped: totals, tasks: v.optional(totals) })),
43
43
  members: v.optional(v.strictObject({ fetched: count, failed: count })),
44
44
  stems: v.optional(v.strictObject({ stemmed: count })),
45
+ caught_up: v.optional(v.strictObject({ chats: count, fetched: count, failed: count, stopped: v.boolean() })),
45
46
  tasks: v.optional(v.strictObject({ added: count, closed: count, review: count })),
46
47
  });
@@ -309,6 +309,9 @@ export declare const meetingPreparation: v.StrictObjectSchema<{
309
309
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
310
310
  readonly excerpt: v.StringSchema<undefined>;
311
311
  readonly offset_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
312
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
313
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
314
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
312
315
  readonly match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
313
316
  readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
314
317
  readonly from: v.StringSchema<undefined>;
@@ -33,6 +33,7 @@ const SIGN_IN = [
33
33
  ["sign-in.client-file-invalid", "configuration_error", "the file is not a Desktop app OAuth client JSON"],
34
34
  ];
35
35
  const OTHERS = [
36
+ ["query.time-limit", "timeout", "the search took longer than its time limit; the query itself is valid"],
36
37
  ["model.offline", "permission_error", "downloading a model needs the network; --offline was requested"],
37
38
  [
38
39
  "contract.unacknowledged-override",
@@ -376,6 +376,9 @@ export declare const callMeetingPreparationTool: (read: MeetingPreparationReader
376
376
  id: string;
377
377
  excerpt: string;
378
378
  offset_ms: number | null;
379
+ language?: string | null | undefined;
380
+ line?: number | undefined;
381
+ lines_total?: number | undefined;
379
382
  match?: "corrected" | "words" | undefined;
380
383
  corrections?: {
381
384
  from: string;
@@ -15,6 +15,11 @@ export declare const meetingHit: v.StrictObjectSchema<{
15
15
  readonly excerpt: v.StringSchema<undefined>;
16
16
  /** How far into the meeting the passage is. */
17
17
  readonly offset_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
18
+ /** A transcript passage's transcript language (`ru`, `en`…), `null` when unknown. */
19
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
20
+ /** A transcript passage's line, from 1, of `lines_total`. */
21
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
22
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
18
23
  /** `corrected`: a query word matched only a garbled form of itself, listed in `corrections`. */
19
24
  readonly match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
20
25
  readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
@@ -16,6 +16,11 @@ export const meetingHit = v.strictObject({
16
16
  excerpt: text,
17
17
  /** How far into the meeting the passage is. */
18
18
  offset_ms: v.nullable(count),
19
+ /** A transcript passage's transcript language (`ru`, `en`…), `null` when unknown. */
20
+ language: v.optional(v.nullable(text)),
21
+ /** A transcript passage's line, from 1, of `lines_total`. */
22
+ line: v.optional(v.pipe(count, v.minValue(1))),
23
+ lines_total: v.optional(count),
19
24
  /** `corrected`: a query word matched only a garbled form of itself, listed in `corrections`. */
20
25
  match: v.optional(v.picklist(["words", "corrected"])),
21
26
  corrections: v.optional(v.array(v.strictObject({ from: text, to: v.array(text) }))),
@@ -190,6 +195,9 @@ export const meetingHitItem = (hit) => ({
190
195
  id: String(hit.id),
191
196
  excerpt: hit.text,
192
197
  offset_ms: hit.startMs,
198
+ ...(hit.language === undefined ? {} : { language: hit.language }),
199
+ ...(hit.line === undefined ? {} : { line: hit.line }),
200
+ ...(hit.linesTotal === undefined ? {} : { lines_total: hit.linesTotal }),
193
201
  untrusted: hit.source === undefined ? ["excerpt"] : ["excerpt", "source.title"],
194
202
  ...(hit.match === undefined ? {} : { match: hit.match }),
195
203
  ...(hit.corrections === undefined ? {} : { corrections: hit.corrections }),
@@ -146,6 +146,20 @@ const addMeetingCommandsDefinition = (program, deps) => {
146
146
  throw new MeetingError("validation_error", "file account differs from selected account");
147
147
  print(await importFiles(files, deps.store, deps.now?.()), command);
148
148
  });
149
+ output(annotate(group.command("repair"), {
150
+ effects: LOCAL_WRITE,
151
+ output: { entity: "meeting_repair" },
152
+ }).description("preview filling in what older builds left out of stored transcripts (their language); --yes stores it"))
153
+ .option("--yes", "store the detected languages; otherwise only preview")
154
+ .action(async (opts, command) => {
155
+ if (!deps.store.fillTranscriptLanguages)
156
+ throw new MeetingError("configuration_error", "this store cannot fill transcript languages");
157
+ print(await deps.store.fillTranscriptLanguages({
158
+ accountId: deps.accountId,
159
+ apply: opts.yes === true,
160
+ now: deps.now?.() ?? Date.now(),
161
+ }), command);
162
+ });
149
163
  const eventList = queryWordsAfterOptions(annotate(program.command("events").description("the owner's stored events"), {
150
164
  effects: { remote: "none", local: "none" },
151
165
  }).command("list"))
@@ -14,6 +14,7 @@ export { liftMeetingFields, MEETING_HIT_QUERY, meetingWordsQuery, parseMeetingQu
14
14
  export { type ImportFile, importFiles } from "./import.js";
15
15
  export { MEETING_ISSUES, MEETING_QUERY, type MeetingIssue, type MeetingItem, type MeetingOwner, meeting, meetingIssuesOf, meetingItem, } from "./item.js";
16
16
  export { joinKeyOf, joinUrlWithoutQuery } from "./join-key.js";
17
+ export { transcriptLanguage } from "./language.js";
17
18
  export { CHAT_MESSAGES_READ, type MeetingChatLine, type MeetingChatLinesInput, type MeetingChatLinesStore, type MeetingLink, } from "./links.js";
18
19
  export { createMeetingContext, type MeetingContextAction, type MeetingContextChange, type MeetingContextOperation, type MeetingContextPorts, type MeetingContextReceipt, validateMeetingContextChange, } from "./meeting-context.js";
19
20
  export { createMeetingManagement, dispatchMeetingMutation, type ManagedMeeting, type ManagedMeetingChange, type MeetingManagement, type MeetingManagementPorts, type MeetingMutationOptions, type MeetingMutationProposal, type MeetingMutationReceipt, type MeetingOperationOptions, type MeetingProviderContext, validateMeetingChange, } from "./meeting-management.js";
@@ -51,7 +52,7 @@ export type { MeetingSeriesCandidate, MeetingSeriesInventoryPage, MeetingSeriesI
51
52
  export { validateMeetingSeriesInventoryCursor } from "./series-inventory-validation.js";
52
53
  export type { MeetingSource, SourceParticipant } from "./source.js";
53
54
  export { aggregateMeetingStats, type MeetingSpeakerStats, type MeetingStats, type MeetingStatsInput, type MeetingStatsRow, type MeetingStatsSelection, type MeetingStatsStore, type MeetingWeekStats, } from "./stats.js";
54
- export type { ChatInput, ContractCase, EventCandidateFilter, IdentityInput, MeetingDetails, MeetingFilter, MeetingHitSource, MeetingInput, MeetingSave, MeetingStore, NewRecord, ParticipantInput, SearchHit, TranscriptInput, TranscriptRowInput, } from "./store.js";
55
+ export type { ChatInput, ContractCase, EventCandidateFilter, IdentityInput, MeetingDetails, MeetingFilter, MeetingHitSource, MeetingInput, MeetingSave, MeetingStore, NewRecord, ParticipantInput, SearchHit, TranscriptInput, TranscriptLanguageFill, TranscriptRowInput, } from "./store.js";
55
56
  export type { MeetingTranscriptReceiptStore, MeetingTranscriptStore, TranscriptAppend, TranscriptAppendReceipt, UnlinkedTranscriptInput, } from "./transcript-store.js";
56
57
  export { parseTranscriptText, TranscriptTextError, type TranscriptTextHeader } from "./transcript-text.js";
57
58
  export { type MeetingMediaDescriptor, type MeetingRecognitionSegment, type MeetingTranscriptionContext, type MeetingTranscriptionOptions, type MeetingTranscriptionReceipt, type MeetingTranscriptionSource, transcribeMeeting, } from "./transcription.js";
@@ -11,6 +11,7 @@ export { liftMeetingFields, MEETING_HIT_QUERY, meetingWordsQuery, parseMeetingQu
11
11
  export { importFiles } from "./import.js";
12
12
  export { MEETING_ISSUES, MEETING_QUERY, meeting, meetingIssuesOf, meetingItem, } from "./item.js";
13
13
  export { joinKeyOf, joinUrlWithoutQuery } from "./join-key.js";
14
+ export { transcriptLanguage } from "./language.js";
14
15
  export { CHAT_MESSAGES_READ, } from "./links.js";
15
16
  export { createMeetingContext, validateMeetingContextChange, } from "./meeting-context.js";
16
17
  export { createMeetingManagement, dispatchMeetingMutation, validateMeetingChange, } from "./meeting-management.js";
@@ -1,3 +1,4 @@
1
+ import { transcriptLanguage } from "./language.js";
1
2
  export const contentHash = async (text) => {
2
3
  const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
3
4
  return Array.from(new Uint8Array(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
@@ -11,7 +12,7 @@ export const speakerPosition = (name, participants) => {
11
12
  export const transcriptInput = async (lines, participants, source, hashText = JSON.stringify(lines), format = null) => ({
12
13
  source,
13
14
  format,
14
- language: null,
15
+ language: transcriptLanguage(lines.map((line) => line.text)),
15
16
  contentHash: await contentHash(hashText),
16
17
  externalCreatedAt: null,
17
18
  metadata: null,
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The language most of a transcript is in, from its letters: Cyrillic is Russian (Ukrainian when its own letters
3
+ * show), Latin is decided by frequent words. `null` when the text is too short, mixed, or in neither script.
4
+ */
5
+ export declare const transcriptLanguage: (texts: Iterable<string>) => string | null;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Words frequent in one Latin-script language and rare in the others here. Letters alone cannot tell Spanish from
3
+ * English, and calling a Spanish meeting English is worse than calling it nothing.
4
+ */
5
+ const LATIN_WORDS = {
6
+ en: ["the", "and", "is", "that", "you", "this", "what", "have", "with", "are"],
7
+ es: ["el", "los", "las", "por", "pero", "para", "está", "muy", "también", "hay"],
8
+ de: ["der", "und", "ist", "nicht", "das", "ich", "wir", "mit", "auch", "ein"],
9
+ fr: ["le", "les", "est", "une", "pas", "je", "vous", "nous", "avec", "mais"],
10
+ it: ["gli", "della", "sono", "perché", "anche", "questo", "molto", "che", "di", "è"],
11
+ pt: ["não", "você", "isso", "muito", "então", "com", "uma", "também", "mas", "eu"],
12
+ };
13
+ const LATIN_LANGUAGE = new Map(Object.entries(LATIN_WORDS).flatMap(([language, words]) => words.map((word) => [word, language])));
14
+ /** Letters Ukrainian writes and Russian does not. */
15
+ const UKRAINIAN = /[іїєґ]/giu;
16
+ const CYRILLIC = /\p{Script=Cyrillic}/gu;
17
+ const LATIN = /\p{Script=Latin}/gu;
18
+ const MIN_LETTERS = 20;
19
+ /** A meeting in one language keeps a few lines of another; a share below this is a mixed meeting. */
20
+ const DOMINANT = 0.75;
21
+ const countOf = (text, pattern) => text.match(pattern)?.length ?? 0;
22
+ const latinLanguage = (texts) => {
23
+ const votes = new Map();
24
+ for (const text of texts)
25
+ for (const word of text.toLowerCase().split(/[^\p{L}]+/u)) {
26
+ const language = LATIN_LANGUAGE.get(word);
27
+ if (language)
28
+ votes.set(language, (votes.get(language) ?? 0) + 1);
29
+ }
30
+ const [first, second] = [...votes].sort((a, b) => b[1] - a[1]);
31
+ if (!first || first[1] < 3 || (second && first[1] < 2 * second[1]))
32
+ return null;
33
+ return first[0];
34
+ };
35
+ /**
36
+ * The language most of a transcript is in, from its letters: Cyrillic is Russian (Ukrainian when its own letters
37
+ * show), Latin is decided by frequent words. `null` when the text is too short, mixed, or in neither script.
38
+ */
39
+ export const transcriptLanguage = (texts) => {
40
+ const all = [...texts];
41
+ let cyrillic = 0;
42
+ let latin = 0;
43
+ let ukrainian = 0;
44
+ for (const text of all) {
45
+ cyrillic += countOf(text, CYRILLIC);
46
+ latin += countOf(text, LATIN);
47
+ ukrainian += countOf(text, UKRAINIAN);
48
+ }
49
+ const letters = cyrillic + latin;
50
+ if (letters < MIN_LETTERS)
51
+ return null;
52
+ if (cyrillic / letters >= DOMINANT)
53
+ return ukrainian / cyrillic >= 0.01 ? "uk" : "ru";
54
+ if (latin / letters >= DOMINANT)
55
+ return latinLanguage(all);
56
+ return null;
57
+ };
@@ -139,6 +139,9 @@ export declare const callMeetingSearchTool: (search: MeetingHitSearch, input: un
139
139
  id: string;
140
140
  excerpt: string;
141
141
  offset_ms: number | null;
142
+ language?: string | null | undefined;
143
+ line?: number | undefined;
144
+ lines_total?: number | undefined;
142
145
  match?: "corrected" | "words" | undefined;
143
146
  corrections?: {
144
147
  from: string;
@@ -24,6 +24,9 @@ export declare const meetingProjectEvidence: v.StrictObjectSchema<{
24
24
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
25
25
  readonly excerpt: v.StringSchema<undefined>;
26
26
  readonly offset_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
27
+ readonly language: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
28
+ readonly line: v.OptionalSchema<v.SchemaWithPipe<readonly [v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, v.MinValueAction<number, 1, undefined>]>, undefined>;
29
+ readonly lines_total: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
27
30
  readonly match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
28
31
  readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
29
32
  readonly from: v.StringSchema<undefined>;
@@ -124,4 +124,13 @@ export declare const MEETING_RESULT_ENTITIES: {
124
124
  readonly next_transcript_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
125
125
  }, undefined>;
126
126
  }, undefined>], undefined>;
127
+ readonly meeting_repair: v.StrictObjectSchema<{
128
+ readonly account_id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
129
+ readonly applied: v.BooleanSchema<undefined>;
130
+ readonly transcripts: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
131
+ readonly languages: v.ArraySchema<v.StrictObjectSchema<{
132
+ readonly language: v.NullableSchema<v.StringSchema<undefined>, undefined>;
133
+ readonly transcripts: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
134
+ }, undefined>, undefined>;
135
+ }, undefined>;
127
136
  };