@wirecat/cli-core 0.378.0 → 0.380.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.
- package/CHANGELOG.md +73 -0
- package/dist/cli/envelope.d.ts +10 -0
- package/dist/cli/list-query.js +2 -2
- package/dist/cli/meeting-preparation-answer.d.ts +5 -0
- package/dist/cli/meeting-preparation-projects.d.ts +5 -0
- package/dist/cli/meeting-preparation-read.d.ts +5 -0
- package/dist/cli/meeting-preparation-read.js +5 -5
- package/dist/cli/meeting-series-inventory-read.js +3 -4
- package/dist/cli/messenger/chats-stats-command.js +5 -1
- package/dist/cli/messenger/contacts-command.js +8 -4
- package/dist/cli/messenger/stats-answers.d.ts +2 -1
- package/dist/cli/messenger/stats-answers.js +1 -1
- package/dist/cli/messenger/stats-command.js +4 -7
- package/dist/domain/moment.d.ts +8 -0
- package/dist/domain/moment.js +14 -0
- package/dist/domain/send-time.d.ts +2 -2
- package/dist/domain/send-time.js +4 -3
- package/dist/entities/account-session.d.ts +2 -2
- package/dist/entities/admin-report.d.ts +8 -8
- package/dist/entities/agenda.d.ts +12 -12
- package/dist/entities/chat-event.d.ts +1 -1
- package/dist/entities/chat-stats.d.ts +5 -5
- package/dist/entities/chat.d.ts +4 -4
- package/dist/entities/contact-note.d.ts +2 -2
- package/dist/entities/contact.d.ts +13 -13
- package/dist/entities/conversation.d.ts +3 -3
- package/dist/entities/counter-reading.d.ts +1 -1
- package/dist/entities/counters.d.ts +2 -2
- package/dist/entities/document.d.ts +2 -2
- package/dist/entities/evidence.d.ts +72 -72
- package/dist/entities/fact.d.ts +3 -3
- package/dist/entities/fields.d.ts +3 -1
- package/dist/entities/fields.js +2 -0
- package/dist/entities/hit.d.ts +1 -1
- package/dist/entities/index.d.ts +231 -215
- package/dist/entities/index.js +1 -0
- package/dist/entities/invite-link.d.ts +1 -1
- package/dist/entities/job.d.ts +2 -2
- package/dist/entities/join-request.d.ts +1 -1
- package/dist/entities/meeting-communications.d.ts +4 -4
- package/dist/entities/meeting-findings.d.ts +2 -2
- package/dist/entities/meeting-preparation-parts.d.ts +9 -9
- package/dist/entities/meeting-preparation.d.ts +28 -23
- package/dist/entities/meeting-series-inventory.d.ts +3 -3
- package/dist/entities/member.d.ts +3 -3
- package/dist/entities/memory.d.ts +3 -3
- package/dist/entities/message.d.ts +6 -6
- package/dist/entities/note.d.ts +3 -3
- package/dist/entities/official-stats.d.ts +2 -2
- package/dist/entities/poll-vote.d.ts +1 -1
- package/dist/entities/ranking.d.ts +2 -2
- package/dist/entities/relationship.d.ts +1 -1
- package/dist/entities/retention.d.ts +4 -4
- package/dist/entities/saved-search.d.ts +2 -2
- package/dist/entities/tagging.d.ts +1 -1
- package/dist/entities/task.d.ts +7 -7
- package/dist/entities/topic.d.ts +2 -2
- package/dist/mcp/meeting-preparation.d.ts +5 -0
- package/dist/mcp/tools/stats.js +9 -4
- package/dist/meetings/answers.d.ts +20 -14
- package/dist/meetings/answers.js +5 -0
- package/dist/meetings/cli/index.d.ts +2 -0
- package/dist/meetings/cli/index.js +12 -6
- package/dist/meetings/cli/search.js +12 -14
- package/dist/meetings/hit-query.d.ts +12 -0
- package/dist/meetings/hit-query.js +58 -0
- package/dist/meetings/import.d.ts +2 -0
- package/dist/meetings/import.js +8 -2
- package/dist/meetings/index.d.ts +2 -0
- package/dist/meetings/index.js +2 -0
- package/dist/meetings/item.d.ts +4 -4
- package/dist/meetings/mcp/search.d.ts +6 -0
- package/dist/meetings/mcp/search.js +5 -1
- package/dist/meetings/project-evidence-answer.d.ts +8 -3
- package/dist/meetings/pull.d.ts +2 -0
- package/dist/meetings/recording-schedule.js +6 -5
- package/dist/meetings/search-store.d.ts +3 -1
- package/dist/meetings/store.d.ts +7 -0
- package/dist/meetings/transcript-text.d.ts +20 -0
- package/dist/meetings/transcript-text.js +59 -0
- package/dist/render/markdown.js +2 -2
- package/dist/search/garbled.d.ts +29 -0
- package/dist/search/garbled.js +125 -0
- package/dist/search/russian-dictionary.d.ts +5 -0
- package/dist/search/russian-dictionary.js +66 -0
- package/dist/services/admin-statistics.js +2 -2
- package/dist/services/meeting-project-discovery.js +2 -2
- package/dist/services/moment.d.ts +25 -2
- package/dist/services/moment.js +32 -4
- package/dist/services/retention.js +6 -3
- package/dist/store/sqlite/facts.js +2 -1
- package/dist/store/sqlite/meeting-hit-query.d.ts +60 -0
- package/dist/store/sqlite/meeting-hit-query.js +262 -0
- package/dist/store/sqlite/meeting-hit-search.js +28 -45
- package/package.json +4 -3
|
@@ -376,6 +376,11 @@ export declare const callMeetingPreparationTool: (read: MeetingPreparationReader
|
|
|
376
376
|
id: string;
|
|
377
377
|
excerpt: string;
|
|
378
378
|
offset_ms: number | null;
|
|
379
|
+
match?: "corrected" | "words" | undefined;
|
|
380
|
+
corrections?: {
|
|
381
|
+
from: string;
|
|
382
|
+
to: string[];
|
|
383
|
+
}[] | undefined;
|
|
379
384
|
source?: {
|
|
380
385
|
ref: string;
|
|
381
386
|
title: string | null;
|
package/dist/mcp/tools/stats.js
CHANGED
|
@@ -7,7 +7,7 @@ import { chartRenderer } from "../../charts/render.js";
|
|
|
7
7
|
import { sealed } from "../../cli/envelope.js";
|
|
8
8
|
import { chartAnswer } from "../../cli/messenger/stats-answers.js";
|
|
9
9
|
import { servicesFor, storedDeps } from "../../services/index.js";
|
|
10
|
-
import {
|
|
10
|
+
import { dateWindow } from "../../services/moment.js";
|
|
11
11
|
import { chatOf, Picture, READ, tool } from "../tool.js";
|
|
12
12
|
export const statsTools = (messenger) => ({
|
|
13
13
|
stats_charts: tool({
|
|
@@ -29,16 +29,21 @@ export const statsTools = (messenger) => ({
|
|
|
29
29
|
stored: async (store, account, args, defaults) => {
|
|
30
30
|
const timezone = timezoneOf(args.timezone);
|
|
31
31
|
const by = args.by ?? "day";
|
|
32
|
+
const window = dateWindow({
|
|
33
|
+
...(args.since_time === undefined ? {} : { sinceTime: args.since_time }),
|
|
34
|
+
zone: timezone,
|
|
35
|
+
names: ["since_time", "until_time"],
|
|
36
|
+
});
|
|
32
37
|
const stats = await servicesFor(storedDeps(messenger, store, account, defaults.guard)).chats.stats(args.chat, {
|
|
33
38
|
by,
|
|
34
39
|
timezone,
|
|
35
|
-
...(
|
|
40
|
+
...(window.since === undefined ? {} : { since: window.since }),
|
|
36
41
|
});
|
|
37
42
|
const chart = chatChart(stats, { kind: args.chart_kind ?? "messages", by, timezone });
|
|
38
43
|
if (args.format !== "png")
|
|
39
|
-
return chartAnswer(chart);
|
|
44
|
+
return chartAnswer(chart, undefined, window.meta);
|
|
40
45
|
const image = await chartPng(await (await chartRenderer()).render(chart, CHART_SIZE));
|
|
41
|
-
return new Picture(image.bytes, image.mimeType, sealed(chartAnswer(chart)));
|
|
46
|
+
return new Picture(image.bytes, image.mimeType, sealed(chartAnswer(chart, undefined, window.meta)));
|
|
42
47
|
},
|
|
43
48
|
}),
|
|
44
49
|
});
|
|
@@ -15,10 +15,16 @@ 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
|
+
/** `corrected`: a query word matched only a garbled form of itself, listed in `corrections`. */
|
|
19
|
+
readonly match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
|
|
20
|
+
readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
|
|
21
|
+
readonly from: v.StringSchema<undefined>;
|
|
22
|
+
readonly to: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
23
|
+
}, undefined>, undefined>, undefined>;
|
|
18
24
|
readonly source: v.OptionalSchema<v.StrictObjectSchema<{
|
|
19
25
|
readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
|
|
20
26
|
readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
21
|
-
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
27
|
+
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
22
28
|
readonly url: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
23
29
|
}, undefined>, undefined>;
|
|
24
30
|
}, undefined>;
|
|
@@ -29,8 +35,8 @@ export declare const meetingTranscript: v.StrictObjectSchema<{
|
|
|
29
35
|
readonly source: v.StringSchema<undefined>;
|
|
30
36
|
readonly language: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
31
37
|
/** When a newer transcript of the same source replaced it; `meetings transcript --history` shows those too. */
|
|
32
|
-
readonly superseded_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
33
|
-
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
38
|
+
readonly superseded_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
39
|
+
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
34
40
|
readonly lines: v.ArraySchema<v.StrictObjectSchema<{
|
|
35
41
|
readonly position: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
|
|
36
42
|
readonly offset_ms: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
|
|
@@ -53,8 +59,8 @@ export declare const meetingSummary: v.StrictObjectSchema<{
|
|
|
53
59
|
readonly next_steps: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
54
60
|
readonly content: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
55
61
|
readonly url: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
56
|
-
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
57
|
-
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
62
|
+
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
63
|
+
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
58
64
|
}, undefined>;
|
|
59
65
|
/** `meetings show`: the meeting with who took part, what was said in its chat, and what it holds. */
|
|
60
66
|
export declare const meetingDetails: v.StrictObjectSchema<{
|
|
@@ -66,13 +72,13 @@ export declare const meetingDetails: v.StrictObjectSchema<{
|
|
|
66
72
|
readonly description: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
67
73
|
readonly location: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
68
74
|
readonly url: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
69
|
-
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
70
|
-
readonly ended_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
75
|
+
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
76
|
+
readonly ended_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
71
77
|
readonly duration_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
72
78
|
readonly timezone: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
73
79
|
readonly participants_count: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
74
|
-
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
75
|
-
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
80
|
+
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
81
|
+
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
76
82
|
/** The stored event and series it belongs to, as `meetings_list` takes them. */
|
|
77
83
|
readonly event_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
78
84
|
readonly series_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -81,8 +87,8 @@ export declare const meetingDetails: v.StrictObjectSchema<{
|
|
|
81
87
|
readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
82
88
|
readonly email: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
83
89
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
84
|
-
readonly joined_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
85
|
-
readonly left_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
90
|
+
readonly joined_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
91
|
+
readonly left_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
86
92
|
readonly duration_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
87
93
|
}, undefined>, undefined>;
|
|
88
94
|
readonly transcripts: v.ArraySchema<v.StrictObjectSchema<{
|
|
@@ -92,7 +98,7 @@ export declare const meetingDetails: v.StrictObjectSchema<{
|
|
|
92
98
|
readonly lines_count: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
|
|
93
99
|
}, undefined>, undefined>;
|
|
94
100
|
readonly chat: v.ArraySchema<v.StrictObjectSchema<{
|
|
95
|
-
readonly sent_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
101
|
+
readonly sent_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
96
102
|
readonly sender: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
97
103
|
readonly recipient: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
98
104
|
readonly text: v.StringSchema<undefined>;
|
|
@@ -110,8 +116,8 @@ export declare const meetingDetails: v.StrictObjectSchema<{
|
|
|
110
116
|
readonly next_steps: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
111
117
|
readonly content: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
112
118
|
readonly url: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
113
|
-
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
114
|
-
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
119
|
+
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
120
|
+
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
115
121
|
}, undefined>, undefined>;
|
|
116
122
|
readonly attachments: v.ArraySchema<v.StrictObjectSchema<{
|
|
117
123
|
readonly position: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
|
package/dist/meetings/answers.js
CHANGED
|
@@ -16,6 +16,9 @@ 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
|
+
/** `corrected`: a query word matched only a garbled form of itself, listed in `corrections`. */
|
|
20
|
+
match: v.optional(v.picklist(["words", "corrected"])),
|
|
21
|
+
corrections: v.optional(v.array(v.strictObject({ from: text, to: v.array(text) }))),
|
|
19
22
|
source: v.optional(v.strictObject({
|
|
20
23
|
ref: reference,
|
|
21
24
|
title: v.nullable(text),
|
|
@@ -185,6 +188,8 @@ export const meetingHitItem = (hit) => ({
|
|
|
185
188
|
id: String(hit.id),
|
|
186
189
|
excerpt: hit.text,
|
|
187
190
|
offset_ms: hit.startMs,
|
|
191
|
+
...(hit.match === undefined ? {} : { match: hit.match }),
|
|
192
|
+
...(hit.corrections === undefined ? {} : { corrections: hit.corrections }),
|
|
188
193
|
...(hit.source === undefined
|
|
189
194
|
? {}
|
|
190
195
|
: {
|
|
@@ -7,6 +7,8 @@ export interface MeetingCommandDeps {
|
|
|
7
7
|
accountId: number;
|
|
8
8
|
source?: MeetingSource;
|
|
9
9
|
readFiles?: (folder: string) => Promise<ImportFile[]>;
|
|
10
|
+
/** The host's file names and how it reads their time, shown in `meetings import --help`. */
|
|
11
|
+
importHelp?: string;
|
|
10
12
|
writeFile?: (path: string, content: string) => Promise<void>;
|
|
11
13
|
write: (value: unknown, format: "json" | "jsonl" | "text") => void;
|
|
12
14
|
now?: () => number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
2
|
-
import { defineQuery, fieldsHelp } from "@wirecat/cli-base/query";
|
|
2
|
+
import { defineQuery, fieldsHelp, timezoneOf, zonedMoment } from "@wirecat/cli-base/query";
|
|
3
3
|
import { InvalidArgumentError, Option } from "commander";
|
|
4
4
|
import { exportMeeting } from "../export.js";
|
|
5
5
|
import { importFiles } from "../import.js";
|
|
@@ -19,9 +19,12 @@ const lookbackDays = (text) => {
|
|
|
19
19
|
return Number(text);
|
|
20
20
|
};
|
|
21
21
|
const date = (text) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
try {
|
|
23
|
+
return zonedMoment(text, timezoneOf(), { start: 0, end: text.length });
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
throw new InvalidArgumentError("expected an ISO date, or a time with or without an offset");
|
|
27
|
+
}
|
|
25
28
|
};
|
|
26
29
|
const LOCAL_READ = { remote: "none", local: "read" };
|
|
27
30
|
const LOCAL_WRITE = { remote: "none", local: "write" };
|
|
@@ -119,9 +122,12 @@ export const addMeetingCommands = (program, deps) => {
|
|
|
119
122
|
lookbackMs: opts.lookbackDays * 86400000,
|
|
120
123
|
}), command);
|
|
121
124
|
});
|
|
122
|
-
|
|
125
|
+
const importCommand = annotate(group.command("import"), { effects: LOCAL_WRITE })
|
|
123
126
|
.description("import downloaded meeting transcripts")
|
|
124
|
-
.argument("<folder>", "folder of transcripts downloaded from the provider")
|
|
127
|
+
.argument("<folder>", "folder of transcripts downloaded from the provider");
|
|
128
|
+
if (deps.importHelp)
|
|
129
|
+
importCommand.addHelpText("after", `\n${deps.importHelp}`);
|
|
130
|
+
output(importCommand).action(async (folder, _opts, command) => {
|
|
125
131
|
if (!deps.readFiles)
|
|
126
132
|
throw new MeetingError("configuration_error", "file reader is unavailable");
|
|
127
133
|
const files = await deps.readFiles(folder);
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
|
+
import { timezoneOf, zonedMoment } from "@wirecat/cli-base/query";
|
|
3
4
|
import { Command } from "commander";
|
|
4
5
|
import { meetingHitsList } from "../answers.js";
|
|
5
6
|
import { validateMeetingHitSearch } from "../search-validation.js";
|
|
6
7
|
export { validateMeetingHitSearch } from "../search-validation.js";
|
|
8
|
+
const moment = (flag, end) => (value) => {
|
|
9
|
+
try {
|
|
10
|
+
return zonedMoment(value, timezoneOf(), { start: 0, end: value.length }, { end });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new CliError("validation_error", `${flag} takes an ISO date, or a time with or without an offset`);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
7
16
|
const integer = (value) => {
|
|
8
17
|
if (!/^[1-9]\d*$/.test(value) || !Number.isSafeInteger(Number(value)))
|
|
9
18
|
throw new CliError("validation_error", "expected a positive safe integer");
|
|
10
19
|
return Number(value);
|
|
11
20
|
};
|
|
12
|
-
const timestamp = (value) => {
|
|
13
|
-
const parsed = Date.parse(value);
|
|
14
|
-
const date = value.slice(0, 10);
|
|
15
|
-
const day = Date.parse(`${date}T00:00:00Z`);
|
|
16
|
-
if (!/^\d{4}-\d{2}-\d{2}(?:T.+(?:Z|[+-]\d{2}:\d{2}))?$/.test(value) ||
|
|
17
|
-
!Number.isFinite(parsed) ||
|
|
18
|
-
!Number.isFinite(day) ||
|
|
19
|
-
new Date(day).toISOString().slice(0, 10) !== date)
|
|
20
|
-
throw new CliError("validation_error", "meeting search dates require a real ISO date or timestamp with offset");
|
|
21
|
-
return parsed;
|
|
22
|
-
};
|
|
23
21
|
/** Shared grammar without an action: a host with other source reports supplies their transport routing. */
|
|
24
22
|
export const createMeetingSearchCommand = (program) => {
|
|
25
23
|
let search = program.commands.find((command) => command.name() === "search");
|
|
@@ -30,7 +28,7 @@ export const createMeetingSearchCommand = (program) => {
|
|
|
30
28
|
const command = search
|
|
31
29
|
.command("meetings")
|
|
32
30
|
.description("find words in stored meetings, indexing new ones first")
|
|
33
|
-
.argument("<query>",
|
|
31
|
+
.argument("<query>", 'words, OR, (groups), -word, "a phrase", "a b"~N (within N lines), exact:word, from:"Name" (who said the line); a word also matches its other forms and spellings speech recognition garbled')
|
|
34
32
|
.option("--meeting-id <id>", "only this stored meeting", integer)
|
|
35
33
|
.option("--identity-id <id>", "meetings with this participant identity; does not say who spoke a hit", integer)
|
|
36
34
|
.option("--person-id <id>", "meetings with a participant linked to this person", integer)
|
|
@@ -39,8 +37,8 @@ export const createMeetingSearchCommand = (program) => {
|
|
|
39
37
|
.option("--project <name>", "meetings confirmed in this project, by name, key or alias")
|
|
40
38
|
.option("--tag <name>", "meetings with this tag, by name or alias")
|
|
41
39
|
.option("--topic <name>", "meetings with this topic, by name or alias")
|
|
42
|
-
.option("--since-time <time>", "meetings starting at or after this ISO 8601 date or time",
|
|
43
|
-
.option("--until-time <time>", "meetings starting at or before this ISO 8601 date or time",
|
|
40
|
+
.option("--since-time <time>", "meetings starting at or after this ISO 8601 date or time", moment("--since-time", false))
|
|
41
|
+
.option("--until-time <time>", "meetings starting at or before this ISO 8601 date or time; a date alone covers that whole local day", moment("--until-time", true))
|
|
44
42
|
.option("--limit <n>", "how many hits, 1 through 1000 (default 100)", integer)
|
|
45
43
|
.option("--cursor <cursor>", "continue from the previous page's page.next_cursor, with the same query and filters")
|
|
46
44
|
.option("--max-read-bytes <bytes>", "most stored bytes to read, 1 through 67108864 (default 4194304)", integer);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type QueryAst } from "@wirecat/cli-base/query";
|
|
2
|
+
/** A transcript line holds a sentence or two; further than this is a different part of the meeting. */
|
|
3
|
+
export declare const MOST_LINES_APART = 20;
|
|
4
|
+
/** The messages query language over meeting text: the same fields, a narrower set of operators. */
|
|
5
|
+
export declare const MEETING_HIT_QUERY: import("@wirecat/cli-base/query").QueryRegistry;
|
|
6
|
+
/** What a person typed: the CLI, MCP and batch queries. */
|
|
7
|
+
export declare const parseMeetingQuery: (query: string) => QueryAst;
|
|
8
|
+
/**
|
|
9
|
+
* Words from a name or a note, never parsed: a project called «C++ (beta)» must not become syntax. Each word is
|
|
10
|
+
* required, in any form.
|
|
11
|
+
*/
|
|
12
|
+
export declare const meetingWordsQuery: (text: string) => QueryAst;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineQuery, parseLucene, queryError, validateQuery, } from "@wirecat/cli-base/query";
|
|
2
|
+
const context = {
|
|
3
|
+
command: "search meetings",
|
|
4
|
+
guide: "https://github.com/WireCatLabs/cli-core/blob/main/docs/search/query-language.md#встречи",
|
|
5
|
+
};
|
|
6
|
+
const words = ["term", "phrase"];
|
|
7
|
+
/** A transcript line holds a sentence or two; further than this is a different part of the meeting. */
|
|
8
|
+
export const MOST_LINES_APART = 20;
|
|
9
|
+
const near = (node) => {
|
|
10
|
+
if (node.slop !== undefined && node.slop > MOST_LINES_APART)
|
|
11
|
+
queryError("query.invalid-number", node.span, `words at most ${MOST_LINES_APART} lines apart: "a b"~${MOST_LINES_APART}`, context);
|
|
12
|
+
};
|
|
13
|
+
/** The messages query language over meeting text: the same fields, a narrower set of operators. */
|
|
14
|
+
export const MEETING_HIT_QUERY = defineQuery({
|
|
15
|
+
entity: "meeting_hit",
|
|
16
|
+
backend: "sql",
|
|
17
|
+
fields: [
|
|
18
|
+
{
|
|
19
|
+
name: "text",
|
|
20
|
+
type: "txt",
|
|
21
|
+
operators: words,
|
|
22
|
+
example: "text:budget",
|
|
23
|
+
relation: "a passage with the word in any form, or a spelling speech recognition garbled",
|
|
24
|
+
validate: near,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "exact",
|
|
28
|
+
type: "txt",
|
|
29
|
+
operators: words,
|
|
30
|
+
example: "exact:budget",
|
|
31
|
+
relation: "a passage with the word as typed: no other forms, no garbled spellings",
|
|
32
|
+
validate: near,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "from",
|
|
36
|
+
type: "kw",
|
|
37
|
+
operators: words,
|
|
38
|
+
example: 'from:"Alice Synthetic"',
|
|
39
|
+
relation: "a line said or a chat message written by this person; attendance is --identity-id",
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
/** What a person typed: the CLI, MCP and batch queries. */
|
|
44
|
+
export const parseMeetingQuery = (query) => validateQuery(parseLucene(query, { defaultField: "text", proximity: true, ...context }), MEETING_HIT_QUERY, context);
|
|
45
|
+
/**
|
|
46
|
+
* Words from a name or a note, never parsed: a project called «C++ (beta)» must not become syntax. Each word is
|
|
47
|
+
* required, in any form.
|
|
48
|
+
*/
|
|
49
|
+
export const meetingWordsQuery = (text) => {
|
|
50
|
+
const found = text.match(/[\p{L}\p{N}\p{M}]+/gu) ?? [];
|
|
51
|
+
const span = { start: 0, end: text.length };
|
|
52
|
+
const clauses = found.map((value) => ({
|
|
53
|
+
occur: "must",
|
|
54
|
+
node: { kind: "predicate", field: "text", operator: "term", value, span },
|
|
55
|
+
}));
|
|
56
|
+
const root = clauses.length === 1 && clauses[0] ? clauses[0].node : { kind: "boolean", clauses, span };
|
|
57
|
+
return { version: 1, language: "lucene-v1", root };
|
|
58
|
+
};
|
|
@@ -5,6 +5,8 @@ export interface ImportFile {
|
|
|
5
5
|
content: string;
|
|
6
6
|
participants?: ParticipantInput[];
|
|
7
7
|
source?: string;
|
|
8
|
+
/** `vtt` (the default) or `text`, the form `parseTranscriptText` reads. */
|
|
9
|
+
format?: "vtt" | "text";
|
|
8
10
|
}
|
|
9
11
|
/** The caller reads files and supplies provider-neutral occurrence metadata. */
|
|
10
12
|
export declare const importFiles: (files: ImportFile[], store: MeetingStore, now?: number) => Promise<RunReport>;
|
package/dist/meetings/import.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { linkEvent } from "./events.js";
|
|
2
2
|
import { transcriptInput } from "./ingest.js";
|
|
3
|
+
import { parseTranscriptText } from "./transcript-text.js";
|
|
3
4
|
import { parseVtt } from "./vtt.js";
|
|
4
5
|
/** The caller reads files and supplies provider-neutral occurrence metadata. */
|
|
5
6
|
export const importFiles = async (files, store, now = Date.now()) => {
|
|
6
7
|
const report = { meetings: 0, participants: 0, transcriptRows: 0, summaries: 0, warnings: [] };
|
|
7
8
|
for (const file of files) {
|
|
8
9
|
try {
|
|
9
|
-
const
|
|
10
|
+
const format = file.format ?? "vtt";
|
|
11
|
+
const lines = format === "text" ? parseTranscriptText(file.content).lines : parseVtt(file.content);
|
|
10
12
|
const participants = file.participants ?? [];
|
|
11
13
|
const details = await store.saveMeeting({
|
|
12
14
|
meeting: file.meeting,
|
|
13
15
|
participants: file.participants,
|
|
14
|
-
transcripts: [await transcriptInput(lines, participants, file.source ?? "file", file.content,
|
|
16
|
+
transcripts: [await transcriptInput(lines, participants, file.source ?? "file", file.content, format)],
|
|
15
17
|
now,
|
|
16
18
|
});
|
|
17
19
|
await linkEvent(store, details, now);
|
|
@@ -26,5 +28,9 @@ export const importFiles = async (files, store, now = Date.now()) => {
|
|
|
26
28
|
});
|
|
27
29
|
}
|
|
28
30
|
}
|
|
31
|
+
const zones = new Set(files.map((file) => file.meeting.timezone).filter((zone) => zone !== null && zone !== undefined));
|
|
32
|
+
const [zone] = zones;
|
|
33
|
+
if (zones.size === 1 && zone)
|
|
34
|
+
report.timezone = zone;
|
|
29
35
|
return report;
|
|
30
36
|
};
|
package/dist/meetings/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { linkEvent } from "./events.js";
|
|
|
6
6
|
export { exportMeeting, type MeetingExport, type MeetingExportFormat, type MeetingExportOptions, serializeVtt, } from "./export.js";
|
|
7
7
|
export { type FindingEvidence, type FindingOutcome, findingHash, MEETING_FINDINGS_KIND, type MeetingFactFinding, type MeetingFinding, type MeetingFindingsInput, type MeetingFindingsReceipt, type MeetingTaskFinding, meetingFindingFingerprint, validateMeetingFindings, } from "./findings.js";
|
|
8
8
|
export { type Finding, type FindingsInput, type FindingsReceipt, type FindingsRules, findingFingerprint, validateFindings, } from "./findings-rules.js";
|
|
9
|
+
export { MEETING_HIT_QUERY, meetingWordsQuery, parseMeetingQuery } from "./hit-query.js";
|
|
9
10
|
export { type ImportFile, importFiles } from "./import.js";
|
|
10
11
|
export { MEETING_QUERY, type MeetingItem, type MeetingOwner, meeting, meetingItem } from "./item.js";
|
|
11
12
|
export { createMeetingContext, MEETING_FACT_TYPES, type MeetingContextAction, type MeetingContextChange, type MeetingContextOperation, type MeetingContextPorts, type MeetingContextReceipt, validateMeetingContextChange, } from "./meeting-context.js";
|
|
@@ -41,6 +42,7 @@ export { validateMeetingSeriesInventoryCursor } from "./series-inventory-validat
|
|
|
41
42
|
export type { MeetingSource, SourceParticipant } from "./source.js";
|
|
42
43
|
export type { ChatInput, ContractCase, EventCandidateFilter, IdentityInput, MeetingDetails, MeetingFilter, MeetingHitSource, MeetingInput, MeetingSave, MeetingStore, NewRecord, ParticipantInput, SearchHit, TranscriptInput, TranscriptRowInput, } from "./store.js";
|
|
43
44
|
export type { MeetingTranscriptReceiptStore, MeetingTranscriptStore, TranscriptAppend, TranscriptAppendReceipt, UnlinkedTranscriptInput, } from "./transcript-store.js";
|
|
45
|
+
export { parseTranscriptText, TranscriptTextError, type TranscriptTextHeader } from "./transcript-text.js";
|
|
44
46
|
export { type MeetingMediaDescriptor, type MeetingRecognitionSegment, type MeetingTranscriptionContext, type MeetingTranscriptionOptions, type MeetingTranscriptionReceipt, type MeetingTranscriptionSource, transcribeMeeting, } from "./transcription.js";
|
|
45
47
|
export { createUpcomingMeetingReader } from "./upcoming.js";
|
|
46
48
|
export type { MeetingOccurrence, MeetingOccurrencePort, MeetingOccurrenceRead, MeetingOccurrenceSchedule, UpcomingMeetingRequest, UpcomingMeetingResult, } from "./upcoming-types.js";
|
package/dist/meetings/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { linkEvent } from "./events.js";
|
|
|
4
4
|
export { exportMeeting, serializeVtt, } from "./export.js";
|
|
5
5
|
export { findingHash, MEETING_FINDINGS_KIND, meetingFindingFingerprint, validateMeetingFindings, } from "./findings.js";
|
|
6
6
|
export { findingFingerprint, validateFindings, } from "./findings-rules.js";
|
|
7
|
+
export { MEETING_HIT_QUERY, meetingWordsQuery, parseMeetingQuery } from "./hit-query.js";
|
|
7
8
|
export { importFiles } from "./import.js";
|
|
8
9
|
export { MEETING_QUERY, meeting, meetingItem } from "./item.js";
|
|
9
10
|
export { createMeetingContext, MEETING_FACT_TYPES, validateMeetingContextChange, } from "./meeting-context.js";
|
|
@@ -27,6 +28,7 @@ export { validateMeetingHitSearch } from "./search-validation.js";
|
|
|
27
28
|
export { validateMeetingSeriesHistory, } from "./series-history.js";
|
|
28
29
|
export { createMeetingSeriesInventoryReader } from "./series-inventory.js";
|
|
29
30
|
export { validateMeetingSeriesInventoryCursor } from "./series-inventory-validation.js";
|
|
31
|
+
export { parseTranscriptText, TranscriptTextError } from "./transcript-text.js";
|
|
30
32
|
export { transcribeMeeting, } from "./transcription.js";
|
|
31
33
|
export { createUpcomingMeetingReader } from "./upcoming.js";
|
|
32
34
|
export { parseVtt, VttError } from "./vtt.js";
|
package/dist/meetings/item.d.ts
CHANGED
|
@@ -11,13 +11,13 @@ export declare const meeting: v.StrictObjectSchema<{
|
|
|
11
11
|
readonly location: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
12
12
|
/** The link that joins it. */
|
|
13
13
|
readonly url: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
14
|
-
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
15
|
-
readonly ended_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
14
|
+
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
15
|
+
readonly ended_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
16
16
|
readonly duration_ms: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
17
17
|
readonly timezone: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
18
18
|
readonly participants_count: v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
19
|
-
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
20
|
-
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
19
|
+
readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
20
|
+
readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
|
|
21
21
|
}, undefined>;
|
|
22
22
|
export type MeetingItem = v.InferOutput<typeof meeting>;
|
|
23
23
|
/** Which provider and account a stored meeting account is, as `MeetingStore.account` answers it. */
|
|
@@ -15,6 +15,7 @@ export declare const meetingSearchTool: {
|
|
|
15
15
|
query: {
|
|
16
16
|
type: string;
|
|
17
17
|
minLength: number;
|
|
18
|
+
description: string;
|
|
18
19
|
};
|
|
19
20
|
meeting_id: {
|
|
20
21
|
type: string;
|
|
@@ -138,6 +139,11 @@ export declare const callMeetingSearchTool: (search: MeetingHitSearch, input: un
|
|
|
138
139
|
id: string;
|
|
139
140
|
excerpt: string;
|
|
140
141
|
offset_ms: number | null;
|
|
142
|
+
match?: "corrected" | "words" | undefined;
|
|
143
|
+
corrections?: {
|
|
144
|
+
from: string;
|
|
145
|
+
to: string[];
|
|
146
|
+
}[] | undefined;
|
|
141
147
|
source?: {
|
|
142
148
|
ref: string;
|
|
143
149
|
title: string | null;
|
|
@@ -11,7 +11,11 @@ export const meetingSearchTool = {
|
|
|
11
11
|
inputSchema: {
|
|
12
12
|
type: "object",
|
|
13
13
|
properties: {
|
|
14
|
-
query: {
|
|
14
|
+
query: {
|
|
15
|
+
type: "string",
|
|
16
|
+
minLength: 1,
|
|
17
|
+
description: 'The messages query language: words (all required), OR, (groups), NOT or -word, "a phrase", "a b"~N for words within N transcript lines (at most 20), exact:word, from:"Name" for who said the line',
|
|
18
|
+
},
|
|
15
19
|
meeting_id: integer,
|
|
16
20
|
identity_id: integer,
|
|
17
21
|
person_id: integer,
|
|
@@ -24,10 +24,15 @@ 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 match: v.OptionalSchema<v.PicklistSchema<["words", "corrected"], undefined>, undefined>;
|
|
28
|
+
readonly corrections: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
|
|
29
|
+
readonly from: v.StringSchema<undefined>;
|
|
30
|
+
readonly to: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
31
|
+
}, undefined>, undefined>, undefined>;
|
|
27
32
|
readonly source: v.OptionalSchema<v.StrictObjectSchema<{
|
|
28
33
|
readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
|
|
29
34
|
readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
30
|
-
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
35
|
+
readonly started_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
31
36
|
readonly url: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
32
37
|
}, undefined>, undefined>;
|
|
33
38
|
}, undefined>, undefined>;
|
|
@@ -40,8 +45,8 @@ export declare const meetingProjectEvidence: v.StrictObjectSchema<{
|
|
|
40
45
|
readonly tag_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
41
46
|
readonly event_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
42
47
|
readonly series_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
43
|
-
readonly since: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
44
|
-
readonly until: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time
|
|
48
|
+
readonly since: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
49
|
+
readonly until: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
|
|
45
50
|
}, undefined>;
|
|
46
51
|
readonly limits: v.StrictObjectSchema<{
|
|
47
52
|
readonly limit: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
|
package/dist/meetings/pull.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface RunReport {
|
|
|
9
9
|
externalId: string;
|
|
10
10
|
message: string;
|
|
11
11
|
}[];
|
|
12
|
+
/** An import whose files all read their start time in one zone names it; files carry no zone of their own. */
|
|
13
|
+
timezone?: string;
|
|
12
14
|
}
|
|
13
15
|
export interface PullOptions {
|
|
14
16
|
accountId: number;
|
|
@@ -12,6 +12,8 @@ const clock = (now) => {
|
|
|
12
12
|
return new Date(now);
|
|
13
13
|
};
|
|
14
14
|
const day = (instant) => instant.toISOString().slice(0, 10);
|
|
15
|
+
/** The calendar day it is at `instant` in the schedule's own zone: the day the owner's daily run belongs to. */
|
|
16
|
+
const localDay = (instant, timeZone) => new Intl.DateTimeFormat("en-CA", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).format(instant);
|
|
15
17
|
const identity = (schedule) => createHash("sha256").update(JSON.stringify(schedule)).digest("hex");
|
|
16
18
|
export const planRecordingArchiveSchedule = (input, options) => {
|
|
17
19
|
const now = clock(options.now);
|
|
@@ -29,8 +31,8 @@ export const planRecordingArchiveSchedule = (input, options) => {
|
|
|
29
31
|
fail("archive schedule requires a valid IANA time zone");
|
|
30
32
|
}
|
|
31
33
|
recordingWindows(input.from, input.from);
|
|
32
|
-
if (input.from <=
|
|
33
|
-
recordingWindows(input.from,
|
|
34
|
+
if (input.from <= localDay(now, input.timeZone))
|
|
35
|
+
recordingWindows(input.from, localDay(now, input.timeZone));
|
|
34
36
|
const lookbackDays = input.lookbackDays ?? 7;
|
|
35
37
|
const maxBytes = input.maxBytes ?? 20 * 1024 ** 3;
|
|
36
38
|
if (!Number.isSafeInteger(lookbackDays) || lookbackDays < 0 || lookbackDays > 31)
|
|
@@ -76,11 +78,10 @@ export const parseRecordingArchiveSchedule = (value) => {
|
|
|
76
78
|
export const recordingArchiveScheduleWindow = (value, options) => {
|
|
77
79
|
const schedule = parseRecordingArchiveSchedule(value);
|
|
78
80
|
const now = clock(options.now);
|
|
79
|
-
const through =
|
|
81
|
+
const through = localDay(now, schedule.timeZone);
|
|
80
82
|
if (schedule.from > through)
|
|
81
83
|
return null;
|
|
82
|
-
const floor = new Date(
|
|
83
|
-
floor.setUTCHours(0, 0, 0, 0);
|
|
84
|
+
const floor = new Date(`${through}T00:00:00Z`);
|
|
84
85
|
// A running job ages beyond its original ten-year discovery interval; saved pending work survives separately.
|
|
85
86
|
const month = floor.getUTCMonth();
|
|
86
87
|
const date = floor.getUTCDate();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { QueryAst } from "@wirecat/cli-base/query";
|
|
1
2
|
import type { SearchHit } from "./store.js";
|
|
2
3
|
export interface MeetingSearchOptions {
|
|
3
4
|
accountId: number;
|
|
@@ -37,7 +38,8 @@ export interface MeetingSearchPage {
|
|
|
37
38
|
}
|
|
38
39
|
/** Optional bounded read capability; paging reaches inside a single large transcript. */
|
|
39
40
|
export interface MeetingSearchStore {
|
|
40
|
-
|
|
41
|
+
/** A string is what a person typed, parsed as a query; text that must not become syntax comes as `meetingWordsQuery`. */
|
|
42
|
+
searchHits(query: string | QueryAst, options: MeetingSearchOptions): Promise<MeetingSearchPage>;
|
|
41
43
|
}
|
|
42
44
|
export interface MeetingSearchIndexInput {
|
|
43
45
|
accountId: number;
|
package/dist/meetings/store.d.ts
CHANGED
|
@@ -82,6 +82,13 @@ export interface SearchHit {
|
|
|
82
82
|
id: number;
|
|
83
83
|
text: string;
|
|
84
84
|
startMs: number | null;
|
|
85
|
+
/** `corrected` when a query word matched only as a stored word recognition may have garbled. */
|
|
86
|
+
match?: "words" | "corrected";
|
|
87
|
+
/** For a `corrected` hit, the stored words each such query word matched in this passage. */
|
|
88
|
+
corrections?: {
|
|
89
|
+
from: string;
|
|
90
|
+
to: string[];
|
|
91
|
+
}[];
|
|
85
92
|
}
|
|
86
93
|
export interface ContractCase {
|
|
87
94
|
name: string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TranscriptLine } from "./model.js";
|
|
2
|
+
export declare class TranscriptTextError extends Error {
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
/** What the header of a text transcript says, as written; the caller reads the date in its zone. */
|
|
6
|
+
export interface TranscriptTextHeader {
|
|
7
|
+
title: string | null;
|
|
8
|
+
date: string | null;
|
|
9
|
+
meetingId: string | null;
|
|
10
|
+
speakers: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A transcript in the text form zoom-searcher wrote: a header (`Встреча:`, `Дата:`, `Zoom ID:`, `Говорят:`),
|
|
14
|
+
* a rule, then `[hh:mm:ss] Speaker: text` blocks apart by a blank line. A block may run over several lines.
|
|
15
|
+
* A line ends where the next begins: the file keeps start times only.
|
|
16
|
+
*/
|
|
17
|
+
export declare const parseTranscriptText: (input: string) => {
|
|
18
|
+
header: TranscriptTextHeader;
|
|
19
|
+
lines: TranscriptLine[];
|
|
20
|
+
};
|