@wirecat/cli-core 0.551.0 → 0.553.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 (94) hide show
  1. package/CHANGELOG.md +83 -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/compact.d.ts +4 -0
  8. package/dist/cli/compact.js +65 -7
  9. package/dist/cli/context.d.ts +2 -0
  10. package/dist/cli/meeting-preparation-answer.d.ts +3 -0
  11. package/dist/cli/meeting-preparation-projects.d.ts +3 -0
  12. package/dist/cli/meeting-preparation-read.d.ts +3 -0
  13. package/dist/cli/messenger/context.d.ts +3 -0
  14. package/dist/cli/messenger/projects-command.js +38 -11
  15. package/dist/cli/messenger/search-answers.js +8 -1
  16. package/dist/cli/messenger/serve-catch-up.d.ts +43 -0
  17. package/dist/cli/messenger/serve-catch-up.js +90 -0
  18. package/dist/cli/messenger/serve-command.js +54 -1
  19. package/dist/cli/messenger/serve-relay.d.ts +1 -0
  20. package/dist/cli/messenger/server-command.d.ts +4 -3
  21. package/dist/cli/messenger/server-command.js +30 -12
  22. package/dist/cli/program.js +9 -4
  23. package/dist/cli/project-evidence.d.ts +33 -4
  24. package/dist/cli/project-evidence.js +38 -4
  25. package/dist/cli/project-status-rows.js +11 -1
  26. package/dist/cli/project-status.d.ts +24 -0
  27. package/dist/cli/project-status.js +52 -9
  28. package/dist/cli/schedule/schedule-command.js +5 -1
  29. package/dist/entities/hit.d.ts +5 -0
  30. package/dist/entities/hit.js +5 -0
  31. package/dist/entities/index.d.ts +27 -0
  32. package/dist/entities/listener.d.ts +6 -0
  33. package/dist/entities/listener.js +1 -0
  34. package/dist/entities/meeting-preparation.d.ts +3 -0
  35. package/dist/errors/reasons.js +1 -0
  36. package/dist/mcp/meeting-preparation.d.ts +3 -0
  37. package/dist/meetings/answers.d.ts +5 -0
  38. package/dist/meetings/answers.js +8 -0
  39. package/dist/meetings/cli/index.js +14 -0
  40. package/dist/meetings/index.d.ts +2 -1
  41. package/dist/meetings/index.js +1 -0
  42. package/dist/meetings/ingest.js +2 -1
  43. package/dist/meetings/language.d.ts +5 -0
  44. package/dist/meetings/language.js +57 -0
  45. package/dist/meetings/mcp/search.d.ts +3 -0
  46. package/dist/meetings/project-evidence-answer.d.ts +3 -0
  47. package/dist/meetings/result-items.d.ts +9 -0
  48. package/dist/meetings/result-items.js +7 -0
  49. package/dist/meetings/store.d.ts +22 -0
  50. package/dist/meetings/testing/memory.js +3 -0
  51. package/dist/meetings/transcription.d.ts +2 -0
  52. package/dist/meetings/transcription.js +5 -1
  53. package/dist/search/lucene/types.d.ts +7 -0
  54. package/dist/search/lucene/types.js +11 -1
  55. package/dist/services/index.d.ts +4 -3
  56. package/dist/services/index.js +4 -3
  57. package/dist/services/link-scorers/index.d.ts +1 -1
  58. package/dist/services/link-scorers/index.js +1 -1
  59. package/dist/services/link-scorers/scan.d.ts +0 -1
  60. package/dist/services/link-scorers/scan.js +1 -1
  61. package/dist/services/messages-archive-search.js +3 -2
  62. package/dist/services/messages-combined.js +2 -2
  63. package/dist/services/messages-discovery.js +2 -2
  64. package/dist/services/notes-search.js +4 -5
  65. package/dist/services/project-purposes.d.ts +28 -0
  66. package/dist/services/project-purposes.js +41 -0
  67. package/dist/services/project-status/index.d.ts +22 -8
  68. package/dist/services/project-status/index.js +17 -9
  69. package/dist/services/search-all-meetings.d.ts +3 -0
  70. package/dist/services/search-all-meetings.js +6 -1
  71. package/dist/services/stored-project-gathering.d.ts +79 -4
  72. package/dist/services/stored-project-gathering.js +171 -22
  73. package/dist/speech/local.d.ts +2 -0
  74. package/dist/speech/local.js +8 -1
  75. package/dist/speech/models.d.ts +2 -0
  76. package/dist/speech/models.js +2 -0
  77. package/dist/store/driver.d.ts +11 -0
  78. package/dist/store/driver.js +13 -0
  79. package/dist/store/drivers/node-sqlite.d.ts +1 -1
  80. package/dist/store/drivers/node-sqlite.js +3 -0
  81. package/dist/store/messages.d.ts +2 -1
  82. package/dist/store/messages.js +2 -2
  83. package/dist/store/sqlite/lucene.d.ts +1 -1
  84. package/dist/store/sqlite/lucene.js +33 -7
  85. package/dist/store/sqlite/meeting-hit-search.js +10 -3
  86. package/dist/store/sqlite/meeting-languages.d.ts +4 -0
  87. package/dist/store/sqlite/meeting-languages.js +36 -0
  88. package/dist/store/sqlite/meetings.d.ts +2 -1
  89. package/dist/store/sqlite/meetings.js +9 -3
  90. package/dist/store/sqlite/note-search.js +2 -2
  91. package/dist/store/sqlite/reads.d.ts +1 -1
  92. package/dist/store/sqlite/reads.js +2 -2
  93. package/package.json +1 -1
  94. package/parity.json +10 -0
@@ -0,0 +1,4 @@
1
+ import { type MeetingStore } from "../../meetings/index.js";
2
+ import type { StoreContext } from "./open.js";
3
+ export type MeetingLanguageStore = Required<Pick<MeetingStore, "fillTranscriptLanguages">>;
4
+ export declare const meetingLanguagesOver: ({ database }: StoreContext) => MeetingLanguageStore;
@@ -0,0 +1,36 @@
1
+ import { transcriptLanguage } from "../../meetings/index.js";
2
+ import { positiveReadInteger } from "./meeting-reads.js";
3
+ import { read, writeBatch } from "./transaction.js";
4
+ export const meetingLanguagesOver = ({ database }) => ({
5
+ async fillTranscriptLanguages({ accountId, apply, now }) {
6
+ positiveReadInteger(accountId, "accountId");
7
+ const found = read(database, () => {
8
+ const rows = database.prepare("SELECT text FROM meeting_transcript_rows WHERE meeting_transcript_id = ?");
9
+ return database
10
+ .prepare(`SELECT t.id FROM meeting_transcripts t JOIN meetings m ON m.id = t.meeting_id
11
+ WHERE m.account_id = ? AND t.language IS NULL AND t.deleted_at IS NULL ORDER BY t.id`)
12
+ .all(accountId)
13
+ .map(({ id }) => ({
14
+ id: Number(id),
15
+ language: transcriptLanguage(rows.all(Number(id)).map((row) => String(row.text))),
16
+ }));
17
+ });
18
+ if (apply) {
19
+ const update = database.prepare("UPDATE meeting_transcripts SET language = ?, updated_at = ? WHERE id = ? AND language IS NULL");
20
+ writeBatch(database, () => {
21
+ for (const { id, language } of found)
22
+ if (language !== null)
23
+ update.run(language, now, id);
24
+ });
25
+ }
26
+ const counts = new Map();
27
+ for (const { language } of found)
28
+ counts.set(language, (counts.get(language) ?? 0) + 1);
29
+ return {
30
+ accountId,
31
+ applied: apply,
32
+ transcripts: found.length,
33
+ languages: [...counts].map(([language, transcripts]) => ({ language, transcripts })),
34
+ };
35
+ },
36
+ });
@@ -1,5 +1,6 @@
1
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
+ import { type MeetingLanguageStore } from "./meeting-languages.js";
3
4
  import { type MeetingContextReadCapabilities, type MeetingReadCapabilities } from "./meeting-reads.js";
4
5
  import type { StoreContext } from "./open.js";
5
6
  type Row = Record<string, unknown>;
@@ -11,7 +12,7 @@ export declare const saveAttachment: (database: CacheDatabase, type: string, par
11
12
  export declare const drainMeetingIndex: (database: CacheDatabase, batch?: number) => number;
12
13
  /** Each word of the query, as a prefix, all required. */
13
14
  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 & MeetingReviewStore & MeetingChatLinesStore;
15
+ export type StoredMeetings = MeetingStore & MeetingPreparationContextStore & MeetingPreparationKnowledgeStore & MeetingPreparationNotesStore & MeetingRelatedHistoryStore & MeetingSeriesHistoryStore & MeetingTranscriptStore & MeetingReadCapabilities & MeetingContextReadCapabilities & MeetingParticipantSearchStore & MeetingSearchStore & MeetingTranscriptReceiptStore & MeetingContextStore & MeetingSearchIndexStore & MeetingStatsStore & MeetingReviewStore & MeetingChatLinesStore & MeetingLanguageStore;
15
16
  /** The `MeetingStore` of `src/meetings/` over the shared store. */
16
17
  export declare const meetingStoreOver: (context: StoreContext) => StoredMeetings;
17
18
  export {};
@@ -11,6 +11,7 @@ import { meetingContextLinksOver } from "./meeting-context-links.js";
11
11
  import { meetingHitIndexOver } from "./meeting-hit-index.js";
12
12
  import { meetingHitSearchOver } from "./meeting-hit-search.js";
13
13
  import { INDEX_CODES, indexedText, meetingRowid, summaryOf } from "./meeting-index-values.js";
14
+ import { meetingLanguagesOver } from "./meeting-languages.js";
14
15
  import { meetingParticipantSearchOver } from "./meeting-participant-search.js";
15
16
  import { meetingPreparationContextOver } from "./meeting-preparation-context.js";
16
17
  import { meetingPreparationKnowledgeOver } from "./meeting-preparation-knowledge.js";
@@ -516,17 +517,18 @@ const search = (database, query, filter) => {
516
517
  .prepare(`WITH hit AS (SELECT rowid AS r FROM meeting_words WHERE meeting_words MATCH ?),
517
518
  picked AS (SELECT id, row_number() OVER (ORDER BY coalesce(started_at, 0) DESC, id) AS n FROM (${picked.sql}))
518
519
  SELECT p.n, 0 AS kind, t.id AS a, r.position AS b, r.id, t.meeting_id, r.start_ms, coalesce(length(CAST(r.text AS BLOB)),0) AS bytes,
519
- r.speaker_name AS speaker, m.account_id
520
+ r.speaker_name AS speaker, m.account_id, t.language,
521
+ (SELECT count(*) FROM meeting_transcript_rows n WHERE n.meeting_transcript_id = t.id) AS lines_total
520
522
  FROM hit h JOIN meeting_transcript_rows r ON h.r % 4 = 1 AND r.id = h.r / 4
521
523
  JOIN meeting_transcripts t ON t.id = r.meeting_transcript_id
522
524
  AND t.superseded_at IS NULL AND t.deleted_at IS NULL
523
525
  JOIN picked p ON p.id = t.meeting_id JOIN meetings m ON m.id = t.meeting_id
524
526
  UNION ALL
525
- SELECT p.n, 1, c.id, 0, c.id, c.meeting_id, NULL, coalesce(length(CAST(c.text AS BLOB)),0), NULL, NULL
527
+ SELECT p.n, 1, c.id, 0, c.id, c.meeting_id, NULL, coalesce(length(CAST(c.text AS BLOB)),0), NULL, NULL, NULL, NULL
526
528
  FROM hit h JOIN meeting_chat_messages c ON h.r % 4 = 2 AND c.id = h.r / 4
527
529
  JOIN picked p ON p.id = c.meeting_id
528
530
  UNION ALL
529
- SELECT p.n, 2, s.id, 0, s.id, s.meeting_id, NULL, coalesce(length(CAST(s.title AS BLOB)),0)+coalesce(length(CAST(s.overview AS BLOB)),0)+coalesce(length(CAST(s.sections AS BLOB)),0)+coalesce(length(CAST(s.next_steps AS BLOB)),0)+coalesce(length(CAST(s.content AS BLOB)),0), NULL, NULL
531
+ SELECT p.n, 2, s.id, 0, s.id, s.meeting_id, NULL, coalesce(length(CAST(s.title AS BLOB)),0)+coalesce(length(CAST(s.overview AS BLOB)),0)+coalesce(length(CAST(s.sections AS BLOB)),0)+coalesce(length(CAST(s.next_steps AS BLOB)),0)+coalesce(length(CAST(s.content AS BLOB)),0), NULL, NULL, NULL, NULL
530
532
  FROM hit h JOIN meeting_summaries s ON h.r % 4 = 3 AND s.id = h.r / 4
531
533
  JOIN picked p ON p.id = s.meeting_id
532
534
  ORDER BY 1, 2, 3, 4 LIMIT 10001`)
@@ -551,6 +553,9 @@ const search = (database, query, filter) => {
551
553
  cuePosition: Number(row.b),
552
554
  }),
553
555
  speakerName: row.speaker === null ? null : String(row.speaker),
556
+ language: row.language === null ? null : String(row.language),
557
+ line: Number(row.b) + 1,
558
+ linesTotal: Number(row.lines_total),
554
559
  }
555
560
  : {};
556
561
  return {
@@ -596,6 +601,7 @@ export const meetingStoreOver = (context) => {
596
601
  ...meetingParticipantSearchOver(context),
597
602
  ...meetingHitIndexOver(context),
598
603
  ...meetingContextLinksOver(context),
604
+ ...meetingLanguagesOver(context),
599
605
  async appendTranscriptsWithReceipt(input) {
600
606
  try {
601
607
  return append(context, input);
@@ -2,7 +2,7 @@ import { CliError } from "@wirecat/cli-base";
2
2
  import { tagOf } from "../../domain/tags.js";
3
3
  import { compileAutomaton, foldRegex, wildcardPattern, } from "../../search/lucene/automaton.js";
4
4
  import { isStemmed } from "../../search/lucene/resolved.js";
5
- import { exhausted, QUERY_LIMITS, searchError } from "../../search/lucene/types.js";
5
+ import { exhausted, outOfTime, QUERY_LIMITS, searchError } from "../../search/lucene/types.js";
6
6
  import { normalize } from "../normalize.js";
7
7
  import { contextDocumentTime } from "./context-document-source.js";
8
8
  import { documentPicturesOver } from "./document-pictures.js";
@@ -126,7 +126,7 @@ export const searchCorpus = (context, query, corpus) => {
126
126
  if (query.signal?.aborted)
127
127
  throw new CliError("validation_error", "search was aborted", { reason: "query.aborted", complete: false });
128
128
  if (context.now() - started > QUERY_LIMITS.milliseconds)
129
- exhausted("time");
129
+ outOfTime();
130
130
  };
131
131
  const tests = new Map();
132
132
  const fragments = new Map();
@@ -882,7 +882,7 @@ export declare const selectMessages: ({ orm }: StoreContext) => Omit<import("dri
882
882
  export declare const newestFirst: SQL<unknown>[];
883
883
  export declare const before: (sentAt: number, pk: number) => SQL<unknown>;
884
884
  export declare const toMessages: ({ orm }: StoreContext, rows: MessageRow[]) => Message[];
885
- export declare const countMessages: ({ orm }: StoreContext, chatKey: number, since: string | undefined) => number;
885
+ export declare const countMessages: ({ orm }: StoreContext, chatKey: number, since: string | undefined, until?: string) => number;
886
886
  /**
887
887
  * What changed in a chat after `at`, a time on this machine's clock: messages first saved or edited
888
888
  * since, oldest first, and the ids deleted since. Send time cannot answer it — an edit made today to
@@ -51,10 +51,10 @@ export const toMessages = ({ orm }, rows) => {
51
51
  }
52
52
  return rows.map((row) => toMessage(row, byMessage.get(row.pk) ?? []));
53
53
  };
54
- export const countMessages = ({ orm }, chatKey, since) => Number(orm
54
+ export const countMessages = ({ orm }, chatKey, since, until) => Number(orm
55
55
  .select({ n: sql `count(*)` })
56
56
  .from(messages)
57
- .where(live(chatKey, since === undefined ? undefined : gte(messages.sentAt, toMs(since))))
57
+ .where(live(chatKey, since === undefined ? undefined : gte(messages.sentAt, toMs(since)), until === undefined ? undefined : lte(messages.sentAt, toMs(until))))
58
58
  .get()?.n);
59
59
  /**
60
60
  * What changed in a chat after `at`, a time on this machine's clock: messages first saved or edited
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.551.0",
3
+ "version": "0.553.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
@@ -478,6 +478,9 @@
478
478
  "meaning": "every chat of these kinds, comma-separated",
479
479
  "note": "a folder (`chats folders`) or an export folder (`store export`) takes these chats"
480
480
  },
481
+ "--include-proposed": {
482
+ "meaning": "also read chats and members proposed for the project and not yet confirmed, each item marked"
483
+ },
481
484
  "--into": {
482
485
  "value": "<id>",
483
486
  "meaning": "the task that stays: a duplicate is merged into it, or a message is linked to it instead of opening a task"
@@ -832,6 +835,10 @@
832
835
  "value": "<url>",
833
836
  "meaning": "the tunnel's https address: the browser apps reach mcp serve --http through it, a messenger delivers to bot watch"
834
837
  },
838
+ "--purpose": {
839
+ "value": "<purposes>",
840
+ "meaning": "the linked chats' purposes to read, comma-separated, or all; a chat left out is counted"
841
+ },
835
842
  "--question": {
836
843
  "meaning": "match only questions"
837
844
  },
@@ -3707,9 +3714,11 @@
3707
3714
  "--contact": "all",
3708
3715
  "--context-query": "all",
3709
3716
  "--cursor": "all",
3717
+ "--include-proposed": "all",
3710
3718
  "--limit": "all",
3711
3719
  "--max-pages": "all",
3712
3720
  "--no-catch-up": "all",
3721
+ "--purpose": "all",
3713
3722
  "--since-time": "all",
3714
3723
  "--sync-first": "all",
3715
3724
  "--sync-time": "all"
@@ -3723,6 +3732,7 @@
3723
3732
  "options": {
3724
3733
  "--before-time": "all",
3725
3734
  "--context-query": "all",
3735
+ "--purpose": "all",
3726
3736
  "--since-time": "all"
3727
3737
  }
3728
3738
  },