@wirecat/cli-core 0.405.0 → 0.407.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 (127) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/botcheck/reasons.d.ts +1 -1
  3. package/dist/cli/analysis-choice.js +1 -1
  4. package/dist/cli/answer-entity.d.ts +8 -0
  5. package/dist/cli/answer-entity.js +31 -0
  6. package/dist/cli/command-contract.js +5 -6
  7. package/dist/cli/commands-command.js +4 -1
  8. package/dist/cli/effects.js +1 -1
  9. package/dist/cli/embedding-choice.d.ts +1 -1
  10. package/dist/cli/embedding-choice.js +2 -2
  11. package/dist/cli/help/command-help.js +2 -2
  12. package/dist/cli/index.d.ts +6 -2
  13. package/dist/cli/index.js +6 -2
  14. package/dist/cli/json-fields.js +2 -2
  15. package/dist/cli/meeting-batch.d.ts +1 -1
  16. package/dist/cli/meeting-batch.js +20 -2
  17. package/dist/cli/meeting-project-candidates-command.js +0 -1
  18. package/dist/cli/meeting-results.d.ts +3 -0
  19. package/dist/cli/meeting-results.js +31 -0
  20. package/dist/cli/meeting-series-inventory-command.js +0 -1
  21. package/dist/cli/messenger/admin-commands.js +14 -14
  22. package/dist/cli/messenger/archive-commands.js +2 -2
  23. package/dist/cli/messenger/attachments-command.js +7 -8
  24. package/dist/cli/messenger/backfill-command.js +1 -1
  25. package/dist/cli/messenger/chat-answers.js +3 -3
  26. package/dist/cli/messenger/chat-lists.js +3 -3
  27. package/dist/cli/messenger/chats-command.js +8 -8
  28. package/dist/cli/messenger/chats-members-command.js +1 -1
  29. package/dist/cli/messenger/contacts-command.js +10 -7
  30. package/dist/cli/messenger/context.d.ts +11 -4
  31. package/dist/cli/messenger/context.js +6 -0
  32. package/dist/cli/messenger/conversation-examples.js +7 -6
  33. package/dist/cli/messenger/conversations-command.d.ts +0 -4
  34. package/dist/cli/messenger/conversations-command.js +130 -135
  35. package/dist/cli/messenger/counters-command.js +4 -2
  36. package/dist/cli/messenger/doctor-command.js +8 -4
  37. package/dist/cli/messenger/gaps-command.js +2 -2
  38. package/dist/cli/messenger/hearing-command.d.ts +1 -1
  39. package/dist/cli/messenger/hearing-command.js +1 -1
  40. package/dist/cli/messenger/images-command.js +1 -1
  41. package/dist/cli/messenger/inbox.js +1 -3
  42. package/dist/cli/messenger/lacks.d.ts +1 -0
  43. package/dist/cli/messenger/lacks.js +1 -1
  44. package/dist/cli/messenger/mcp-command.js +4 -4
  45. package/dist/cli/messenger/messages-comments-command.js +10 -5
  46. package/dist/cli/messenger/metadata-command.js +5 -5
  47. package/dist/cli/messenger/models-command.js +101 -90
  48. package/dist/cli/messenger/private-people-command.js +5 -6
  49. package/dist/cli/messenger/replies-edit-command.js +0 -1
  50. package/dist/cli/messenger/review.js +1 -3
  51. package/dist/cli/messenger/serve-relay.d.ts +1 -0
  52. package/dist/cli/messenger/stats-command.js +1 -1
  53. package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
  54. package/dist/cli/messenger/store-maintenance-command.js +4 -4
  55. package/dist/cli/messenger/stored.js +5 -0
  56. package/dist/cli/messenger/tags-command.js +4 -10
  57. package/dist/cli/messenger/tasks-command.js +3 -3
  58. package/dist/cli/messenger/transcribe-command.js +1 -1
  59. package/dist/cli/moved.d.ts +2 -0
  60. package/dist/cli/moved.js +39 -1
  61. package/dist/cli/permission-keys.js +2 -0
  62. package/dist/cli/result-fields.js +19 -1
  63. package/dist/cli/settings.js +1 -1
  64. package/dist/cli/steps.js +4 -4
  65. package/dist/cli/store-settings.js +1 -1
  66. package/dist/cli/upgrade-command.js +0 -1
  67. package/dist/domain/models.d.ts +3 -3
  68. package/dist/domain/task-categories.js +1 -1
  69. package/dist/embeddings/remote.js +1 -1
  70. package/dist/entities/contact.d.ts +6 -0
  71. package/dist/entities/contact.js +3 -0
  72. package/dist/entities/index.d.ts +139 -0
  73. package/dist/entities/index.js +4 -1
  74. package/dist/entities/member.d.ts +2 -2
  75. package/dist/entities/member.js +2 -2
  76. package/dist/entities/store-records.d.ts +11 -0
  77. package/dist/entities/store-records.js +1 -0
  78. package/dist/mcp/agent.d.ts +1 -0
  79. package/dist/mcp/agent.js +1 -1
  80. package/dist/mcp/tools/attachments.js +1 -1
  81. package/dist/meetings/cli/index.js +10 -3
  82. package/dist/meetings/index.d.ts +1 -0
  83. package/dist/meetings/index.js +1 -0
  84. package/dist/meetings/result-items.d.ts +127 -0
  85. package/dist/meetings/result-items.js +125 -0
  86. package/dist/ports/app.d.ts +1 -1
  87. package/dist/ports/messenger.d.ts +6 -1
  88. package/dist/search/task-similarity.js +1 -1
  89. package/dist/sends/guard.js +2 -2
  90. package/dist/sends/permission-aliases.d.ts +5 -0
  91. package/dist/sends/permission-aliases.js +49 -0
  92. package/dist/sends/permissions.js +33 -25
  93. package/dist/services/admin.js +7 -7
  94. package/dist/services/chats.js +1 -1
  95. package/dist/services/conversations.d.ts +1 -1
  96. package/dist/services/conversations.js +1 -1
  97. package/dist/services/counters.js +1 -1
  98. package/dist/services/embeddings-maintenance.js +2 -2
  99. package/dist/services/embeddings-search.js +1 -1
  100. package/dist/services/embeddings.d.ts +4 -4
  101. package/dist/services/messages-search.d.ts +1 -1
  102. package/dist/services/messages-search.js +2 -2
  103. package/dist/services/metadata.js +2 -2
  104. package/dist/services/notes-search.js +3 -3
  105. package/dist/services/search-catchup.js +1 -1
  106. package/dist/speech/install.d.ts +4 -2
  107. package/dist/speech/install.js +16 -4
  108. package/dist/speech/local.js +1 -1
  109. package/dist/speech/transcribe.js +1 -1
  110. package/dist/store/search-index.d.ts +1 -1
  111. package/dist/store/sqlite/attachment-texts.d.ts +1 -1
  112. package/dist/store/sqlite/attachment-texts.js +1 -1
  113. package/dist/store/sqlite/batches.js +1 -1
  114. package/dist/store/sqlite/involvements.d.ts +1 -1
  115. package/dist/store/sqlite/note-index.d.ts +2 -2
  116. package/dist/store/sqlite/note-index.js +2 -2
  117. package/dist/store/sqlite/search-index.d.ts +1 -1
  118. package/dist/store/sqlite/search-index.js +1 -1
  119. package/dist/store/sqlite/stems-fill.d.ts +3 -3
  120. package/dist/store/sqlite/stems-fill.js +3 -3
  121. package/dist/store/sqlite/stems.d.ts +1 -1
  122. package/dist/store/sqlite/task-pairs.d.ts +1 -1
  123. package/dist/store/sqlite/task-pairs.js +1 -1
  124. package/package.json +1 -1
  125. package/parity.json +130 -139
  126. package/skills/follow-ups/SKILL.md +5 -5
  127. package/skills/link-conversations/SKILL.md +8 -8
package/CHANGELOG.md CHANGED
@@ -5,7 +5,42 @@ Notable changes to `@wirecat/cli-core` (`@wirecat/cli-messaging` up to 0.261.0,
5
5
  minor version may break callers, and says how under "Changed — may break callers". `pnpm docs:check` checks the
6
6
  shape of this file.
7
7
 
8
- ## Unreleased
8
+ ## 0.407.0 — 24.10.2026
9
+
10
+ ### Added
11
+
12
+ - The `contact` entity has optional `email` and `phones` (number and label), for a source that knows them, such as zm's Zoom contacts.
13
+
14
+ - Command discovery projections preserve the CLI document and command identities while selecting fields inside its command tree.
15
+
16
+ - Portable ingestion, export, association, transcription and embedding receipts have shared entities and `meetingResultItem` serializers. Public IDs are strings; stored numeric IDs remain internal.
17
+
18
+ - Meeting batch results declare their correlated success/error schemas. `answerEntity` can name a separate typed projection payload, preserving batch field selection inside each answer without weakening its outer result contract.
19
+
20
+ ## 0.406.0 — 24.10.2026
21
+
22
+ ### Added
23
+
24
+ - `StoredMessages.threadMessages` lets an adapter read a provider thread from the shared message store without
25
+ keeping another copy. `HistoryBatch.deletions` applies chat-scoped tombstones from synced snapshots without
26
+ replaying those deletions as live events. `Messenger.readsComments` allows comment reads independently of
27
+ comment sending; unset, it keeps the existing capability behavior.
28
+ - Speech model installation can verify existing files before reusing them (`verifyExisting`), so repair uses the shared checksum and download path.
29
+ - Provider adapters can declare a typed answer with `answerEntity`, shared by command schemas, help and JSON field validation without changing a shared entity.
30
+
31
+ ### Fixed
32
+
33
+ - Finite meeting inventory, project scanning and upgrade commands are available to the shared MCP catalogue. Profile permissions still apply; upgrade retains its authority grant.
34
+
35
+ ### Changed — may break callers
36
+
37
+ - **Only canonical option spellings are accepted.** The hidden flag aliases introduced in 0.399.0 are removed: use the analysis/embedding/consent provider flags, `--claim`, `--answer-model`, `--template-mode`, `--text-file`, `--disappear-after` and the `kind:` query term. Retired flags are refused before command work.
38
+
39
+ - **Shared command paths use the vocabulary.** Contacts use `info`, `events` and `aliases remove`; chat invite links use `links remove`, member checks use `check`, and join requests use `confirm` or `reject`. Metadata uses `show` and `sync`; task edits use `update`; derived tags and search indexes use `rebuild`. Discovery uses `commands info`; MCP configuration uses `mcp add` and `mcp check`.
40
+
41
+ - **Explicit model and conversation commands.** Use `models list kind:audio` or `kind:text`, `models download <model>` and `models keys set/remove`. Conversation link construction is `conversations links rebuild`; vector reports and removal are `conversations embeddings status/clear`, while `conversations embed` still computes vectors. Duplicate candidates are `tasks duplicates list`. Report information is `doctor reports show`; `doctor reports create` writes the report. Bare groups only offer help. Retired spellings are refused with guidance to the canonical path; no compatibility command aliases are mounted. CLI and MCP use the same paths.
42
+
43
+ - **Rename moved permission paths.** A saved key or startup override using a renamed path now stops with `configuration_error` and its exact replacement (including bot keys), before opening the store or performing the action. Canonical commands keep the migrated denial; retired CLI spellings cannot run.
9
44
 
10
45
  ## 0.405.0 — 24.10.2026
11
46
 
@@ -1,4 +1,4 @@
1
- /** What `chats members audit` judges from a member list and the store. */
1
+ /** What `chats members check` judges from a member list and the store. */
2
2
  export type AuditReason = "bot" | "scam" | "fake" | "deleted" | "no_photo" | "no_username" | "odd_name" | "never_wrote" | "link_first" | "burst_join" | "mass_invited";
3
3
  /** What only a look at one person adds: their profile, all their stored messages, the registries. */
4
4
  export type PersonReason = "new_account" | "no_bio" | "same_text" | "photo_recent" | RegistryReason;
@@ -35,6 +35,6 @@ export const analysisChoice = (options, app, settings, env, keyring) => {
35
35
  const keyName = customUrl === undefined ? provider : endpointKeyName(baseUrl);
36
36
  const apiKey = embeddingKeys(app, env, keyring).read(keyName)?.key;
37
37
  if (!apiKey && customUrl === undefined)
38
- throw new CliError("authentication_error", `no ${provider} key — use models text key set ${provider}`);
38
+ throw new CliError("authentication_error", `no ${provider} key — use models keys set ${provider}`);
39
39
  return { provider, model, baseUrl, ...(apiKey ? { apiKey } : {}) };
40
40
  };
@@ -0,0 +1,8 @@
1
+ import type { Command } from "commander";
2
+ import type * as v from "valibot";
3
+ /** Provider-specific wire fields must not redefine an entity shared by every CLI. */
4
+ export declare const answerEntity: (command: Command, name: string, schema: v.GenericSchema, options?: {
5
+ project?: v.GenericSchema;
6
+ }) => Command;
7
+ export declare const answerEntitySchema: (command: Command | undefined) => v.GenericSchema | undefined;
8
+ export declare const answerProjectionSchema: (command: Command | undefined) => v.GenericSchema | undefined;
@@ -0,0 +1,31 @@
1
+ import { annotate, metaOf } from "@wirecat/cli-base/commands";
2
+ import { ENTITIES } from "../entities/index.js";
3
+ const schemas = new WeakMap();
4
+ /** Provider-specific wire fields must not redefine an entity shared by every CLI. */
5
+ export const answerEntity = (command, name, schema, options = {}) => {
6
+ if (Object.hasOwn(ENTITIES, name))
7
+ throw new Error(`${name} is a shared entity; use its existing schema`);
8
+ if (!/^[a-z][a-z0-9_]*$/.test(name))
9
+ throw new Error("an answer entity needs a lowercase name");
10
+ if (!("entries" in schema) && schema.type !== "union")
11
+ throw new Error("an answer entity needs an object schema or a union of object schemas");
12
+ if (options.project && !("entries" in options.project) && options.project.type !== "union")
13
+ throw new Error("projection needs an object schema or a union of object schemas");
14
+ schemas.set(command, { name, schema, ...options });
15
+ return annotate(command, { output: { entity: name } });
16
+ };
17
+ export const answerEntitySchema = (command) => {
18
+ const output = command && metaOf(command).output;
19
+ if (!output)
20
+ return undefined;
21
+ const name = output.view ? `${output.entity}.${output.view}` : output.entity;
22
+ const shared = ENTITIES[name];
23
+ if (shared)
24
+ return shared;
25
+ const own = schemas.get(command);
26
+ return own?.name === name ? own.schema : undefined;
27
+ };
28
+ export const answerProjectionSchema = (command) => {
29
+ const own = command && schemas.get(command);
30
+ return own && metaOf(command).output?.entity === own.name ? own.project : undefined;
31
+ };
@@ -1,8 +1,8 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
2
  import { describeOptions, metaOf } from "@wirecat/cli-base/commands";
3
3
  import { jsonSchemaOf } from "@wirecat/cli-base/standards";
4
- import { ENTITIES } from "../entities/index.js";
5
4
  import { keyForCommand } from "../sends/permissions.js";
5
+ import { answerEntitySchema, answerProjectionSchema } from "./answer-entity.js";
6
6
  import { answerSchema } from "./envelope.js";
7
7
  export const SCHEMA_DIALECT = "https://json-schema.org/draft/2020-12/schema";
8
8
  /**
@@ -10,10 +10,7 @@ export const SCHEMA_DIALECT = "https://json-schema.org/draft/2020-12/schema";
10
10
  * A command that declares none answers the same envelopes with items of any shape; `--jsonl` streams the items.
11
11
  */
12
12
  export const outputOf = (command) => {
13
- const output = metaOf(command).output;
14
- const entity = output
15
- ? ENTITIES[(output.view ? `${output.entity}.${output.view}` : output.entity)]
16
- : undefined;
13
+ const entity = answerEntitySchema(command);
17
14
  const { $schema: _, ...schema } = jsonSchemaOf(answerSchema(entity));
18
15
  const { $schema: __, ...item } = (entity ? jsonSchemaOf(entity) : {});
19
16
  const coverage = entity ? "declared-entity" : "envelope-with-open-items";
@@ -100,7 +97,9 @@ export const commandContract = (command) => {
100
97
  outputSchemaCoverage: output.coverage,
101
98
  jsonlSchema: { $schema: SCHEMA_DIALECT, ...output.item },
102
99
  jsonlSchemaCoverage: output.coverage,
103
- projection: "--json=<fields> may omit item/object members; present members retain their types and envelopes are preserved",
100
+ projection: answerProjectionSchema(command)
101
+ ? "--json=<fields> selects inside each nested answer; correlation and envelopes are preserved"
102
+ : "--json=<fields> may omit item/object members; present members retain their types and envelopes are preserved",
104
103
  validation: {
105
104
  syntax: "declared",
106
105
  semantic: "command-and-provider-validation",
@@ -50,7 +50,10 @@ export const commandsCommand = (app) => {
50
50
  exit_codes: { ok: 0, [CRASH_CODE]: GENERIC_FAILURE, ...EXIT_CODES },
51
51
  });
52
52
  });
53
- command.addCommand(annotate(new Command("schema"), { effects: NO_EFFECTS })
53
+ command.addCommand(annotate(new Command("info"), {
54
+ effects: NO_EFFECTS,
55
+ examples: [`${app.command} commands info messages list`],
56
+ })
54
57
  .description("one command's argv and result schemas, effects, permissions and retry guidance")
55
58
  .argument("<path...>", "one command path, for example: stats messages show")
56
59
  .action(function (path) {
@@ -124,7 +124,7 @@ export const ownerOnlyOption = (flags, description) => annotateOption(new Option
124
124
  export const judgedEffects = (effects) => effects && { remote: effects.remote, local: "none" };
125
125
  /**
126
126
  * An unasked step is judged stricter than a retry: only a fetch's local write is incidental. A command that reads
127
- * nothing remotely and writes here (`server restart`, `store reindex`) is the whole point of the step, so it waits
127
+ * nothing remotely and writes here (`server restart`, `store rebuild`) is the whole point of the step, so it waits
128
128
  * to be asked (RISK-1211).
129
129
  */
130
130
  const judgedStepEffects = (effects) => effects?.remote === "none" ? effects : judgedEffects(effects);
@@ -10,7 +10,7 @@ export interface ModelOptions {
10
10
  dims?: number;
11
11
  concurrency?: number;
12
12
  }
13
- /** A local model id, or a remote model with its key from `models text key set`. */
13
+ /** A local model id, or a remote model with its key from `models keys set`. */
14
14
  export declare const embeddingChoice: ({ model, provider, embeddingProvider, baseUrl, dims, concurrency }: ModelOptions, app: AppIdentity, settings: AISettings, env: NodeJS.ProcessEnv, { needKey, keyring }?: {
15
15
  needKey?: boolean;
16
16
  keyring?: KeyringStore | undefined;
@@ -5,7 +5,7 @@ import { DEFAULT_TEXT_MODEL } from "../embeddings/models.js";
5
5
  import { isLocal, remoteModel } from "../embeddings/remote.js";
6
6
  import { readOnlyLockOf, readOnlyRefusal } from "../ports/app.js";
7
7
  import { typedCommand } from "../runs/scope.js";
8
- /** A local model id, or a remote model with its key from `models text key set`. */
8
+ /** A local model id, or a remote model with its key from `models keys set`. */
9
9
  export const embeddingChoice = ({ model, provider, embeddingProvider, baseUrl, dims, concurrency }, app, settings, env, { needKey = true, keyring } = {}) => {
10
10
  if (embeddingProvider !== undefined && provider !== undefined)
11
11
  throw new CliError("validation_error", "give --embedding-provider or its legacy --provider spelling, not both");
@@ -34,7 +34,7 @@ export const embeddingChoice = ({ model, provider, embeddingProvider, baseUrl, d
34
34
  const keyName = baseUrl === undefined ? "openai" : endpointKeyName(baseUrl);
35
35
  const key = embeddingKeys(app, env, keyring).read(keyName)?.key;
36
36
  if (!key && needKey && baseUrl === undefined) {
37
- throw new CliError("authentication_error", `no OpenAI key — \`${typedCommand(app.command, "models text key set openai")}\`, or OPENAI_API_KEY`);
37
+ throw new CliError("authentication_error", `no OpenAI key — \`${typedCommand(app.command, "models keys set openai")}\`, or OPENAI_API_KEY`);
38
38
  }
39
39
  return { remote, ...(key ? { apiKey: key } : {}), ...(concurrency ? { concurrency } : {}) };
40
40
  };
@@ -112,8 +112,8 @@ const returnsOf = (command) => {
112
112
  const noun = (output.view ? `${output.entity} ${output.view}` : output.entity).replaceAll("_", " ");
113
113
  const more = fields.length > 8 ? `, and ${fields.length - 8} more` : "";
114
114
  const root = rootOf(command);
115
- const schema = commandAt(root, "commands schema")
116
- ? `; every field: ${root.name()} commands schema ${commandPathOf(command).join(" ")}`
115
+ const schema = commandAt(root, "commands info")
116
+ ? `; every field: ${root.name()} commands info ${commandPathOf(command).join(" ")}`
117
117
  : "";
118
118
  return `${noun} — ${fields.slice(0, 8).join(", ")}${more}${schema}`;
119
119
  };
@@ -1,5 +1,6 @@
1
1
  export { AI_ENTRIES, AI_SETTING_KEYS, type AISettings, resolveAISettings } from "../analysis/settings.js";
2
2
  export { parseDuration } from "../domain/duration.js";
3
+ export { syncProgress } from "../entities/store-records.js";
3
4
  export { isCliFailure, isCommanderFailure } from "../errors/failures.js";
4
5
  export { type AppErrors, failureContext } from "../errors/reasons.js";
5
6
  export { botInstructions } from "../mcp/bot/instructions.js";
@@ -10,6 +11,7 @@ export { callMeetingProjectCandidatesTool, meetingProjectCandidatesTool } from "
10
11
  export { callMeetingSeriesInventoryTool, meetingSeriesInventoryTool } from "../mcp/meeting-series-inventory.js";
11
12
  export { registerLinkConversationsPrompt } from "../mcp/prompts.js";
12
13
  export { agentBody, agentJson, agentResult, UNTRUSTED, UNTRUSTED_INSTRUCTION } from "../mcp/text.js";
14
+ export { MEETING_RESULT_ENTITIES } from "../meetings/index.js";
13
15
  export { type AppIdentity, envName, readOnlyLockOf, readOnlyRefusal } from "../ports/app.js";
14
16
  export type { AccountEditing, AccountHealth, AccountRecords, AccountSettings, AccountStanding, AccountTools, After, BotChats, ChannelComments, ChatDeletion, ChatFolders, ChatReading, ContactBook, Download, ForumControl, ForumState, GroupAdmin, GroupModeration, HistoryBatch, HistoryChatEvent, HistoryReaction, HistoryStar, HistoryVote, InviteLinks, JoinRequests, LiveUpdates, MessageButtons, MessageEditing, MessageMedia, MessagePermalinks, MessagePins, MessagePolls, MessageReactions, MessageSearch, MessageStars, MessengerAdapter, MessengerCore, NewPoll, OfficialStats, PassiveUpdates, PersonProfiles, ProfileChange, ProfilePhotos, PushedHistory, ReadState, RemoteFile, ScheduledMessages, SenderIdentities, SenderSearch, SendOptions, Sent, ServerQuery, ServerReads, ThreadAddressing, TopicEditing, TopicHistory, TopicReadState, Transcript, } from "../ports/messenger.js";
15
17
  export type { Fetching, MediaOption, MessengerTraits } from "../ports/traits.js";
@@ -33,6 +35,7 @@ export { unanswered } from "../services/questions.js";
33
35
  export { openRequestTask } from "../services/task-rules.js";
34
36
  export { TASK_PAIR_QUERY, TASK_QUERY } from "../services/tasks.js";
35
37
  export { type AgentPolicy, type AgentTask, type EvaluationResult, evaluateAgent, type Observation, } from "./agent-evaluation.js";
38
+ export { answerEntity } from "./answer-entity.js";
36
39
  export { botAdminsCommand, botMembersCommand } from "./bot/admins.js";
37
40
  export { type ApiCommandInput, type ApiCommands, generatedApiCommand } from "./bot/api.js";
38
41
  export { apiFlagOf, apiJson, apiOptionKey, apiPlainJson, checkApiBody, checkApiParameter, parseApiJson, readApiBody, } from "./bot/api-input.js";
@@ -53,8 +56,8 @@ export { loadSnakeCaseConfig } from "./config-keys.js";
53
56
  export { type AgentRun, type BaseContext, type BaseEnvironment, baseContext, environmentOf, outputFor, provide, secretInputOf, } from "./context.js";
54
57
  export { type Closeable, withDeadline } from "./deadline.js";
55
58
  export { DEFAULT_CONFIG, ensureDefaultConfig } from "./default-config.js";
56
- export { changesAuthority, changesAuthorityAt, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
57
- export { type AnswerOutput, answerSchema, type Body, type ItemBody, itemAnswer, itemOf, jsonlRecords, judgedAnswer, type ListBody, type ListInput, listOf, metaNow, printItem, renderAnswer, sealed, snakeKeys, snakeKeysKeeping, } from "./envelope.js";
59
+ export { changesAuthority, changesAuthorityAt, changesAuthorityNow, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
60
+ export { type AnswerOutput, answerSchema, type Body, type ItemBody, isBody, itemAnswer, itemOf, jsonlRecords, judgedAnswer, type ListBody, type ListInput, listOf, metaNow, printItem, renderAnswer, sealed, snakeKeys, snakeKeysKeeping, } from "./envelope.js";
58
61
  export { withAbort } from "./execution.js";
59
62
  export { askSetupQuestions, asksAtStart, type FirstRun, type FirstRunIo, LANGUAGES, setupAtStart, systemLanguage, } from "./first-run.js";
60
63
  export { checkGuide, checkStep, type GuideOptions, type GuideReference, type GuideStep, guideCommand, loadScenarios, MEMO_SCENARIOS, type Scenario, shellProblems, } from "./guide.js";
@@ -73,6 +76,7 @@ export { addMeetingPreparationCommand } from "./meeting-preparation-command.js";
73
76
  export { type MeetingPreparationReader, meetingPreparationInput, readMeetingPreparation, } from "./meeting-preparation-read.js";
74
77
  export { addMeetingProjectCandidatesCommand } from "./meeting-project-candidates-command.js";
75
78
  export { readMeetingProjectCandidates } from "./meeting-project-candidates-read.js";
79
+ export { meetingResultItem } from "./meeting-results.js";
76
80
  export { addMeetingSeriesInventoryCommand } from "./meeting-series-inventory-command.js";
77
81
  export { type MeetingSeriesInventoryReader, readMeetingSeriesInventory } from "./meeting-series-inventory-read.js";
78
82
  export { accountCommand } from "./messenger/account-command.js";
package/dist/cli/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { AI_ENTRIES, AI_SETTING_KEYS, resolveAISettings } from "../analysis/settings.js";
2
2
  export { parseDuration } from "../domain/duration.js";
3
+ export { syncProgress } from "../entities/store-records.js";
3
4
  export { isCliFailure, isCommanderFailure } from "../errors/failures.js";
4
5
  export { failureContext } from "../errors/reasons.js";
5
6
  export { botInstructions } from "../mcp/bot/instructions.js";
@@ -8,6 +9,7 @@ export { callMeetingProjectCandidatesTool, meetingProjectCandidatesTool } from "
8
9
  export { callMeetingSeriesInventoryTool, meetingSeriesInventoryTool } from "../mcp/meeting-series-inventory.js";
9
10
  export { registerLinkConversationsPrompt } from "../mcp/prompts.js";
10
11
  export { agentBody, agentJson, agentResult, UNTRUSTED, UNTRUSTED_INSTRUCTION } from "../mcp/text.js";
12
+ export { MEETING_RESULT_ENTITIES } from "../meetings/index.js";
11
13
  export { envName, readOnlyLockOf, readOnlyRefusal } from "../ports/app.js";
12
14
  export { senderFacts } from "../replies/dry-run.js";
13
15
  export { replyRenderer } from "../replies/rendering.js";
@@ -28,6 +30,7 @@ export { unanswered } from "../services/questions.js";
28
30
  export { openRequestTask } from "../services/task-rules.js";
29
31
  export { TASK_PAIR_QUERY, TASK_QUERY } from "../services/tasks.js";
30
32
  export { evaluateAgent, } from "./agent-evaluation.js";
33
+ export { answerEntity } from "./answer-entity.js";
31
34
  export { botAdminsCommand, botMembersCommand } from "./bot/admins.js";
32
35
  export { generatedApiCommand } from "./bot/api.js";
33
36
  export { apiFlagOf, apiJson, apiOptionKey, apiPlainJson, checkApiBody, checkApiParameter, parseApiJson, readApiBody, } from "./bot/api-input.js";
@@ -48,8 +51,8 @@ export { loadSnakeCaseConfig } from "./config-keys.js";
48
51
  export { baseContext, environmentOf, outputFor, provide, secretInputOf, } from "./context.js";
49
52
  export { withDeadline } from "./deadline.js";
50
53
  export { DEFAULT_CONFIG, ensureDefaultConfig } from "./default-config.js";
51
- export { changesAuthority, changesAuthorityAt, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
52
- export { answerSchema, itemAnswer, itemOf, jsonlRecords, judgedAnswer, listOf, metaNow, printItem, renderAnswer, sealed, snakeKeys, snakeKeysKeeping, } from "./envelope.js";
54
+ export { changesAuthority, changesAuthorityAt, changesAuthorityNow, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
55
+ export { answerSchema, isBody, itemAnswer, itemOf, jsonlRecords, judgedAnswer, listOf, metaNow, printItem, renderAnswer, sealed, snakeKeys, snakeKeysKeeping, } from "./envelope.js";
53
56
  export { withAbort } from "./execution.js";
54
57
  export { askSetupQuestions, asksAtStart, LANGUAGES, setupAtStart, systemLanguage, } from "./first-run.js";
55
58
  export { checkGuide, checkStep, guideCommand, loadScenarios, MEMO_SCENARIOS, shellProblems, } from "./guide.js";
@@ -68,6 +71,7 @@ export { addMeetingPreparationCommand } from "./meeting-preparation-command.js";
68
71
  export { meetingPreparationInput, readMeetingPreparation, } from "./meeting-preparation-read.js";
69
72
  export { addMeetingProjectCandidatesCommand } from "./meeting-project-candidates-command.js";
70
73
  export { readMeetingProjectCandidates } from "./meeting-project-candidates-read.js";
74
+ export { meetingResultItem } from "./meeting-results.js";
71
75
  export { addMeetingSeriesInventoryCommand } from "./meeting-series-inventory-command.js";
72
76
  export { readMeetingSeriesInventory } from "./meeting-series-inventory-read.js";
73
77
  export { accountCommand } from "./messenger/account-command.js";
@@ -1,6 +1,7 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
2
  import { metaOf } from "@wirecat/cli-base/commands";
3
3
  import { ENTITIES } from "../entities/index.js";
4
+ import { answerEntitySchema, answerProjectionSchema } from "./answer-entity.js";
4
5
  const declaredEntity = (command) => {
5
6
  const output = command ? metaOf(command).output : undefined;
6
7
  return output && (output.view ? `${output.entity}.${output.view}` : output.entity);
@@ -37,8 +38,7 @@ export const answerFields = (command, resolve) => {
37
38
  const own = resolve?.(command);
38
39
  if (own !== undefined)
39
40
  return [...own];
40
- const name = declaredEntity(command);
41
- const schema = name === undefined ? undefined : ENTITIES[name];
41
+ const schema = answerProjectionSchema(command) ?? answerEntitySchema(command);
42
42
  return schemaFields(schema);
43
43
  };
44
44
  const PATHS = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*(,[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*)*$/;
@@ -1,5 +1,5 @@
1
1
  import { type BatchReport } from "@wirecat/cli-base";
2
- import type { Meta } from "@wirecat/cli-base/standards";
2
+ import { type Meta } from "@wirecat/cli-base/standards";
3
3
  import { Command } from "commander";
4
4
  import { type MeetingBatchReader, type MeetingPassageOutputFormat } from "../meetings/index.js";
5
5
  import { type Body } from "./envelope.js";
@@ -1,11 +1,16 @@
1
1
  import { BATCH_LIMITS, CliError, prepareBatch, runBatch, } from "@wirecat/cli-base";
2
2
  import { annotate } from "@wirecat/cli-base/commands";
3
+ import { errorObjectSchema } from "@wirecat/cli-base/standards";
3
4
  import { Command, Option } from "commander";
5
+ import * as v from "valibot";
6
+ import { ENTITIES } from "../entities/index.js";
4
7
  import { failureContext } from "../errors/reasons.js";
5
8
  import { createMeetingPassageCommand, createMeetingSearchCommand, meetingHitSearchRequest, meetingPassageRequest, meetingSearchArguments, meetingSearchMeta, } from "../meetings/cli/index.js";
6
9
  import { meetingHitsList, parseMeetingReference, } from "../meetings/index.js";
7
10
  import { formatMeetingEvidenceText, formatMeetingPassage } from "../services/meeting-passage-format.js";
8
- import { itemOf, listOf } from "./envelope.js";
11
+ import { answerEntity } from "./answer-entity.js";
12
+ import { destroysNothing } from "./effects.js";
13
+ import { answerSchema, itemOf, listOf } from "./envelope.js";
9
14
  const INDEX_BYTES = 4194304;
10
15
  const parse = (command, args) => {
11
16
  command
@@ -162,10 +167,23 @@ export const addMeetingBatchCommand = (program, deps) => {
162
167
  },
163
168
  }), report, format);
164
169
  });
165
- return annotate(command, {
170
+ destroysNothing(command);
171
+ annotate(command, {
166
172
  origin: "handwritten",
167
173
  partial: true,
168
174
  effects: { remote: "none", local: "write" },
169
175
  examples: [`${program.name()} batch requests.json --json`],
170
176
  });
177
+ return answerEntity(command, "meeting_batch_result", batchResult, { project: batchPayload });
171
178
  };
179
+ const batchPayload = v.union([ENTITIES.meeting_hit, ENTITIES.meeting_passage]);
180
+ const correlated = { id: v.string(), command: v.array(v.string()) };
181
+ const batchResult = v.union([
182
+ v.strictObject({ ...correlated, status: v.literal("ok"), answer: answerSchema(batchPayload), complete: v.boolean() }),
183
+ v.strictObject({
184
+ ...correlated,
185
+ status: v.picklist(["error", "not_run"]),
186
+ error: errorObjectSchema.entries.error,
187
+ complete: v.literal(false),
188
+ }),
189
+ ]);
@@ -31,7 +31,6 @@ export const addMeetingProjectCandidatesCommand = (program, deps) => {
31
31
  cursor: options.cursor,
32
32
  }, deps.signal()))), {
33
33
  origin: "handwritten",
34
- mcp: false,
35
34
  effects: LOCAL_READ,
36
35
  output: { entity: "meeting_project_candidates" },
37
36
  examples: [`${program.name()} meetings projects scan meeting:1/2 --json`],
@@ -0,0 +1,3 @@
1
+ import { MEETING_RESULT_ENTITIES } from "../meetings/index.js";
2
+ /** Store IDs stay numeric below the CLI; public receipts use the shared string IDs and validated wire fields. */
3
+ export declare const meetingResultItem: (entity: keyof typeof MEETING_RESULT_ENTITIES, value: unknown) => unknown;
@@ -0,0 +1,31 @@
1
+ import { CliError } from "@wirecat/cli-base";
2
+ import * as v from "valibot";
3
+ import { MEETING_RESULT_ENTITIES } from "../meetings/index.js";
4
+ import { snakeKeys } from "./envelope.js";
5
+ const ids = new Set([
6
+ "meeting_id",
7
+ "account_id",
8
+ "participant_id",
9
+ "event_id",
10
+ "previous_event_id",
11
+ "expected_event_id",
12
+ "next_transcript_id",
13
+ ]);
14
+ const publicValue = (value, key = "") => {
15
+ if (typeof value === "number" && ids.has(key))
16
+ return String(value);
17
+ if (Array.isArray(value))
18
+ return value.map((item) => publicValue(item, key === "target_account_ids" ? "account_id" : ""));
19
+ if (value && typeof value === "object")
20
+ return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, publicValue(item, name)]));
21
+ return value;
22
+ };
23
+ /** Store IDs stay numeric below the CLI; public receipts use the shared string IDs and validated wire fields. */
24
+ export const meetingResultItem = (entity, value) => {
25
+ const parsed = v.safeParse(MEETING_RESULT_ENTITIES[entity], publicValue(snakeKeys(value)));
26
+ if (!parsed.success) {
27
+ const applied = value && typeof value === "object" && "applied" in value && value.applied === true;
28
+ throw new CliError(applied ? "outcome_unknown" : "invalid_response", `the command returned an invalid ${entity} answer`);
29
+ }
30
+ return parsed.output;
31
+ };
@@ -31,7 +31,6 @@ export const addMeetingSeriesInventoryCommand = (program, deps) => {
31
31
  origin: "handwritten",
32
32
  effects: REMOTE_READ,
33
33
  offline: false,
34
- mcp: false,
35
34
  output: { entity: "meeting_series_inventory" },
36
35
  examples: [`${program.name()} meetings scheduled --json`],
37
36
  });
@@ -69,14 +69,8 @@ const updateCommand = (messenger) => {
69
69
  update.option("--remove-photo", "take its photo away; not with --photo");
70
70
  for (const key of keys) {
71
71
  const option = new Option(`--${SETTING_FLAGS[key][0]}`, SETTING_FLAGS[key][1]);
72
- if (key === "disappearingSeconds")
73
- option.conflicts("disappearTime");
74
72
  update.addOption(option);
75
73
  }
76
- if (keys.includes("disappearingSeconds"))
77
- update.addOption(new Option("--disappear-time <duration|off>", "compatibility alias for --disappear-after")
78
- .hideHelp()
79
- .conflicts("disappearAfter"));
80
74
  return update.action(async function (chat) {
81
75
  const context = messengerContext(this, messenger);
82
76
  const { title, description, photo, removePhoto, ...rest } = this.opts();
@@ -92,7 +86,7 @@ const updateCommand = (messenger) => {
92
86
  });
93
87
  };
94
88
  const linkCommand = (messenger) => {
95
- const link = new Command("link").description("a group's invite link");
89
+ const link = new Command("links").description("a group's invite link");
96
90
  annotate(link.command("show"), { output: { entity: "chat_invite" }, effects: REMOTE_READ })
97
91
  .description("the invite link, if you may see it")
98
92
  .argument("<chat>", messenger.chatArgument)
@@ -132,10 +126,13 @@ const linkCommand = (messenger) => {
132
126
  ].join(" ")));
133
127
  }));
134
128
  if (messenger.inviteLinkRevoke !== false)
135
- link.addCommand(annotate(new Command("revoke"), { output: { entity: "chat_invite_change" }, effects: REMOTE_WRITE })
129
+ link.addCommand(annotate(new Command("remove"), {
130
+ output: { entity: "chat_invite_change" },
131
+ effects: REMOTE_WRITE,
132
+ })
136
133
  .description("stop one link; for the group's own link, the answer is the new one")
137
134
  .argument("<chat>", messenger.chatArgument)
138
- .argument("<link>", "the link, as `chats link list` shows it")
135
+ .argument("<link>", "the link, as `chats links list` shows it")
139
136
  .action(async function (chat, link) {
140
137
  const context = messengerContext(this, messenger);
141
138
  renderItem(this, context, await context.withServices((services) => services.admin.revokeLink(chat, link)));
@@ -144,7 +141,7 @@ const linkCommand = (messenger) => {
144
141
  link.addCommand(annotate(new Command("update"), { output: { entity: "chat_invite_change" }, effects: REMOTE_WRITE })
145
142
  .description("change one of your invite links, the group's own one too")
146
143
  .argument("<chat>", messenger.chatArgument)
147
- .argument("<link>", "the link, as `chats link list` shows it")
144
+ .argument("<link>", "the link, as `chats links list` shows it")
148
145
  .option("--approval", "who joins by it asks first, and an admin lets them in; it then has no use limit")
149
146
  .option("--no-approval", "anyone with it joins at once")
150
147
  .option("--expire-time <time>", "it stops working then: 2026-09-25T09:00 (local time), or 30m, 2h, 7d from now; `never` takes the expiry away")
@@ -219,11 +216,14 @@ const requestsCommand = (messenger) => {
219
216
  }));
220
217
  const everyone = messenger.joinRequestsAll !== false;
221
218
  const byLink = everyone && messenger.joinRequestsByLink !== false;
222
- for (const [verb, accept, help] of [
223
- ["accept", true, "let them in; the group sees them join"],
224
- ["decline", false, "turn the request away"],
219
+ for (const [accept, help] of [
220
+ [true, "let them in; the group sees them join"],
221
+ [false, "turn the request away"],
225
222
  ]) {
226
- const answer = annotate(new Command(verb), { output: { entity: "chat_request_change" }, effects: REMOTE_WRITE })
223
+ const answer = annotate(new Command(accept ? "confirm" : "reject"), {
224
+ output: { entity: "chat_request_change" },
225
+ effects: REMOTE_WRITE,
226
+ })
227
227
  .description(help)
228
228
  .argument("<chat>", messenger.chatArgument)
229
229
  .argument(everyone ? "[person]" : "<person>", "who asked: an id from `chats requests list`");
@@ -38,7 +38,7 @@ export const storeCommand = (messenger) => {
38
38
  "copies delete": "messages_copy_1",
39
39
  decrypt: "./backup.enc --output ./restored.db",
40
40
  export: '"Book club" --output ./messages.jsonl',
41
- "gaps plan": '"Book club"',
41
+ "gaps show": '"Book club"',
42
42
  "gaps repair": '"Book club" --limit 100',
43
43
  info: "",
44
44
  "jobs cancel": "job-101",
@@ -47,7 +47,7 @@ export const storeCommand = (messenger) => {
47
47
  "jobs retry": "--failed",
48
48
  "jobs show": "",
49
49
  migrate: "",
50
- reindex: "",
50
+ rebuild: "",
51
51
  repair: "--dry-run",
52
52
  reset: "",
53
53
  restore: "./backup.db",
@@ -27,7 +27,7 @@ const count = (value) => {
27
27
  const line = ({ status, ref, attachment, name, chars }) => `${status} ${ref} #${attachment}${name ? ` ${name}` : ""}${chars === undefined ? "" : ` (${chars} characters)`}`;
28
28
  const summary = (run) => [
29
29
  `${run.extracted} extracted`,
30
- run.needsAgent ? `${run.needsAgent} for an agent to read (attachments text set)` : "",
30
+ run.needsAgent ? `${run.needsAgent} for an agent to read (attachments update)` : "",
31
31
  run.failed ? `${run.failed} unreadable` : "",
32
32
  run.unchanged ? `${run.unchanged} unchanged` : "",
33
33
  run.notDownloaded ? `${run.notDownloaded} not downloaded (--download)` : "",
@@ -172,12 +172,11 @@ const showCommand = (messenger) => annotate(new Command("show"), {
172
172
  stop.release();
173
173
  }
174
174
  });
175
- const textCommand = (messenger) => {
176
- const text = new Command("text").description("the text of one file, as an agent read it");
177
- readsStdin(annotate(text.command("set"), {
175
+ const textUpdateCommand = (messenger) => {
176
+ const update = readsStdin(annotate(new Command("update"), {
178
177
  output: { entity: "attachment_text_change" },
179
178
  effects: LOCAL_WRITE,
180
- examples: [`${messenger.app.command} personal attachments text set "Book club" 101 --text-file ./transcript.txt`],
179
+ examples: [`${messenger.app.command} personal attachments update "Book club" 101 --text-file ./transcript.txt`],
181
180
  }), {
182
181
  name: "text",
183
182
  description: "the text of the file",
@@ -190,7 +189,7 @@ const textCommand = (messenger) => {
190
189
  .addOption(ownerOnlyOption("--text-file <path>", "read the text from this file; - or none reads stdin"))
191
190
  .action(async function (chat, message) {
192
191
  const context = messengerContext(this, messenger);
193
- refuseLocalWrite(context, messenger.app.command, "attachments.text.set");
192
+ refuseLocalWrite(context, messenger.app.command, "attachments.update");
194
193
  const { attachment, textFile } = this.opts();
195
194
  const given = textFile === undefined || textFile === "-" ? await readAll(context.stdin) : readFileSync(textFile, "utf8");
196
195
  const done = await context.withServices((services) => services.attachments.setText({
@@ -201,7 +200,7 @@ const textCommand = (messenger) => {
201
200
  }));
202
201
  renderAnswer(this, context, itemOf(snakeKeys(done)), () => `${done.ref} #${done.attachment} ${done.chars} characters kept\n`);
203
202
  });
204
- return text;
203
+ return update;
205
204
  };
206
205
  /** Files of stored messages: what is in them, for `content:` in a search. Nothing here is sent. */
207
206
  export const attachmentsCommand = (messenger) => {
@@ -211,7 +210,7 @@ export const attachmentsCommand = (messenger) => {
211
210
  .addCommand(extractCommand(messenger))
212
211
  .addCommand(listCommand(messenger))
213
212
  .addCommand(showCommand(messenger))
214
- .addCommand(textCommand(messenger));
213
+ .addCommand(textUpdateCommand(messenger));
215
214
  addMediaArchiveCommands(attachments, messenger);
216
215
  return attachments;
217
216
  };
@@ -107,7 +107,7 @@ export const syncCommand = (messenger) => {
107
107
  if (prepare) {
108
108
  validateCatchUpBounds(preparation);
109
109
  refuseLocalWrite(context, messenger.app.command, "conversations.links");
110
- refuseLocalWrite(context, messenger.app.command, "conversations.embed");
110
+ refuseLocalWrite(context, messenger.app.command, "conversations.embeddings");
111
111
  }
112
112
  if (background) {
113
113
  const named = chat ?? ALL_CHATS;
@@ -182,19 +182,19 @@ export const chatShown = (account, card) => {
182
182
  };
183
183
  /** The lowest score `score>=n` asks for; the audit's own floor when the query names none. */
184
184
  export const scoreFloor = (ast) => {
185
- const term = nativeTerms(ast, "chats members audit").get("score");
185
+ const term = nativeTerms(ast, "chats members check").get("score");
186
186
  if (!term)
187
187
  return AUDIT_MIN_SCORE;
188
188
  const upper = term.operator === "range" ? (term.upper ?? "*") : term.value;
189
189
  if (term.operator !== "range" || upper !== "*")
190
190
  queryError("query.unsupported-operator", term.span, "score takes a lower bound: score>=3", {
191
- command: "chats members audit",
191
+ command: "chats members check",
192
192
  guide: LIST_QUERY_GUIDE,
193
193
  });
194
194
  const floor = Number(term.value);
195
195
  return Math.ceil(term.lower_inclusive === false ? floor + 1 : floor);
196
196
  };
197
- export const auditAnswer = (audit) => wholeList("chats members audit", audit.items.map(memberAnswer), {
197
+ export const auditAnswer = (audit) => wholeList("chats members check", audit.items.map(memberAnswer), {
198
198
  ...(audit.more ? { meta: { truncated: true } } : {}),
199
199
  ...(audit.completeness && audit.completeness.state !== "complete"
200
200
  ? {
@@ -45,16 +45,16 @@ export const membersHistory = async (services, chat, query) => {
45
45
  });
46
46
  };
47
47
  export const membersAudit = async (services, chat, query, options) => {
48
- const minScore = scoreFloor(listQuery(typedQuery(query), AUDIT_QUERY, "chats members audit"));
48
+ const minScore = scoreFloor(listQuery(typedQuery(query), AUDIT_QUERY, "chats members check"));
49
49
  const audit = await services.chats.audit(chat, { ...options, minScore });
50
50
  return { audit, body: auditAnswer(audit) };
51
51
  };
52
52
  /** The source takes a count but no offset, so page n reads n pages and shows the last. */
53
53
  export const inviteLinks = async (services, chat, query, { limit, page }) => {
54
- const terms = nativeTerms(listQuery(typedQuery(query), LINKS_QUERY, "chats link list"), "chats link list");
54
+ const terms = nativeTerms(listQuery(typedQuery(query), LINKS_QUERY, "chats links list"), "chats links list");
55
55
  const revoked = terms.get("revoked")?.value.toLowerCase() === "true";
56
56
  const found = await services.admin.links(chat, { limit: limit * page, revoked });
57
- return listOf("chats link list", {
57
+ return listOf("chats links list", {
58
58
  items: found.items.slice((page - 1) * limit).map(inviteLinkAnswer),
59
59
  limit,
60
60
  has_more: found.hasMore,