@wirecat/cli-core 0.389.0 → 0.391.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 +37 -0
- package/dist/cli/context.js +1 -0
- package/dist/cli/effects.d.ts +2 -0
- package/dist/cli/effects.js +8 -2
- package/dist/cli/messenger/catch-up.d.ts +0 -19
- package/dist/cli/messenger/catch-up.js +0 -43
- package/dist/cli/messenger/context.js +6 -3
- package/dist/cli/messenger/inbox.js +6 -11
- package/dist/cli/messenger/messages-command.js +5 -15
- package/dist/cli/messenger/review.d.ts +1 -1
- package/dist/cli/messenger/review.js +5 -10
- package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
- package/dist/cli/messenger/tags-command.js +2 -2
- package/dist/cli/program.js +10 -0
- package/dist/cli/settings.d.ts +0 -4
- package/dist/cli/settings.js +7 -5
- package/dist/meetings/index.d.ts +2 -0
- package/dist/meetings/index.js +2 -0
- package/dist/meetings/links.d.ts +18 -0
- package/dist/meetings/links.js +1 -0
- package/dist/meetings/review.d.ts +45 -0
- package/dist/meetings/review.js +1 -0
- package/dist/runs/recording.d.ts +5 -0
- package/dist/runs/recording.js +6 -3
- package/dist/runs/scope.d.ts +3 -1
- package/dist/runs/scope.js +2 -0
- package/dist/search/lucene/registry.d.ts +5 -1
- package/dist/search/lucene/registry.js +10 -4
- package/dist/search/lucene/types.d.ts +8 -0
- package/dist/search/lucene/types.js +4 -0
- package/dist/search/question-plan.js +3 -3
- package/dist/services/excerpt.js +4 -1
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.js +2 -0
- package/dist/services/meeting-links.d.ts +33 -0
- package/dist/services/meeting-links.js +41 -0
- package/dist/services/meeting-review.d.ts +12 -0
- package/dist/services/meeting-review.js +8 -0
- package/dist/services/messages-search.js +2 -2
- package/dist/services/searches.js +3 -3
- package/dist/store/sqlite/lucene-fields.d.ts +3 -1
- package/dist/store/sqlite/lucene-fields.js +78 -11
- package/dist/store/sqlite/lucene.js +16 -11
- package/dist/store/sqlite/meeting-chat-lines.d.ts +3 -0
- package/dist/store/sqlite/meeting-chat-lines.js +34 -0
- package/dist/store/sqlite/meeting-review.d.ts +4 -0
- package/dist/store/sqlite/meeting-review.js +97 -0
- package/dist/store/sqlite/meetings.d.ts +2 -2
- package/dist/store/sqlite/meetings.js +4 -0
- package/package.json +1 -1
- package/parity.json +0 -11
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
import { REVIEW_LIMIT } from "../../meetings/index.js";
|
|
3
|
+
import { fromJson } from "./events.js";
|
|
4
|
+
import { checkMeetingCancelled } from "./meeting-operation.js";
|
|
5
|
+
import { positiveReadInteger } from "./meeting-reads.js";
|
|
6
|
+
import { meetingSelectionSql } from "./meeting-selection.js";
|
|
7
|
+
import { read } from "./transaction.js";
|
|
8
|
+
const number = (value) => (value === null || value === undefined ? null : Number(value));
|
|
9
|
+
const text = (value) => (value === null || value === undefined ? null : String(value));
|
|
10
|
+
/** Talk and words come from one transcript per meeting, its earliest current one, as in meeting stats. */
|
|
11
|
+
export const meetingReviewOver = ({ database }) => ({
|
|
12
|
+
async meetingReview(input) {
|
|
13
|
+
checkMeetingCancelled(input.signal);
|
|
14
|
+
positiveReadInteger(input.accountId, "accountId");
|
|
15
|
+
const limit = input.limit ?? REVIEW_LIMIT.default;
|
|
16
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > REVIEW_LIMIT.most)
|
|
17
|
+
throw new CliError("validation_error", `a review shows 1 through ${REVIEW_LIMIT.most} meetings`);
|
|
18
|
+
return read(database, () => {
|
|
19
|
+
const { clauses, params } = meetingSelectionSql(input);
|
|
20
|
+
const meetings = database
|
|
21
|
+
.prepare(`SELECT m.id, m.account_id, m.title, m.started_at, m.duration_ms, m.participants_count FROM meetings m
|
|
22
|
+
WHERE ${clauses.join(" AND ")} ORDER BY m.started_at DESC, m.id DESC LIMIT ?`)
|
|
23
|
+
.all(...params, limit + 1);
|
|
24
|
+
const shown = meetings.slice(0, limit);
|
|
25
|
+
const items = new Map();
|
|
26
|
+
for (const row of shown)
|
|
27
|
+
items.set(Number(row.id), {
|
|
28
|
+
meetingId: Number(row.id),
|
|
29
|
+
accountId: Number(row.account_id),
|
|
30
|
+
title: text(row.title),
|
|
31
|
+
startedAt: number(row.started_at),
|
|
32
|
+
durationMs: number(row.duration_ms),
|
|
33
|
+
participantsCount: number(row.participants_count),
|
|
34
|
+
projects: [],
|
|
35
|
+
transcript: null,
|
|
36
|
+
speakers: [],
|
|
37
|
+
summary: null,
|
|
38
|
+
});
|
|
39
|
+
if (items.size) {
|
|
40
|
+
const ids = [...items.keys()];
|
|
41
|
+
const marks = ids.map(() => "?").join(",");
|
|
42
|
+
checkMeetingCancelled(input.signal);
|
|
43
|
+
const talk = database
|
|
44
|
+
.prepare(`WITH chosen AS (SELECT min(t.id) AS id, t.meeting_id FROM meeting_transcripts t
|
|
45
|
+
WHERE t.meeting_id IN (${marks}) AND t.deleted_at IS NULL AND t.superseded_at IS NULL GROUP BY t.meeting_id)
|
|
46
|
+
SELECT c.meeting_id, coalesce(person.name, i.name, r.speaker_name, p.display_name) AS speaker,
|
|
47
|
+
count(*) AS lines, sum(max(r.end_ms - r.start_ms, 0)) AS talk_ms,
|
|
48
|
+
sum(length(trim(r.text)) - length(replace(trim(r.text), ' ', '')) + (length(trim(r.text)) > 0)) AS words
|
|
49
|
+
FROM chosen c JOIN meeting_transcript_rows r ON r.meeting_transcript_id = c.id
|
|
50
|
+
LEFT JOIN meeting_participants p ON p.id = r.speaker_participant_id
|
|
51
|
+
LEFT JOIN identities i ON i.id = p.identity_id
|
|
52
|
+
LEFT JOIN identity_links l ON l.identity_id = p.identity_id
|
|
53
|
+
LEFT JOIN persons person ON person.id = l.person_id
|
|
54
|
+
GROUP BY c.meeting_id, speaker ORDER BY c.meeting_id, talk_ms DESC`)
|
|
55
|
+
.all(...ids);
|
|
56
|
+
for (const row of talk) {
|
|
57
|
+
const item = items.get(Number(row.meeting_id));
|
|
58
|
+
item.transcript ??= { lines: 0, words: 0 };
|
|
59
|
+
item.transcript.lines += Number(row.lines);
|
|
60
|
+
item.transcript.words += Number(row.words);
|
|
61
|
+
if (item.speakers.length < 3)
|
|
62
|
+
item.speakers.push({ name: text(row.speaker), talkMs: Number(row.talk_ms) });
|
|
63
|
+
}
|
|
64
|
+
const transcribed = database
|
|
65
|
+
.prepare(`SELECT DISTINCT meeting_id FROM meeting_transcripts
|
|
66
|
+
WHERE meeting_id IN (${marks}) AND deleted_at IS NULL AND superseded_at IS NULL`)
|
|
67
|
+
.all(...ids);
|
|
68
|
+
for (const row of transcribed) {
|
|
69
|
+
const item = items.get(Number(row.meeting_id));
|
|
70
|
+
item.transcript ??= { lines: 0, words: 0 };
|
|
71
|
+
}
|
|
72
|
+
const summaries = database
|
|
73
|
+
.prepare(`SELECT meeting_id, source, title, overview, next_steps, doc_url FROM meeting_summaries
|
|
74
|
+
WHERE meeting_id IN (${marks}) ORDER BY coalesce(external_updated_at, updated_at) DESC, id DESC`)
|
|
75
|
+
.all(...ids);
|
|
76
|
+
for (const row of summaries) {
|
|
77
|
+
const item = items.get(Number(row.meeting_id));
|
|
78
|
+
item.summary ??= {
|
|
79
|
+
source: String(row.source),
|
|
80
|
+
title: text(row.title),
|
|
81
|
+
overview: text(row.overview),
|
|
82
|
+
nextSteps: fromJson(row.next_steps) ?? [],
|
|
83
|
+
url: text(row.doc_url),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const projects = database
|
|
87
|
+
.prepare(`SELECT l.from_id, p.name FROM links l JOIN projects p ON p.id = l.to_id
|
|
88
|
+
WHERE l.from_type = 'meeting' AND l.from_id IN (${marks}) AND l.to_type = 'project' AND l.kind = 'member-of'
|
|
89
|
+
AND l.anchor IS NULL AND l.confirmed = 1 AND p.account_id IS NULL AND p.deleted_at IS NULL ORDER BY p.name`)
|
|
90
|
+
.all(...ids);
|
|
91
|
+
for (const row of projects)
|
|
92
|
+
items.get(Number(row.from_id)).projects.push(String(row.name));
|
|
93
|
+
}
|
|
94
|
+
return { items: [...items.values()], hasMore: meetings.length > limit };
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Attachment, MeetingContextStore, MeetingParticipantSearchStore, MeetingPreparationContextStore, MeetingPreparationKnowledgeStore, MeetingPreparationNotesStore, MeetingRelatedHistoryStore, MeetingSearchIndexStore, MeetingSearchStore, MeetingSeriesHistoryStore, MeetingStatsStore, MeetingStore, MeetingTranscriptReceiptStore, MeetingTranscriptStore, NewRecord } from "../../meetings/index.js";
|
|
1
|
+
import type { Attachment, MeetingChatLinesStore, MeetingContextStore, MeetingParticipantSearchStore, MeetingPreparationContextStore, MeetingPreparationKnowledgeStore, MeetingPreparationNotesStore, MeetingRelatedHistoryStore, MeetingReviewStore, MeetingSearchIndexStore, MeetingSearchStore, MeetingSeriesHistoryStore, MeetingStatsStore, MeetingStore, MeetingTranscriptReceiptStore, MeetingTranscriptStore, NewRecord } from "../../meetings/index.js";
|
|
2
2
|
import type { CacheDatabase } from "../driver.js";
|
|
3
3
|
import { type MeetingContextReadCapabilities, type MeetingReadCapabilities } from "./meeting-reads.js";
|
|
4
4
|
import type { StoreContext } from "./open.js";
|
|
@@ -11,7 +11,7 @@ export declare const saveAttachment: (database: CacheDatabase, type: string, par
|
|
|
11
11
|
export declare const drainMeetingIndex: (database: CacheDatabase, batch?: number) => number;
|
|
12
12
|
/** Each word of the query, as a prefix, all required. */
|
|
13
13
|
export declare const wordsQuery: (query: string) => string | null;
|
|
14
|
-
export type StoredMeetings = MeetingStore & MeetingPreparationContextStore & MeetingPreparationKnowledgeStore & MeetingPreparationNotesStore & MeetingRelatedHistoryStore & MeetingSeriesHistoryStore & MeetingTranscriptStore & MeetingReadCapabilities & MeetingContextReadCapabilities & MeetingParticipantSearchStore & MeetingSearchStore & MeetingTranscriptReceiptStore & MeetingContextStore & MeetingSearchIndexStore & MeetingStatsStore;
|
|
14
|
+
export type StoredMeetings = MeetingStore & MeetingPreparationContextStore & MeetingPreparationKnowledgeStore & MeetingPreparationNotesStore & MeetingRelatedHistoryStore & MeetingSeriesHistoryStore & MeetingTranscriptStore & MeetingReadCapabilities & MeetingContextReadCapabilities & MeetingParticipantSearchStore & MeetingSearchStore & MeetingTranscriptReceiptStore & MeetingContextStore & MeetingSearchIndexStore & MeetingStatsStore & MeetingReviewStore & MeetingChatLinesStore;
|
|
15
15
|
/** The `MeetingStore` of `src/meetings/` over the shared store. */
|
|
16
16
|
export declare const meetingStoreOver: (context: StoreContext) => StoredMeetings;
|
|
17
17
|
export {};
|
|
@@ -5,6 +5,7 @@ import * as eventQueries from "./events.js";
|
|
|
5
5
|
import { fromJson, int, page, str, toJson } from "./events.js";
|
|
6
6
|
import { folded } from "./folded.js";
|
|
7
7
|
import { meetingIdentityPk } from "./identities.js";
|
|
8
|
+
import { meetingChatLinesOver } from "./meeting-chat-lines.js";
|
|
8
9
|
import { meetingContextLinksOver } from "./meeting-context-links.js";
|
|
9
10
|
import { meetingHitIndexOver } from "./meeting-hit-index.js";
|
|
10
11
|
import { meetingHitSearchOver } from "./meeting-hit-search.js";
|
|
@@ -15,6 +16,7 @@ import { meetingPreparationKnowledgeOver } from "./meeting-preparation-knowledge
|
|
|
15
16
|
import { meetingPreparationNotesOver } from "./meeting-preparation-notes.js";
|
|
16
17
|
import { meetingReadsOver } from "./meeting-reads.js";
|
|
17
18
|
import { meetingRelatedHistoryOver } from "./meeting-related-history.js";
|
|
19
|
+
import { meetingReviewOver } from "./meeting-review.js";
|
|
18
20
|
import { meetingSeriesHistoryOver } from "./meeting-series-history.js";
|
|
19
21
|
import { meetingStatsOver } from "./meeting-stats.js";
|
|
20
22
|
import { invalidateMeetingStems } from "./meeting-stem-state.js";
|
|
@@ -573,6 +575,8 @@ export const meetingStoreOver = (context) => {
|
|
|
573
575
|
...meetingRelatedHistoryOver(context),
|
|
574
576
|
...meetingHitSearchOver(context),
|
|
575
577
|
...meetingStatsOver(context),
|
|
578
|
+
...meetingReviewOver(context),
|
|
579
|
+
...meetingChatLinesOver(context),
|
|
576
580
|
...meetingParticipantSearchOver(context),
|
|
577
581
|
...meetingHitIndexOver(context),
|
|
578
582
|
...meetingContextLinksOver(context),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirecat/cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.391.0",
|
|
4
4
|
"description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Viacheslav Ptsarev",
|
package/parity.json
CHANGED
|
@@ -483,9 +483,6 @@
|
|
|
483
483
|
"--local": {
|
|
484
484
|
"meaning": "use the model on this machine, never the messenger"
|
|
485
485
|
},
|
|
486
|
-
"--mark-read": {
|
|
487
|
-
"meaning": "also mark the chat read up to the newest message shown; the other person sees it"
|
|
488
|
-
},
|
|
489
486
|
"--marker": {
|
|
490
487
|
"value": "<value>",
|
|
491
488
|
"meaning": "Marker"
|
|
@@ -635,9 +632,6 @@
|
|
|
635
632
|
"--no-input": {
|
|
636
633
|
"meaning": "never prompt or open an interactive login; piped input remains available"
|
|
637
634
|
},
|
|
638
|
-
"--no-mark-read": {
|
|
639
|
-
"meaning": "do not mark read, whatever the catch_up_marks_read setting says"
|
|
640
|
-
},
|
|
641
635
|
"--no-mentions-me": {
|
|
642
636
|
"meaning": "do not require a mention of you or a reply to you"
|
|
643
637
|
},
|
|
@@ -2876,10 +2870,8 @@
|
|
|
2876
2870
|
"--all": "all",
|
|
2877
2871
|
"--kind": "all",
|
|
2878
2872
|
"--limit": "all",
|
|
2879
|
-
"--mark-read": "all",
|
|
2880
2873
|
"--model": "all",
|
|
2881
2874
|
"--new": "all",
|
|
2882
|
-
"--no-mark-read": "all",
|
|
2883
2875
|
"--since": {
|
|
2884
2876
|
"in": [],
|
|
2885
2877
|
"planned": {
|
|
@@ -3186,7 +3178,6 @@
|
|
|
3186
3178
|
"options": {
|
|
3187
3179
|
"--cursor": "all",
|
|
3188
3180
|
"--limit": "all",
|
|
3189
|
-
"--mark-read": "all",
|
|
3190
3181
|
"--model": "all",
|
|
3191
3182
|
"--transcribe": "all"
|
|
3192
3183
|
}
|
|
@@ -3610,10 +3601,8 @@
|
|
|
3610
3601
|
"options": {
|
|
3611
3602
|
"--all": "all",
|
|
3612
3603
|
"--kind": "all",
|
|
3613
|
-
"--mark-read": "all",
|
|
3614
3604
|
"--model": "all",
|
|
3615
3605
|
"--new": "all",
|
|
3616
|
-
"--no-mark-read": "all",
|
|
3617
3606
|
"--since": {
|
|
3618
3607
|
"in": [],
|
|
3619
3608
|
"planned": {
|