@wirecat/cli-core 0.410.0 → 0.412.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 (113) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/cli/bot/command.js +4 -3
  3. package/dist/cli/bot/messages-sync.d.ts +7 -0
  4. package/dist/cli/bot/{store.js → messages-sync.js} +4 -5
  5. package/dist/cli/bot/port.d.ts +4 -4
  6. package/dist/cli/bot/setup.js +11 -5
  7. package/dist/cli/commands-command.js +18 -12
  8. package/dist/cli/config-command.js +1 -0
  9. package/dist/cli/contract-evidence.d.ts +26 -0
  10. package/dist/cli/contract-evidence.js +58 -0
  11. package/dist/cli/contract-templates.d.ts +4 -0
  12. package/dist/cli/contract-templates.js +83 -0
  13. package/dist/cli/discovery-descriptions.d.ts +4 -0
  14. package/dist/cli/discovery-descriptions.js +4 -0
  15. package/dist/cli/index.d.ts +21 -55
  16. package/dist/cli/index.js +18 -55
  17. package/dist/cli/messenger/chat-answers.d.ts +1 -1
  18. package/dist/cli/messenger/chat-answers.js +1 -1
  19. package/dist/cli/messenger/chat-lists.d.ts +1 -1
  20. package/dist/cli/messenger/chats-command.js +3 -0
  21. package/dist/cli/messenger/contacts-command.js +23 -15
  22. package/dist/cli/messenger/guard-commands.d.ts +5 -1
  23. package/dist/cli/messenger/guard-commands.js +5 -3
  24. package/dist/cli/messenger/messages-press-command.js +4 -1
  25. package/dist/cli/messenger/models-command.js +3 -11
  26. package/dist/cli/messenger/records-command.js +1 -1
  27. package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
  28. package/dist/cli/messenger/tasks-command.js +14 -4
  29. package/dist/cli/model-catalogue-command.d.ts +15 -0
  30. package/dist/cli/model-catalogue-command.js +110 -0
  31. package/dist/cli/moved.js +1 -0
  32. package/dist/cli/program.js +2 -0
  33. package/dist/cli/runs/search-command.js +2 -3
  34. package/dist/cli/runs/search-query.d.ts +1 -1
  35. package/dist/cli/runs/search-query.js +18 -2
  36. package/dist/cli/runs/search.d.ts +2 -1
  37. package/dist/cli/runs/search.js +4 -3
  38. package/dist/cli/settings.d.ts +2 -0
  39. package/dist/cli/settings.js +5 -1
  40. package/dist/cli/shared-command-exports.d.ts +644 -0
  41. package/dist/cli/shared-command-exports.js +114 -0
  42. package/dist/cli/shared-contracts.d.ts +1 -0
  43. package/dist/cli/shared-contracts.js +1 -0
  44. package/dist/domain/providers.d.ts +25 -3
  45. package/dist/domain/providers.js +89 -5
  46. package/dist/entities/chat.d.ts +3 -3
  47. package/dist/entities/chat.js +2 -2
  48. package/dist/entities/contact-context.d.ts +8 -8
  49. package/dist/entities/contact.d.ts +4 -4
  50. package/dist/entities/index.d.ts +40 -13
  51. package/dist/entities/index.js +5 -1
  52. package/dist/entities/knowledge-lists.d.ts +28 -0
  53. package/dist/entities/knowledge-lists.js +29 -0
  54. package/dist/entities/list-results.d.ts +1 -1
  55. package/dist/entities/list-results.js +1 -1
  56. package/dist/entities/send-attempt.d.ts +0 -1
  57. package/dist/entities/send-attempt.js +0 -1
  58. package/dist/errors/reasons.d.ts +1 -1
  59. package/dist/errors/reasons.js +7 -0
  60. package/dist/index.d.ts +1 -0
  61. package/dist/index.js +1 -0
  62. package/dist/meetings/cli/index.d.ts +1 -1
  63. package/dist/meetings/cli/index.js +25 -9
  64. package/dist/meetings/cli/passage.d.ts +0 -1
  65. package/dist/meetings/cli/passage.js +5 -3
  66. package/dist/meetings/cli/project-evidence.js +3 -2
  67. package/dist/meetings/cli/search.d.ts +2 -2
  68. package/dist/meetings/cli/search.js +9 -7
  69. package/dist/meetings/event-query.d.ts +1 -0
  70. package/dist/meetings/event-query.js +15 -0
  71. package/dist/meetings/index.d.ts +1 -0
  72. package/dist/meetings/index.js +1 -0
  73. package/dist/meetings/store.d.ts +2 -0
  74. package/dist/meetings/testing/memory.js +5 -0
  75. package/dist/search/account-list.d.ts +5 -2
  76. package/dist/search/account-list.js +27 -11
  77. package/dist/search/query.js +3 -1
  78. package/dist/sends/permission-aliases.js +1 -0
  79. package/dist/services/documents/knowledge.d.ts +5 -3
  80. package/dist/services/documents/knowledge.js +4 -4
  81. package/dist/services/meeting-links.d.ts +3 -1
  82. package/dist/services/meeting-links.js +2 -2
  83. package/dist/services/messages-search.js +15 -3
  84. package/dist/services/search-all.js +5 -2
  85. package/dist/services/tasks.d.ts +2 -0
  86. package/dist/services/tasks.js +6 -4
  87. package/dist/store/accounts.d.ts +3 -0
  88. package/dist/store/accounts.js +2 -0
  89. package/dist/store/exports.d.ts +1 -0
  90. package/dist/store/exports.js +1 -0
  91. package/dist/store/index.d.ts +3 -1
  92. package/dist/store/index.js +2 -0
  93. package/dist/store/knowledge-query.d.ts +6 -0
  94. package/dist/store/knowledge-query.js +34 -0
  95. package/dist/store/providers.d.ts +7 -0
  96. package/dist/store/providers.js +5 -0
  97. package/dist/store/sqlite/events.d.ts +2 -1
  98. package/dist/store/sqlite/events.js +16 -1
  99. package/dist/store/sqlite/knowledge.d.ts +5 -4
  100. package/dist/store/sqlite/knowledge.js +50 -17
  101. package/dist/store/sqlite/mail-rules.d.ts +2 -1
  102. package/dist/store/sqlite/mail-rules.js +12 -2
  103. package/dist/store/sqlite/meetings.js +3 -0
  104. package/dist/store/sqlite/notes.d.ts +11 -5
  105. package/dist/store/sqlite/notes.js +9 -2
  106. package/dist/store/sqlite/open-store.js +2 -0
  107. package/dist/store/sqlite/providers.d.ts +12 -0
  108. package/dist/store/sqlite/providers.js +45 -0
  109. package/dist/store/sqlite/tags.d.ts +1 -1
  110. package/dist/store/sqlite/tags.js +3 -3
  111. package/package.json +3 -3
  112. package/parity.json +92 -111
  113. package/dist/cli/bot/store.d.ts +0 -7
@@ -41,6 +41,7 @@ import { imageEmbedding } from "./image-embedding.js";
41
41
  import { inviteLink } from "./invite-link.js";
42
42
  import { job } from "./job.js";
43
43
  import { joinRequest } from "./join-request.js";
44
+ import { organization, project, reminder } from "./knowledge-lists.js";
44
45
  import { botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, callRecord, scheduledJob, stickerInventory, } from "./list-results.js";
45
46
  import { messageEvent, serveSummary, watchedMessage, watchItem } from "./listener.js";
46
47
  import { mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer } from "./media-archive.js";
@@ -91,7 +92,7 @@ import { topic } from "./topic.js";
91
92
  * subset of its fields, never a renamed one. Commands move onto these one by one; until then, a schema
92
93
  * is the target, not a description of today's output.
93
94
  */
94
- export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, cachedChatMetadata, callRecord, chart, chat, chatAdminChange, chatArchive, chatEvent, chatFolderChange, chatFolderOrder, chatFolderRemoval, chatGroupChange, chatInspection, chatInvite, chatInviteChange, chatMembersChange, chatMembersFetch, chatMetadata, chatMetadataRefresh, chatModeration, chatMuting, chatPin, chatRead, chatRemoval, chatRequestChange, chatRules, chatSender, chatStats, chatTracking, chatUnread, contact, contactActivity, contactAlias, contactCheck, contactContext, contactImport, contactLookup, contactNote, contactNoteRemoval, contactPreparation, contactProfile, contactStateChange, contactSync, contactUpdate, conversation, conversationBatch, conversationBatchStatus, conversationBuildResult, conversationChange, conversationDetails, conversationEmbedding, conversationEmbeddingStatus, conversationHit, conversationPreparation, conversationReadiness, counterRefresh, counters, document, documentLink, endedAccountSessions, evidence, evidencePacket, fact, folder, hit, identity, imageEmbedding, inviteLink, job, joinRequest, linkedPerson, mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, mention, mentionDecision, mentionDetails, mentionDomain, mentionRebuild, message, messageContext, messageCounts, messageDeletion, messageDownload, messageEvent, messageLink, messageLinks, messagePin, messageStar, messageSync, messageTranscript, messageWrite, model, modelKey, note, officialStats, person, place, poll, pollChange, pollVote, ranking, reactionChange, recipient, recipientAdded, recipientChange, recipientOff, recipientRemoved, recordedRun, reference, relationship, removedModelKey, retention, runDetails, runHit, runLocation, savedSearch, scheduledJob, searchHistoryClear, sendAttempt, serveSummary, stickerInventory, storeBackup, storeChatStatus, storeCheck, storeClear, storeCopyRemoval, storeDecrypt, storedModelKey, storeExport, storeGapPlan, storeGapRepair, storeInfo, storeJobCancel, storeJobClear, storeJobDetails, storeJobRetry, storeMigration, storeReindex, storeRepair, storeReset, storeRestore, tagChange, tagging, task, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskPair, taskScan, taskSimilar, taskStats, taskUnmerge, topic, trackedChat, trackedChatHistory, watchedMessage, watchItem, };
95
+ export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, cachedChatMetadata, callRecord, chart, chat, chatAdminChange, chatArchive, chatEvent, chatFolderChange, chatFolderOrder, chatFolderRemoval, chatGroupChange, chatInspection, chatInvite, chatInviteChange, chatMembersChange, chatMembersFetch, chatMetadata, chatMetadataRefresh, chatModeration, chatMuting, chatPin, chatRead, chatRemoval, chatRequestChange, chatRules, chatSender, chatStats, chatTracking, chatUnread, contact, contactActivity, contactAlias, contactCheck, contactContext, contactImport, contactLookup, contactNote, contactNoteRemoval, contactPreparation, contactProfile, contactStateChange, contactSync, contactUpdate, conversation, conversationBatch, conversationBatchStatus, conversationBuildResult, conversationChange, conversationDetails, conversationEmbedding, conversationEmbeddingStatus, conversationHit, conversationPreparation, conversationReadiness, counterRefresh, counters, document, documentLink, endedAccountSessions, evidence, evidencePacket, fact, folder, hit, identity, imageEmbedding, inviteLink, job, joinRequest, linkedPerson, mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, mention, mentionDecision, mentionDetails, mentionDomain, mentionRebuild, message, messageContext, messageCounts, messageDeletion, messageDownload, messageEvent, messageLink, messageLinks, messagePin, messageStar, messageSync, messageTranscript, messageWrite, model, modelKey, note, officialStats, organization, person, place, poll, pollChange, pollVote, project, ranking, reactionChange, recipient, recipientAdded, recipientChange, recipientOff, recipientRemoved, recordedRun, reference, relationship, reminder, removedModelKey, retention, runDetails, runHit, runLocation, savedSearch, scheduledJob, searchHistoryClear, sendAttempt, serveSummary, stickerInventory, storeBackup, storeChatStatus, storeCheck, storeClear, storeCopyRemoval, storeDecrypt, storedModelKey, storeExport, storeGapPlan, storeGapRepair, storeInfo, storeJobCancel, storeJobClear, storeJobDetails, storeJobRetry, storeMigration, storeReindex, storeRepair, storeReset, storeRestore, tagChange, tagging, task, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskPair, taskScan, taskSimilar, taskStats, taskUnmerge, topic, trackedChat, trackedChatHistory, watchedMessage, watchItem, };
95
96
  export const ENTITIES = {
96
97
  sync_progress: syncProgress,
97
98
  ...MEETING_RESULT_ENTITIES,
@@ -167,6 +168,9 @@ export const ENTITIES = {
167
168
  account_privacy: accountPrivacy,
168
169
  account_privacy_change: accountPrivacyChange,
169
170
  account_profile: accountProfile,
171
+ organization,
172
+ project,
173
+ reminder,
170
174
  bot_profile: botProfile,
171
175
  bot_template: botTemplate,
172
176
  bot_seen_chat: botSeenChat,
@@ -0,0 +1,28 @@
1
+ import * as v from "valibot";
2
+ export declare const organization: v.StrictObjectSchema<{
3
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
4
+ readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
5
+ readonly kind: v.PicklistSchema<["company", "team", "family", "community"], undefined>;
6
+ readonly name: v.StringSchema<undefined>;
7
+ readonly scope: v.PicklistSchema<["personal", "work"], undefined>;
8
+ 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`">]>;
9
+ }, undefined>;
10
+ export declare const project: v.StrictObjectSchema<{
11
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
12
+ readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
13
+ readonly key: v.StringSchema<undefined>;
14
+ readonly name: v.StringSchema<undefined>;
15
+ readonly type: v.PicklistSchema<["work", "client", "personal", "oss", "other"], undefined>;
16
+ readonly organization_id: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
17
+ readonly scope: v.PicklistSchema<["personal", "work"], undefined>;
18
+ 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`">]>;
19
+ }, undefined>;
20
+ export declare const reminder: v.StrictObjectSchema<{
21
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
22
+ readonly task: v.StringSchema<undefined>;
23
+ readonly due_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`">]>;
24
+ readonly timezone: v.StringSchema<undefined>;
25
+ readonly state: v.PicklistSchema<["pending", "leased", "delivered", "cancelled"], undefined>;
26
+ readonly revision: v.NumberSchema<undefined>;
27
+ readonly receipt: v.NullableSchema<v.StringSchema<undefined>, undefined>;
28
+ }, undefined>;
@@ -0,0 +1,29 @@
1
+ import * as v from "valibot";
2
+ import { id, reference, text, time } from "./fields.js";
3
+ export const organization = v.strictObject({
4
+ id,
5
+ ref: reference,
6
+ kind: v.picklist(["company", "team", "family", "community"]),
7
+ name: text,
8
+ scope: v.picklist(["personal", "work"]),
9
+ created_at: time,
10
+ });
11
+ export const project = v.strictObject({
12
+ id,
13
+ ref: reference,
14
+ key: text,
15
+ name: text,
16
+ type: v.picklist(["work", "client", "personal", "oss", "other"]),
17
+ organization_id: v.nullable(id),
18
+ scope: v.picklist(["personal", "work"]),
19
+ created_at: time,
20
+ });
21
+ export const reminder = v.strictObject({
22
+ id,
23
+ task: text,
24
+ due_at: time,
25
+ timezone: text,
26
+ state: v.picklist(["pending", "leased", "delivered", "cancelled"]),
27
+ revision: v.number(),
28
+ receipt: v.nullable(text),
29
+ });
@@ -39,7 +39,7 @@ export declare const botMenuEntry: v.StrictObjectSchema<{
39
39
  }, undefined>;
40
40
  export declare const botWebhook: v.StrictObjectSchema<{
41
41
  readonly url: v.StringSchema<undefined>;
42
- readonly types: v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
42
+ readonly types: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
43
43
  }, undefined>;
44
44
  export declare const scheduledJob: v.StrictObjectSchema<{
45
45
  readonly name: v.StringSchema<undefined>;
@@ -26,7 +26,7 @@ export const botAdmin = v.strictObject({
26
26
  title: v.nullable(text),
27
27
  });
28
28
  export const botMenuEntry = v.strictObject({ name: text, description: v.nullable(text) });
29
- export const botWebhook = v.strictObject({ url: text, types: v.nullable(v.array(text)) });
29
+ export const botWebhook = v.strictObject({ url: text, types: v.optional(v.array(text)) });
30
30
  export const scheduledJob = v.strictObject({
31
31
  name: text,
32
32
  kind: v.picklist(["command", "agent"]),
@@ -11,7 +11,6 @@ export declare const sendAttempt: v.StrictObjectSchema<{
11
11
  readonly key: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
12
12
  readonly count: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
13
13
  readonly for_everyone: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
14
- readonly send_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
15
14
  readonly operation_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
16
15
  readonly parent_operation_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
17
16
  readonly reply_to: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
@@ -12,7 +12,6 @@ export const sendAttempt = v.strictObject({
12
12
  key: v.optional(text),
13
13
  count: v.optional(count),
14
14
  for_everyone: v.optional(v.boolean()),
15
- send_id: v.optional(id),
16
15
  operation_id: v.optional(id),
17
16
  parent_operation_id: v.optional(id),
18
17
  reply_to: v.optional(id),
@@ -7,7 +7,7 @@ export declare const REASONS: ErrorReason[];
7
7
  * Detail keys an error from this package may carry, until each is registered on its own reason. Not `cause`:
8
8
  * that can hold a provider's or SQLite's raw text.
9
9
  */
10
- export declare const DETAILS: readonly ["allowed", "alternative", "arguments", "at", "available", "batch", "budget", "built", "candidates", "chat", "chat_id", "cli", "complete", "emitted_bytes", "exact", "forum", "guide", "hint", "id", "index", "kind", "limit", "limit_source", "max_bytes", "model", "name", "operation_id", "operation_ids", "text_limit", "store_refused_in", "partial_output", "path", "permission", "person_ids", "previous_chat_id", "profiles", "provider_error", "provider", "recovery", "reference", "remembered", "retry_at", "runtime", "saved", "scheduled_for", "script", "sent", "sent_count", "settlement_failed", "span", "sqlite", "stage", "standing", "state", "stderr", "term", "total", "upgraded", "wanted"];
10
+ export declare const DETAILS: readonly ["contracts", "allowed", "alternative", "arguments", "at", "available", "batch", "budget", "built", "candidates", "chat", "chat_id", "cli", "complete", "emitted_bytes", "exact", "forum", "guide", "hint", "id", "index", "kind", "limit", "limit_source", "max_bytes", "model", "name", "operation_id", "operation_ids", "text_limit", "store_refused_in", "partial_output", "path", "permission", "person_ids", "previous_chat_id", "profiles", "provider_error", "provider", "recovery", "reference", "remembered", "retry_at", "runtime", "saved", "scheduled_for", "script", "sent", "sent_count", "settlement_failed", "span", "sqlite", "stage", "standing", "state", "stderr", "term", "total", "upgraded", "wanted"];
11
11
  /** What a CLI adds to the shared registry: its own reasons, and the detail keys its adapters raise. */
12
12
  export interface AppErrors {
13
13
  reasons?: readonly ErrorReason[];
@@ -16,6 +16,12 @@ const QUERY = [
16
16
  ["query.topic-scope", "a topic needs its chat in the query"],
17
17
  ].map(([reason, message]) => validation(reason, message));
18
18
  const OTHERS = [
19
+ ["model.offline", "permission_error", "downloading a model needs the network; --offline was requested"],
20
+ [
21
+ "contract.unacknowledged-override",
22
+ "configuration_error",
23
+ "a shared command contract changed without an explicit override",
24
+ ],
19
25
  validation("context.read-budget", "the selected context reads exceed their text or request allowance"),
20
26
  validation("meeting-findings.stale", "meeting findings changed since they were read; stage a new batch"),
21
27
  validation("meeting-findings.dedicated-review", "review meeting findings through the dedicated findings command"),
@@ -111,6 +117,7 @@ export const REASONS = defineReasons([
111
117
  * that can hold a provider's or SQLite's raw text.
112
118
  */
113
119
  export const DETAILS = [
120
+ "contracts",
114
121
  "allowed",
115
122
  "alternative",
116
123
  "arguments",
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export { parseMarkdownSpans } from "./domain/markdown-spans.js";
8
8
  export type { MessageLink, MessagePermalink } from "./domain/message-link.js";
9
9
  export type * from "./domain/models.js";
10
10
  export { countedPoll } from "./domain/polls.js";
11
+ export { isKind, KINDS, type Kind, kindIn, kindOf, PROVIDERS, type ProviderEntry, providerNamed, providers, UNKNOWN_PROVIDER, useProviders, } from "./domain/providers.js";
11
12
  export type { RankingGraphEvidence, RankingGraphLink } from "./domain/rankings-graph.js";
12
13
  export type { RankingComponent, RankingInput, RankingMeasure, RankingOptions, RankingTarget, RankingWeights, ScorePreset, } from "./domain/rankings-options.js";
13
14
  export { rankingOptions } from "./domain/rankings-options.js";
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ export { formatLocator, isLocator, parseLocator } from "./domain/locator.js";
5
5
  export { parseMarkdown } from "./domain/markdown.js";
6
6
  export { parseMarkdownSpans } from "./domain/markdown-spans.js";
7
7
  export { countedPoll } from "./domain/polls.js";
8
+ export { isKind, KINDS, kindIn, kindOf, PROVIDERS, providerNamed, providers, UNKNOWN_PROVIDER, useProviders, } from "./domain/providers.js";
8
9
  export { rankingOptions } from "./domain/rankings-options.js";
9
10
  export { canonicalReference, formatReference, parseReference } from "./domain/references.js";
10
11
  export { normalizeTag, TAG_TYPES } from "./domain/tags.js";
@@ -13,8 +13,8 @@ export interface MeetingCommandDeps {
13
13
  write: (value: unknown, format: "json" | "jsonl" | "text") => void;
14
14
  now?: () => number;
15
15
  }
16
- export declare const addMeetingCommands: (program: Command, deps: MeetingCommandDeps) => void;
17
16
  export { addMeetingPassageCommand, createMeetingPassageCommand, type MeetingPassageFlags, meetingPassageRequest, } from "./passage.js";
18
17
  export { addMeetingProjectEvidenceCommand } from "./project-evidence.js";
19
18
  export { queryWordsAfterOptions } from "./query-options.js";
20
19
  export { addMeetingSearchCommand, createMeetingSearchCommand, type MeetingHitSearch, type MeetingHitSearchOptions, type MeetingSearchFlags, meetingHitSearchRequest, meetingSearchArguments, meetingSearchMeta, validateMeetingHitSearch, } from "./search.js";
20
+ export declare const addMeetingCommands: (program: Command, deps: MeetingCommandDeps) => void;
@@ -1,6 +1,7 @@
1
- import { annotate } from "@wirecat/cli-base/commands";
2
- import { defineQuery, fieldsHelp, timezoneOf, zonedMoment } from "@wirecat/cli-base/query";
1
+ import { annotate, sharedCommand } from "@wirecat/cli-base/commands";
2
+ import { defineQuery, fieldsHelp, parseLucene, timezoneOf, validateQuery, zonedMoment } from "@wirecat/cli-base/query";
3
3
  import { InvalidArgumentError, Option } from "commander";
4
+ import { EVENT_QUERY } from "../event-query.js";
4
5
  import { exportMeeting } from "../export.js";
5
6
  import { importFiles } from "../import.js";
6
7
  import { MEETING_QUERY } from "../item.js";
@@ -30,8 +31,10 @@ const date = (text) => {
30
31
  const LOCAL_READ = { remote: "none", local: "read" };
31
32
  const LOCAL_WRITE = { remote: "none", local: "write" };
32
33
  const FETCH = { remote: "read", local: "write" };
33
- export const addMeetingCommands = (program, deps) => {
34
- const group = program.command("meetings").description("stored meetings and their records");
34
+ const addMeetingCommandsDefinition = (program, deps) => {
35
+ const group = annotate(program.command("meetings").description("stored meetings and their records"), {
36
+ effects: { remote: "none", local: "none" },
37
+ });
35
38
  const output = (command) => command
36
39
  .option("--json", "one JSON value")
37
40
  .option("--jsonl", "one JSON object per item")
@@ -143,14 +146,27 @@ export const addMeetingCommands = (program, deps) => {
143
146
  throw new MeetingError("validation_error", "file account differs from selected account");
144
147
  print(await importFiles(files, deps.store, deps.now?.()), command);
145
148
  });
146
- output(annotate(program.command("events").description("the owner's stored events").command("list"), {
147
- effects: LOCAL_READ,
148
- output: { entity: "event" },
149
- }).description("list stored events")).action(async (_opts, command) => {
150
- print(listed((await deps.store.events()).map(eventItem)), command);
149
+ const eventList = queryWordsAfterOptions(annotate(program.command("events").description("the owner's stored events"), {
150
+ effects: { remote: "none", local: "none" },
151
+ }).command("list"))
152
+ .description("list stored events")
153
+ .argument("[query...]", "event id, origin or time fields that narrow the list")
154
+ .addHelpText("after", `\n${fieldsHelp(EVENT_QUERY, MEETING_QUERY_GUIDE)}`);
155
+ annotate(eventList, { effects: LOCAL_READ, output: { entity: "event" }, query: EVENT_QUERY });
156
+ output(eventList).action(async (words, _opts, command) => {
157
+ const query = words.length
158
+ ? parseLucene(words.join(" "), { defaultField: "none", command: "events list" })
159
+ : undefined;
160
+ if (query)
161
+ validateQuery(query, EVENT_QUERY, { command: "events list" });
162
+ if (query && !deps.store.queryEvents)
163
+ throw new MeetingError("validation_error", "this store cannot filter events");
164
+ const events = query ? await deps.store.queryEvents?.(query) : await deps.store.events();
165
+ print(listed((events ?? []).map(eventItem)), command);
151
166
  });
152
167
  };
153
168
  export { addMeetingPassageCommand, createMeetingPassageCommand, meetingPassageRequest, } from "./passage.js";
154
169
  export { addMeetingProjectEvidenceCommand } from "./project-evidence.js";
155
170
  export { queryWordsAfterOptions } from "./query-options.js";
156
171
  export { addMeetingSearchCommand, createMeetingSearchCommand, meetingHitSearchRequest, meetingSearchArguments, meetingSearchMeta, validateMeetingHitSearch, } from "./search.js";
172
+ export const addMeetingCommands = sharedCommand(addMeetingCommandsDefinition);
@@ -10,7 +10,6 @@ export interface MeetingPassageFlags {
10
10
  }
11
11
  export declare const meetingPassageRequest: (reference: string, options: MeetingPassageFlags, signal?: AbortSignal) => MeetingPassageRequest;
12
12
  export declare const createMeetingPassageCommand: (program: Command) => Command;
13
- /** The host fixes account scope, connection lifetime and final rendering/output limits. */
14
13
  export declare const addMeetingPassageCommand: (program: Command, deps: {
15
14
  read: MeetingPassageReader;
16
15
  signal: () => AbortSignal | undefined;
@@ -1,5 +1,5 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
- import { annotate } from "@wirecat/cli-base/commands";
2
+ import { annotate, sharedCommand } from "@wirecat/cli-base/commands";
3
3
  import { Option } from "commander";
4
4
  import { validateMeetingPassage, } from "../passage.js";
5
5
  const count = (value) => {
@@ -21,7 +21,7 @@ export const meetingPassageRequest = (reference, options, signal) => {
21
21
  signal?.throwIfAborted();
22
22
  return input;
23
23
  };
24
- export const createMeetingPassageCommand = (program) => {
24
+ const createMeetingPassageCommandDefinition = (program) => {
25
25
  const meetings = program.commands.find((command) => command.name() === "meetings");
26
26
  if (!meetings)
27
27
  throw new CliError("configuration_error", "meeting command group is unavailable");
@@ -44,7 +44,7 @@ export const createMeetingPassageCommand = (program) => {
44
44
  });
45
45
  };
46
46
  /** The host fixes account scope, connection lifetime and final rendering/output limits. */
47
- export const addMeetingPassageCommand = (program, deps) => createMeetingPassageCommand(program).action(async (reference, options, command) => {
47
+ const addMeetingPassageCommandDefinition = (program, deps) => createMeetingPassageCommand(program).action(async (reference, options, command) => {
48
48
  const globals = command.optsWithGlobals();
49
49
  const format = globals.json || globals.jsonl ? "json" : (options.format ?? "text");
50
50
  const input = meetingPassageRequest(reference, { ...options, format }, deps.signal());
@@ -52,3 +52,5 @@ export const addMeetingPassageCommand = (program, deps) => createMeetingPassageC
52
52
  input.signal?.throwIfAborted();
53
53
  deps.output(result, format);
54
54
  });
55
+ export const createMeetingPassageCommand = sharedCommand(createMeetingPassageCommandDefinition);
56
+ export const addMeetingPassageCommand = sharedCommand(addMeetingPassageCommandDefinition);
@@ -1,5 +1,5 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
- import { annotate } from "@wirecat/cli-base/commands";
2
+ import { annotate, sharedCommand } from "@wirecat/cli-base/commands";
3
3
  import { fieldsHelp } from "@wirecat/cli-base/query";
4
4
  import { readMeetingProjectEvidence } from "../project-evidence.js";
5
5
  import { MEETING_PROJECT_EVIDENCE_QUERY } from "../project-evidence-query.js";
@@ -9,7 +9,7 @@ const integer = (value) => {
9
9
  throw new CliError("validation_error", "expected a positive safe integer");
10
10
  return Number(value);
11
11
  };
12
- export const addMeetingProjectEvidenceCommand = (program, deps) => {
12
+ const addMeetingProjectEvidenceCommandDefinition = (program, deps) => {
13
13
  const group = program.commands.find((command) => command.name() === "meetings");
14
14
  if (!group)
15
15
  throw new CliError("configuration_error", "meeting command group is unavailable");
@@ -33,3 +33,4 @@ export const addMeetingProjectEvidenceCommand = (program, deps) => {
33
33
  output: { entity: "meeting_project_evidence" },
34
34
  });
35
35
  };
36
+ export const addMeetingProjectEvidenceCommand = sharedCommand(addMeetingProjectEvidenceCommandDefinition);
@@ -12,6 +12,7 @@ export interface MeetingSearchFlags {
12
12
  project?: string;
13
13
  tag?: string;
14
14
  topic?: string;
15
+ topicName?: string;
15
16
  sinceTime?: number;
16
17
  untilTime?: number;
17
18
  /** The zone a date or time without one was read in; the parser sets it, since the typed text is gone after. */
@@ -20,14 +21,13 @@ export interface MeetingSearchFlags {
20
21
  cursor?: string;
21
22
  maxReadBytes?: number;
22
23
  }
23
- /** Shared grammar without an action: a host with other source reports supplies their transport routing. */
24
- export declare const createMeetingSearchCommand: (program: Command) => Command;
25
24
  /** Transport fields become one validated word request before a host opens its selected source. */
26
25
  export declare const meetingHitSearchRequest: (query: string, options: MeetingSearchFlags, signal?: AbortSignal) => MeetingHitSearchOptions;
27
26
  /** Parsed dates must become ISO values again so the CLI can replay its own continuation. */
28
27
  export declare const meetingSearchArguments: (query: string, options: MeetingSearchFlags) => Record<string, unknown>;
29
28
  /** What `meta` says about the dates: the zone one without its own was read in, and the window in UTC. */
30
29
  export declare const meetingSearchMeta: (options: MeetingSearchFlags) => Pick<Meta, "timezone" | "window">;
30
+ export declare const createMeetingSearchCommand: (program: Command) => Command;
31
31
  export declare const addMeetingSearchCommand: (program: Command, deps: {
32
32
  search: (query: string, request: MeetingHitSearchOptions, options: MeetingSearchFlags & Record<string, unknown>) => Promise<MeetingSearchPage>;
33
33
  signal: () => AbortSignal | undefined;
@@ -1,5 +1,5 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
- import { annotate } from "@wirecat/cli-base/commands";
2
+ import { annotate, sharedCommand } from "@wirecat/cli-base/commands";
3
3
  import { timezoneOf, zonedMoment } from "@wirecat/cli-base/query";
4
4
  import { Command } from "commander";
5
5
  import { meetingHitsList } from "../answers.js";
@@ -25,7 +25,7 @@ const integer = (value) => {
25
25
  return Number(value);
26
26
  };
27
27
  /** Shared grammar without an action: a host with other source reports supplies their transport routing. */
28
- export const createMeetingSearchCommand = (program) => {
28
+ const createMeetingSearchCommandDefinition = (program) => {
29
29
  let search = program.commands.find((command) => command.name() === "search");
30
30
  if (!search) {
31
31
  search = new Command("search").description("search the stored resources");
@@ -41,9 +41,9 @@ export const createMeetingSearchCommand = (program) => {
41
41
  .option("--person-id <id>", "meetings with a participant linked to this person", integer)
42
42
  .option("--event-id <id>", "only meetings linked to this stored event", integer)
43
43
  .option("--series-id <id>", "only meetings in this stored series", integer)
44
- .option("--project <name>", "meetings confirmed in this project, by name, key or alias")
44
+ .option("--project <project>", "meetings confirmed in this project, by name, key or alias")
45
45
  .option("--tag <name>", "meetings with this tag, by name or alias")
46
- .option("--topic <name>", "meetings with this topic, by name or alias")
46
+ .option("--topic-name <name>", "meetings with this topic, by name or alias")
47
47
  .option("--since-time <time>", "meetings starting at or after this ISO 8601 date or time", moment("--since-time", false, readIn))
48
48
  .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, readIn))
49
49
  .option("--limit <n>", "how many hits, 1 through 1000 (default 100)", integer)
@@ -66,7 +66,7 @@ export const meetingHitSearchRequest = (query, options, signal) => {
66
66
  meetingSeriesId: options.seriesId,
67
67
  project: options.project,
68
68
  tag: options.tag,
69
- topic: options.topic,
69
+ topic: options.topicName ?? options.topic,
70
70
  since: options.sinceTime,
71
71
  until: options.untilTime,
72
72
  limit: options.limit,
@@ -88,7 +88,7 @@ export const meetingSearchArguments = (query, options) => Object.fromEntries(Obj
88
88
  series_id: options.seriesId?.toString(),
89
89
  project: options.project,
90
90
  tag: options.tag,
91
- topic: options.topic,
91
+ topic_name: options.topicName ?? options.topic,
92
92
  since_time: options.sinceTime === undefined ? undefined : new Date(options.sinceTime).toISOString(),
93
93
  until_time: options.untilTime === undefined ? undefined : new Date(options.untilTime).toISOString(),
94
94
  max_read_bytes: options.maxReadBytes ?? 4194304,
@@ -104,7 +104,9 @@ export const meetingSearchMeta = (options) => {
104
104
  ...(Object.keys(window).length === 0 ? {} : { window }),
105
105
  };
106
106
  };
107
- export const addMeetingSearchCommand = (program, deps) => createMeetingSearchCommand(program).action(async (query, options) => {
107
+ const addMeetingSearchCommandDefinition = (program, deps) => createMeetingSearchCommand(program).action(async (query, options) => {
108
108
  const request = meetingHitSearchRequest(query, options, deps.signal());
109
109
  deps.output(meetingHitsList(await deps.search(query, request, options), request.limit ?? 100, "search meetings", meetingSearchArguments(query, options), meetingSearchMeta(options)));
110
110
  });
111
+ export const createMeetingSearchCommand = sharedCommand(createMeetingSearchCommandDefinition);
112
+ export const addMeetingSearchCommand = sharedCommand(addMeetingSearchCommandDefinition);
@@ -0,0 +1 @@
1
+ export declare const EVENT_QUERY: import("@wirecat/cli-base/query").QueryRegistry;
@@ -0,0 +1,15 @@
1
+ import { defineQuery } from "@wirecat/cli-base/query";
2
+ export const EVENT_QUERY = defineQuery({
3
+ entity: "event",
4
+ backend: "sql",
5
+ fields: [
6
+ { name: "id", type: "num", operators: ["term", "range"], example: "id:1" },
7
+ { name: "origin", type: "enum", operators: ["term"], values: ["auto", "owner"], example: "origin:owner" },
8
+ ...["starts_at", "ends_at", "created_at", "updated_at"].map((name) => ({
9
+ name,
10
+ type: "time",
11
+ operators: ["term", "range"],
12
+ example: `${name}>=2026-01-01`,
13
+ })),
14
+ ],
15
+ });
@@ -2,6 +2,7 @@ export { MEETING_STEPS, type MeetingDetailsItem, type MeetingHitItem, type Meeti
2
2
  export type { MeetingBatchReader } from "./batch.js";
3
3
  export type { MeetingContextStore, MeetingEventLinkInput, MeetingEventLinkReceipt, ParticipantPerson, ParticipantPersonInput, ParticipantPersonLinkInput, ParticipantPersonLinkReceipt, } from "./context-store.js";
4
4
  export { type MeetingCueIdentity, meetingCueFingerprint } from "./cue-fingerprint.js";
5
+ export { EVENT_QUERY } from "./event-query.js";
5
6
  export { linkEvent } from "./events.js";
6
7
  export { exportMeeting, type MeetingExport, type MeetingExportFormat, type MeetingExportOptions, serializeVtt, } from "./export.js";
7
8
  export { type FindingEvidence, type FindingOutcome, findingHash, MEETING_FINDINGS_KIND, type MeetingFactFinding, type MeetingFinding, type MeetingFindingsInput, type MeetingFindingsReceipt, type MeetingTaskFinding, meetingFindingFingerprint, validateMeetingFindings, } from "./findings.js";
@@ -1,5 +1,6 @@
1
1
  export { MEETING_STEPS, meetingDetails, meetingHit, meetingHitsList, meetingSummary, meetingTranscript, } from "./answers.js";
2
2
  export { meetingCueFingerprint } from "./cue-fingerprint.js";
3
+ export { EVENT_QUERY } from "./event-query.js";
3
4
  export { linkEvent } from "./events.js";
4
5
  export { exportMeeting, serializeVtt, } from "./export.js";
5
6
  export { findingHash, MEETING_FINDINGS_KIND, meetingFindingFingerprint, validateMeetingFindings, } from "./findings.js";
@@ -111,6 +111,8 @@ export interface MeetingStore {
111
111
  participants(query: string, accountId?: number): Promise<Participant[]>;
112
112
  search(query: string, filter?: MeetingFilter): Promise<SearchHit[]>;
113
113
  events(): Promise<Event[]>;
114
+ /** Filters at the store; adapters without this method refuse nonempty event queries. */
115
+ queryEvents?(query: QueryAst): Promise<Event[]>;
114
116
  /** Inclusive overlap; an event with a start but no end occupies its start instant. */
115
117
  eventCandidates(filter: EventCandidateFilter): Promise<Event[]>;
116
118
  createEvent(input: NewRecord<Event>, now: number): Promise<Event>;
@@ -1,5 +1,7 @@
1
1
  import { evaluate } from "@wirecat/cli-base/query";
2
+ import { EVENT_QUERY } from "../event-query.js";
2
3
  import { MEETING_QUERY, meetingItem } from "../item.js";
4
+ import { eventItem } from "../read-answers.js";
3
5
  import { MeetingError, positiveInteger } from "../reads.js";
4
6
  const overlap = (start, end, from, to) => start !== null && start <= to && (end ?? start) >= from;
5
7
  /** A test store keeps no accounts: every id is an account of the `memory` provider. */
@@ -136,6 +138,9 @@ export const memoryMeetingStore = () => {
136
138
  async events() {
137
139
  return structuredClone(state.events.filter((e) => e.deletedAt === null));
138
140
  },
141
+ async queryEvents(query) {
142
+ return structuredClone(state.events.filter((event) => event.deletedAt === null && evaluate(query, EVENT_QUERY.fields, { ...eventItem(event), id: event.id })));
143
+ },
139
144
  async eventCandidates(filter) {
140
145
  const series = state.series.find((s) => s.id === filter.meetingSeriesId);
141
146
  return structuredClone(state.events.filter((e) => e.deletedAt === null &&
@@ -24,9 +24,12 @@ export interface ListContext {
24
24
  command?: string;
25
25
  };
26
26
  }
27
- /** An account as `--source` and a hit name it: a notes folder is `notes:<its id>`, never the store's ulid. */
27
+ /**
28
+ * An account as `--source` and a hit name it: a notes folder is `notes:<its id>`, never the store's ulid. The kind is
29
+ * `undefined` for a provider no registry entry names: no search reads it, and `fitting` reports it.
30
+ */
28
31
  export interface ListedAccount extends AccountKey {
29
- kind: Kind;
32
+ kind: Kind | undefined;
30
33
  }
31
34
  /** One entry of the list as written, a group's member included, and the accounts it named. */
32
35
  export interface ListedEntry {
@@ -1,5 +1,5 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
- import { FOLDER_PROVIDER, INTERNAL_NOTES, isKind, kindOf, PROVIDERS, providerNamed, } from "../domain/providers.js";
2
+ import { FOLDER_PROVIDER, INTERNAL_NOTES, isKind, kindIn, kindOf, providerNamed, providers as registered, UNKNOWN_PROVIDER, } from "../domain/providers.js";
3
3
  import { isBotProvider } from "./query.js";
4
4
  /** Store-wide: every profile, tg, MAX and memo reads the same groups. */
5
5
  export const ACCOUNT_GROUPS = "accountGroups";
@@ -25,16 +25,20 @@ export const groupMembers = (value) => itemsOf(value).map((item) => item.toLower
25
25
  ? fail(`"${item}" names no account after the colon`)
26
26
  : item);
27
27
  const describe = (accounts) => accounts.map(({ provider, account, name }) => `${provider}:${account}${name ? ` (${name})` : ""}`).join(", ");
28
- const heldOf = (stored) => [
28
+ /** The app running knows its own provider is a messenger, entry or not. */
29
+ const kindHere = (provider, running) => provider === running.provider ? kindOf(provider) : kindIn(provider);
30
+ const heldOf = (stored, running) => [
29
31
  ...stored
30
- .filter(({ provider }) => kindOf(provider) !== "notes")
31
- .map(({ provider, account, name }) => ({ provider, account, name, kind: kindOf(provider) })),
32
+ .filter(({ provider }) => kindIn(provider) !== "notes")
33
+ .map(({ provider, account, name }) => ({ provider, account, name, kind: kindHere(provider, running) })),
32
34
  { provider: "notes", account: INTERNAL_NOTES, name: null, kind: "notes" },
33
35
  ...stored
34
36
  .filter(({ provider }) => provider === FOLDER_PROVIDER)
35
37
  .map(({ id, name }) => ({ provider: "notes", account: String(id), name, kind: "notes" })),
36
38
  ];
37
- const registry = () => PROVIDERS.map(({ name, aliases }) => (aliases.length ? `${name} (${aliases.join(", ")})` : name)).join(", ");
39
+ const registry = () => registered()
40
+ .map(({ name, aliases }) => (aliases.length ? `${name} (${aliases.join(", ")})` : name))
41
+ .join(", ");
38
42
  const providerOf = (prefix, held, { running, profiles }) => {
39
43
  const wanted = prefix.toLowerCase();
40
44
  if (wanted === running.command?.toLowerCase())
@@ -57,7 +61,11 @@ const accountOf = (prefix, ref, held, context) => {
57
61
  const byId = ofProvider.find(({ account }) => account === ref || account === ref.toLowerCase());
58
62
  if (byId)
59
63
  return byId;
60
- const keyed = (key) => ofProvider.find(({ account }) => account === key.account) ?? { ...key, name: null, kind: kindOf(key.provider) };
64
+ const keyed = (key) => ofProvider.find(({ account }) => account === key.account) ?? {
65
+ ...key,
66
+ name: null,
67
+ kind: kindHere(key.provider, context.running),
68
+ };
61
69
  const recorded = context.profiles[prefix.toLowerCase()]?.[ref];
62
70
  if (recorded?.provider === FOLDER_PROVIDER) {
63
71
  const folder = held.find((one) => one.provider === "notes" && one.name === recorded.account);
@@ -105,7 +113,7 @@ const keyOf = ({ provider, account }) => `${provider}\u0000${account}`;
105
113
  * the account's name — a bare provider for all its accounts, or a bare kind for every provider of it.
106
114
  */
107
115
  export const entriesOfList = (value, context) => {
108
- const held = heldOf(context.held);
116
+ const held = heldOf(context.held, context.running);
109
117
  const entries = [];
110
118
  const entry = (item, group) => {
111
119
  const colon = item.indexOf(":");
@@ -161,6 +169,7 @@ const READS = {
161
169
  notes: "notes — search notes reads them",
162
170
  documents: "documents — search notes reads them",
163
171
  meetings: "meetings — search all reads them",
172
+ events: "calendar events — no search reads them yet",
164
173
  };
165
174
  /**
166
175
  * The accounts of `kinds` the entries name, and each entry that names none of them with the reason. A search
@@ -170,16 +179,23 @@ export const fitting = (entries, kinds, what, reasonOf = (kind) => READS[kind])
170
179
  const chosen = new Map();
171
180
  const skipped = [];
172
181
  for (const { entry, accounts } of entries) {
173
- const fits = accounts.filter(({ kind }) => kinds.includes(kind));
182
+ const fits = accounts.filter(({ kind }) => kind !== undefined && kinds.includes(kind));
174
183
  for (const { provider, account } of fits)
175
184
  if (!chosen.has(keyOf({ provider, account })))
176
185
  chosen.set(keyOf({ provider, account }), { provider, account });
186
+ const known = accounts.filter(({ kind }) => kind !== undefined);
187
+ const unknown = accounts.filter(({ kind }) => kind === undefined);
188
+ if (known.length)
189
+ for (const { provider, account } of unknown)
190
+ skipped.push({ source: `${provider}:${account}`, code: "not_found", reason: UNKNOWN_PROVIDER });
177
191
  if (fits.length)
178
192
  continue;
179
- const other = accounts[0];
180
- skipped.push(other
193
+ const other = known[0];
194
+ skipped.push(other?.kind
181
195
  ? { source: entry, code: "validation_error", reason: reasonOf(other.kind) }
182
- : { source: entry, code: "not_found", reason: "no account in the store" });
196
+ : unknown.length
197
+ ? { source: entry, code: "not_found", reason: UNKNOWN_PROVIDER }
198
+ : { source: entry, code: "not_found", reason: "no account in the store" });
183
199
  }
184
200
  if (chosen.size === 0)
185
201
  fail(`--source names nothing ${what} reads: ${skipped.map(({ source, reason }) => `${source} (${reason})`).join(", ")}`);
@@ -27,7 +27,9 @@ export const sourceOf = (name, value, providers) => {
27
27
  return source;
28
28
  if (isKind(source))
29
29
  fail(`${name}${source} names ${source}, which a message search does not read — ` +
30
- `search ${source === "meetings" ? "all --source meetings" : "notes"} does`);
30
+ (source === "events"
31
+ ? "no search reads them yet"
32
+ : `search ${source === "meetings" ? "all --source meetings" : "notes"} does`));
31
33
  const named = providerNamed(source);
32
34
  if (named && providers.includes(named.name))
33
35
  return named.name;
@@ -28,6 +28,7 @@ const RENAMED = [
28
28
  ["conversations.batches.next", "conversations.batches.show"],
29
29
  ["conversations.consents.revoke", "conversations.consents.remove"],
30
30
  ["stats.messages.counters.refresh", "stats.messages.counters.sync"],
31
+ ["store.fetch", "messages.sync"],
31
32
  ["store.gaps.plan", "store.gaps.show"],
32
33
  ["store.reindex", "store.rebuild"],
33
34
  ];
@@ -1,5 +1,5 @@
1
1
  import type { QueryAst } from "@wirecat/cli-base/query";
2
- import type { Author, Fact, Link, LinkInput, Memory, MemoryInput, MessageStore, Note } from "../../store/index.js";
2
+ import type { Author, Fact, Link, LinkInput, LinkListFilter, Memory, MemoryInput, MessageStore, Note } from "../../store/index.js";
3
3
  export interface DocumentKnowledge {
4
4
  documents(principal: string, query: QueryAst | undefined, page: {
5
5
  limit: number;
@@ -9,8 +9,10 @@ export interface DocumentKnowledge {
9
9
  hasMore: boolean;
10
10
  }>;
11
11
  document(principal: string, ref: string): Promise<Note>;
12
- tags(principal: string, ref: string, action: "list" | "add" | "remove", tags?: string[]): Promise<string[]>;
13
- links(principal: string, ref: string): Promise<Link[]>;
12
+ tags(principal: string, ref: string, action: "list" | "add" | "remove", tags?: string[], filter?: {
13
+ tag?: string;
14
+ }): Promise<string[]>;
15
+ links(principal: string, ref: string, filter?: Omit<LinkListFilter, "from" | "to">): Promise<Link[]>;
14
16
  addLink(principal: string, ref: string, input: Omit<LinkInput, "from" | "origin">): Promise<Link>;
15
17
  removeLink(principal: string, ref: string, id: string): Promise<unknown>;
16
18
  notes(principal: string, ref: string, options?: {