@wirecat/cli-core 0.408.0 → 0.410.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ 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
+ ## 0.410.0 — 24.10.2026
9
+
10
+ ### Added
11
+
12
+ - `buildDoctorReport`, `doctorReportFileName` and their report types are public through `/cli`.
13
+ Consumers can reuse run selection, identifier labelling and home-path redaction while retaining
14
+ typed diagnostic payloads and optional technical context. Existing reports keep their shape
15
+ when context is omitted. `eventFields: "recorded"` retains allowlisted recorded technical
16
+ fields for consumers that already include them; the default report projection is unchanged.
17
+
18
+ ### Fixed
19
+
20
+ - **Meeting search continuation arguments match the generated MCP schema.** Stored numeric selector IDs are
21
+ serialized as strings in replay arguments, so an agent can pass the returned next step to the shared read tool
22
+ without converting IDs. Validated search requests still use numeric store IDs.
23
+
24
+ - Media archives skip call events alongside service events and keyboards. A message containing
25
+ both a file and a call event now archives the file and verifies its checksum; call-only
26
+ messages make no download request. Unknown attachment kinds still fail rather than being
27
+ silently dropped.
28
+
29
+ ## 0.409.0 — 24.10.2026
30
+
31
+ ### Added
32
+
33
+ - **Shared lists declare typed queries, including bots, schedules, forum topics, calls and stickers.** Stored bot chats, recipients, send history,
34
+ profiles and schedules filter at their native readers; forum title terms go to the provider. Message predicates
35
+ require `--offline` and run in SQLite before the limit, reporting interpreted time bounds. Provider lists that
36
+ accept no filters refuse terms before connecting, instead of filtering an incomplete response. Existing empty
37
+ queries keep their previous behavior. Shared list-result contracts include the template schema for provider CLIs.
38
+
8
39
  ## 0.408.0 — 24.10.2026
9
40
 
10
41
  ### Fixed
@@ -75,7 +75,7 @@ export declare const scheduledRuns: (state: string) => {
75
75
  job: string;
76
76
  last: LastRun | undefined;
77
77
  }[];
78
- export declare const listSchedules: (state: string) => Schedule[];
78
+ export declare const listSchedules: (state: string, filter?: Partial<Pick<Schedule, "name" | "kind">>) => Schedule[];
79
79
  export declare const describeWhen: (when: When) => string;
80
80
  /** How one operating system starts `argv` at the schedule's times. Every timer runs the same thing: `<cli> schedule exec <file>`. */
81
81
  export interface Timer {
@@ -98,11 +98,13 @@ export const scheduledRuns = (state) => {
98
98
  return [];
99
99
  }
100
100
  };
101
- export const listSchedules = (state) => existsSync(schedulesDir(state))
101
+ export const listSchedules = (state, filter = {}) => existsSync(schedulesDir(state))
102
102
  ? readdirSync(schedulesDir(state))
103
103
  .map((name) => scheduleFile(state, name))
104
104
  .filter((file) => existsSync(file))
105
105
  .map(readSchedule)
106
+ .filter((schedule) => (filter.name === undefined || schedule.name === filter.name) &&
107
+ (filter.kind === undefined || schedule.kind === filter.kind))
106
108
  .sort((a, b) => a.name.localeCompare(b.name))
107
109
  : [];
108
110
  export const describeWhen = (when) => "every" in when
@@ -6,10 +6,12 @@ import { guardedWrite } from "../../sends/guarded.js";
6
6
  import { newOperationId } from "../../sends/send-id.js";
7
7
  import { REMOTE_READ, REMOTE_WRITE } from "../effects.js";
8
8
  import { renderAnswer, snakeKeys } from "../envelope.js";
9
+ import { listQuery, typedQuery, withQuery } from "../list-query.js";
9
10
  import { rightsOf } from "../messenger/admin-commands.js";
10
11
  import { renderItem, wholeList } from "../messenger/chat-answers.js";
11
12
  import { botContext, online } from "./context.js";
12
13
  import { botExamples } from "./examples.js";
14
+ import { BOT_ADMINS_QUERY } from "./list-queries.js";
13
15
  import { botCan } from "./messages.js";
14
16
  const CHAT = "a chat id, or the title of a chat this bot has seen";
15
17
  const PERSON = "the person's user id";
@@ -24,10 +26,10 @@ const personOf = (typed) => {
24
26
  export const botAdminsCommand = (bot) => {
25
27
  const offered = bot.adminRights ?? ADMIN_RIGHTS;
26
28
  const command = new Command("admins").description("the admins of a chat the bot is an admin in");
27
- annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "chats admins list Team") })
29
+ withQuery(annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "chats admins list Team") })
28
30
  .description("the chat's admins and what each may do")
29
- .argument("<chat>", CHAT)
30
- .action(async function (chat) {
31
+ .argument("<chat>", CHAT), BOT_ADMINS_QUERY).action(async function (chat, words) {
32
+ listQuery(typedQuery(words), BOT_ADMINS_QUERY, "bot chats admins list");
31
33
  const context = online(botContext(this, bot), this);
32
34
  const ref = context.chatRef(chat);
33
35
  await context.run(async (events) => {
@@ -6,10 +6,14 @@ import { guardedWrite } from "../../sends/guarded.js";
6
6
  import { newOperationId } from "../../sends/send-id.js";
7
7
  import { grantsAuthority, LOCAL_READ, LOCAL_WRITE, REMOTE_READ, REMOTE_WRITE } from "../effects.js";
8
8
  import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
9
+ import { withQuery } from "../list-query.js";
9
10
  import { renderItem, wholeList } from "../messenger/chat-answers.js";
11
+ import { RECIPIENTS_QUERY, recipientFilter } from "../messenger/recipients-query.js";
12
+ import { SENDS_QUERY, sendFilter } from "../messenger/sends-query.js";
10
13
  import { botAdminsCommand, botMembersCommand } from "./admins.js";
11
14
  import { botContext, online } from "./context.js";
12
15
  import { botExamples } from "./examples.js";
16
+ import { BOT_CHATS_QUERY, BOT_PROFILES_QUERY, botChatFilter, botProfileName } from "./list-queries.js";
13
17
  import { botMcpCommand } from "./mcp.js";
14
18
  import { botCan, botIdOf, botMessagesCommand } from "./messages.js";
15
19
  import { botModerateCommand, botRulesCommand } from "./moderation.js";
@@ -114,11 +118,12 @@ const meCommand = (bot) => annotate(new Command("me"), { effects: REMOTE_READ, e
114
118
  }
115
119
  });
116
120
  });
117
- const listCommand = (bot, tokenVariable) => annotate(new Command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "list", "list --check") })
121
+ const listCommand = (bot, tokenVariable) => withQuery(annotate(new Command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "list", "list --check") }), BOT_PROFILES_QUERY)
118
122
  .description(`every name on this machine that has a bot token; --check asks ${bot.name ?? "the messenger"} which bot each is`)
119
123
  .summary("every bot profile on this machine; --check asks which bot each is")
120
124
  .option("--check", "ask the messenger who each bot is, with its token")
121
- .action(async function () {
125
+ .action(async function (words) {
126
+ const wanted = botProfileName(words);
122
127
  const context = botContext(this, bot);
123
128
  const check = this.opts().check === true;
124
129
  if (check)
@@ -132,6 +137,8 @@ const listCommand = (bot, tokenVariable) => annotate(new Command("list"), { effe
132
137
  }
133
138
  const rows = [];
134
139
  for (const name of names) {
140
+ if (wanted !== undefined && name !== wanted)
141
+ continue;
135
142
  const tokens = bot.tokenStore?.(this, name) ??
136
143
  new BotTokenStore({
137
144
  app: bot.app,
@@ -161,11 +168,12 @@ const recipientsCommand = (bot) => {
161
168
  const command = new Command("recipients")
162
169
  .description("the chats this bot may write to; with no list, every chat — `clear` removes the list")
163
170
  .summary("the chats this bot may write to; with no list, every chat");
164
- annotate(command.command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "recipients list") })
171
+ withQuery(annotate(command.command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "recipients list") }), RECIPIENTS_QUERY)
165
172
  .description("the chats on the list, or nothing when there is no list")
166
- .action(async function () {
173
+ .action(async function (words) {
174
+ const filter = recipientFilter(words, "bot recipients list");
167
175
  const context = botContext(this, bot);
168
- await context.run(async () => renderAnswer(this, context, wholeList("bot recipients list", (context.recipients().read() ?? []).map(snakeKeys))));
176
+ await context.run(async () => renderAnswer(this, context, wholeList("bot recipients list", context.recipients().list(filter).items.map(snakeKeys))));
169
177
  });
170
178
  grantsAuthority(annotate(command.command("add"), {
171
179
  effects: LOCAL_WRITE,
@@ -203,21 +211,23 @@ const recipientsCommand = (bot) => {
203
211
  const sendsCommand = (bot) => new Command("sends")
204
212
  .description("what this bot sent, edited and deleted from this machine — ids and outcomes, never text")
205
213
  .summary("what this bot sent, edited and deleted from here — never the text")
206
- .addCommand(annotate(new Command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "sends list") })
214
+ .addCommand(withQuery(annotate(new Command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "sends list") }), SENDS_QUERY)
207
215
  .description("every send, edit and delete this bot made from this machine, with its outcome")
208
- .action(async function () {
216
+ .action(async function (words) {
217
+ const filter = sendFilter(words, "bot sends list");
209
218
  const context = botContext(this, bot);
210
- await context.run(async () => renderAnswer(this, context, wholeList("bot sends list", context.journal().entries().map(snakeKeys))));
219
+ await context.run(async () => renderAnswer(this, context, wholeList("bot sends list", context.journal().entries(filter).map(snakeKeys))));
211
220
  }));
212
221
  const chatsCommand = (bot) => {
213
222
  const command = new Command("chats")
214
223
  .description(`the chats this bot is in — ${bot.name ?? "the messenger"} gives a bot no list of them, so \`list\` shows the ones it has seen`)
215
224
  .summary("the chats this bot is in, and what it does there");
216
- annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "chats list") })
225
+ withQuery(annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "chats list") }), BOT_CHATS_QUERY)
217
226
  .description(`chats this bot has seen on this machine — not a complete list from ${bot.name ?? "the messenger"}`)
218
- .action(async function () {
227
+ .action(async function (words) {
228
+ const filter = botChatFilter(words);
219
229
  const context = botContext(this, bot);
220
- await context.run(async () => renderAnswer(this, context, wholeList("bot chats list", context.registry.list().map(snakeKeys))));
230
+ await context.run(async () => renderAnswer(this, context, wholeList("bot chats list", context.registry.list(filter).map(snakeKeys))));
221
231
  });
222
232
  annotate(command.command("show"), { effects: REMOTE_READ, examples: botExamples(bot, "chats show Team") })
223
233
  .description(`one chat from ${bot.name ?? "the messenger"}, and remember it`)
@@ -0,0 +1,27 @@
1
+ import { type QueryRegistry } from "@wirecat/cli-base/query";
2
+ import { type QueryWords } from "../list-query.js";
3
+ import type { SeenChat } from "./registry.js";
4
+ export declare const BOT_PROFILES_QUERY: QueryRegistry;
5
+ export declare const botProfileName: (words: QueryWords) => string | undefined;
6
+ export declare const BOT_CHATS_QUERY: QueryRegistry;
7
+ export declare const botChatFilter: (words: QueryWords) => Partial<Pick<SeenChat, "id" | "title" | "kind">>;
8
+ export declare const BOT_MESSAGES_QUERY: QueryRegistry;
9
+ export declare const botMessageWindow: (words: QueryWords) => {
10
+ window: {
11
+ before?: string | undefined;
12
+ since?: string | undefined;
13
+ threadId?: string | undefined;
14
+ outgoing?: boolean | undefined;
15
+ starred?: boolean | undefined;
16
+ };
17
+ meta: {
18
+ timezone: string;
19
+ window: {
20
+ since?: string;
21
+ until?: string;
22
+ };
23
+ } | undefined;
24
+ };
25
+ export declare const BOT_ADMINS_QUERY: QueryRegistry;
26
+ export declare const BOT_MENU_QUERY: QueryRegistry;
27
+ export declare const BOT_WEBHOOKS_QUERY: QueryRegistry;
@@ -0,0 +1,83 @@
1
+ import { queryError, queryFieldsOf } from "@wirecat/cli-base/query";
2
+ import { botAdmin, botMenuEntry, botProfile, botSeenChat, botWebhook, message } from "../../entities/index.js";
3
+ import { listQuery, nativeTerms, queryTerms, timeBounds, typedQuery, unfilteredQuery, } from "../list-query.js";
4
+ const termsOnly = (registry) => ({
5
+ ...registry,
6
+ fields: registry.fields.map((field) => field.native
7
+ ? {
8
+ ...field,
9
+ operators: field.operators.filter((operator) => operator === "term" || operator === "phrase"),
10
+ }
11
+ : field),
12
+ });
13
+ export const BOT_PROFILES_QUERY = termsOnly({
14
+ entity: "bot_profile",
15
+ backend: "native",
16
+ fields: queryFieldsOf(botProfile, { native: ["name"], examples: { name: "name:sales" } }),
17
+ });
18
+ export const botProfileName = (words) => queryTerms(words, BOT_PROFILES_QUERY, "bot list").get("name");
19
+ export const BOT_CHATS_QUERY = termsOnly({
20
+ entity: "bot_seen_chat",
21
+ backend: "native",
22
+ fields: queryFieldsOf(botSeenChat, {
23
+ native: ["id", "title", "kind"],
24
+ examples: { id: "id:7", title: 'title:"Book club"', kind: "kind:group" },
25
+ }),
26
+ });
27
+ export const botChatFilter = (words) => {
28
+ const terms = queryTerms(words, BOT_CHATS_QUERY, "bot chats list");
29
+ const id = terms.get("id"), title = terms.get("title");
30
+ const kind = botSeenChat.entries.kind.wrapped.options.find((value) => value === terms.get("kind"));
31
+ return {
32
+ ...(id === undefined ? {} : { id }),
33
+ ...(title === undefined ? {} : { title }),
34
+ ...(kind === undefined ? {} : { kind }),
35
+ };
36
+ };
37
+ export const BOT_MESSAGES_QUERY = {
38
+ entity: "message",
39
+ backend: "native",
40
+ fields: queryFieldsOf(message, {
41
+ native: ["id", "timestamp", "thread_id", "outgoing", "starred"],
42
+ examples: {
43
+ id: "id<42",
44
+ timestamp: "timestamp>2026-10-01",
45
+ thread_id: "thread_id:12",
46
+ outgoing: "outgoing:false",
47
+ starred: "starred:true",
48
+ },
49
+ }).map((field) => {
50
+ if (field.name === "id" || field.name === "timestamp")
51
+ return { ...field, operators: ["range"] };
52
+ return field.native ? { ...field, operators: ["term"] } : field;
53
+ }),
54
+ };
55
+ export const botMessageWindow = (words) => {
56
+ const command = "bot messages list";
57
+ const terms = nativeTerms(listQuery(typedQuery(words), BOT_MESSAGES_QUERY, command), command);
58
+ const id = terms.get("id");
59
+ if (id && (id.value !== "*" || !id.upper || id.upper === "*" || id.upper_inclusive !== false))
60
+ queryError("query.unsupported-operator", id.span, "id takes an exclusive upper bound here: id<42", { command });
61
+ const timestamp = terms.get("timestamp");
62
+ const bounds = timeBounds(timestamp);
63
+ if (timestamp && (bounds.since === undefined || bounds.until !== undefined))
64
+ queryError("query.unsupported-operator", timestamp.span, "timestamp takes a lower bound here: timestamp>7d", {
65
+ command,
66
+ });
67
+ const topic = terms.get("thread_id")?.value;
68
+ const outgoing = terms.get("outgoing")?.value.toLowerCase();
69
+ const starred = terms.get("starred")?.value.toLowerCase();
70
+ return {
71
+ window: {
72
+ ...(id?.upper === undefined ? {} : { before: id.upper }),
73
+ ...(bounds.since === undefined ? {} : { since: new Date(bounds.since).toISOString() }),
74
+ ...(topic === undefined ? {} : { threadId: topic }),
75
+ ...(outgoing === undefined ? {} : { outgoing: outgoing === "true" }),
76
+ ...(starred === undefined ? {} : { starred: starred === "true" }),
77
+ },
78
+ meta: bounds.meta,
79
+ };
80
+ };
81
+ export const BOT_ADMINS_QUERY = unfilteredQuery("bot_admin", botAdmin);
82
+ export const BOT_MENU_QUERY = unfilteredQuery("bot_menu_entry", botMenuEntry);
83
+ export const BOT_WEBHOOKS_QUERY = unfilteredQuery("bot_webhook", botWebhook);
@@ -9,12 +9,14 @@ import { readAttachments } from "../../sends/upload.js";
9
9
  import { environmentOf } from "../context.js";
10
10
  import { ownerOnlyOption, REMOTE_READ, REMOTE_WRITE } from "../effects.js";
11
11
  import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
12
+ import { typedQuery, withQuery } from "../list-query.js";
12
13
  import { wholeList } from "../messenger/chat-answers.js";
13
14
  import { messageItem } from "../messenger/message-items.js";
14
15
  import { readAll } from "../messenger/stdin.js";
15
16
  import { positiveCount } from "../paging.js";
16
17
  import { botContext } from "./context.js";
17
18
  import { botExamples } from "./examples.js";
19
+ import { BOT_MESSAGES_QUERY, botMessageWindow } from "./list-queries.js";
18
20
  /** The adapter's `method`, or a refusal naming what this messenger's bot cannot do. */
19
21
  export const botCan = (adapter, method, bot, what) => {
20
22
  const found = adapter[method];
@@ -32,10 +34,10 @@ export const botIdOf = async (context, adapter) => {
32
34
  context.registry.rememberBot(id);
33
35
  return id;
34
36
  };
35
- const show = (command, context, bot, botId, messages, one = false) => {
37
+ const show = (command, context, bot, botId, messages, one = false, meta) => {
36
38
  const reader = context.copy.accountOf(botId);
37
39
  const items = messages.map((message) => messageItem(message, reader));
38
- renderAnswer(command, context, one && items[0] ? itemOf(items[0]) : wholeList("bot messages list", items), () => renderMessages(messages, {
40
+ renderAnswer(command, context, one && items[0] ? itemOf(items[0]) : { ...wholeList("bot messages list", items), ...(meta ? { meta } : {}) }, () => renderMessages(messages, {
39
41
  color: context.color,
40
42
  verbosity: context.settings.detail,
41
43
  senderColors: context.settings.senderColors,
@@ -124,33 +126,37 @@ const sendCommand = (bot) => annotate(new Command("send"), {
124
126
  renderAnswer(this, context, written(context, botId, { operationId }, message));
125
127
  });
126
128
  });
127
- const listCommand = (bot) => annotate(new Command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "messages list Team --limit 20") })
129
+ const listCommand = (bot) => withQuery(annotate(new Command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "messages list Team --limit 20") })
128
130
  .description(`the latest messages in a chat; where ${bot.name ?? "the messenger"} gives a bot no history, and with --offline, ` +
129
131
  "the ones this bot has seen on this machine")
130
132
  .summary("the latest messages in a chat")
131
- .argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
133
+ .argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen"), BOT_MESSAGES_QUERY)
134
+ .addHelpText("after", "\nQueries filter the stored copy before limiting results; add --offline. The Bot API does not accept these filters.")
132
135
  .option("--limit <n>", "how many, the newest", positiveCount("--limit"))
133
- .action(async function (chat) {
136
+ .action(async function (chat, words) {
137
+ const narrowed = botMessageWindow(words);
134
138
  const context = botContext(this, bot);
139
+ if (typedQuery(words).trim() && !context.settings.offline)
140
+ throw new CliError("validation_error", "bot message queries filter the local copy; add --offline");
135
141
  const ref = context.chatRef(chat);
136
142
  const limit = this.opts().limit ?? context.settings.limit;
137
143
  await context.run(async (events) => {
138
144
  const fromCopy = async (botId) => {
139
- const page = await context.copy.read((store) => store.messages.messages(context.copy.accountOf(botId), ref, { limit }));
145
+ const page = await context.copy.read((store) => store.messages.messages(context.copy.accountOf(botId), ref, { limit, ...narrowed.window }));
140
146
  return page.items;
141
147
  };
142
148
  if (context.settings.offline) {
143
149
  const botId = context.registry.botId();
144
150
  if (!botId)
145
151
  throw nothingKept(context);
146
- show(this, context, bot, botId, await fromCopy(botId));
152
+ show(this, context, bot, botId, await fromCopy(botId), false, narrowed.meta);
147
153
  return;
148
154
  }
149
155
  const adapter = await context.authenticated({ events });
150
156
  const botId = await botIdOf(context, adapter);
151
157
  if (!adapter.history) {
152
158
  context.renderer.note(`${bot.name ?? "the messenger"} gives a bot no history: these are the messages it kept`);
153
- show(this, context, bot, botId, await fromCopy(botId));
159
+ show(this, context, bot, botId, await fromCopy(botId), false, narrowed.meta);
154
160
  return;
155
161
  }
156
162
  const messages = await adapter.history(ref, { limit });
@@ -24,7 +24,7 @@ export declare const botFiles: (app: AppIdentity, profile: string, env?: NodeJS.
24
24
  export declare class ChatRegistry {
25
25
  #private;
26
26
  constructor(app: AppIdentity, profile: string, env?: NodeJS.ProcessEnv);
27
- list(): SeenChat[];
27
+ list(filter?: Partial<Pick<SeenChat, "id" | "title" | "kind">>): SeenChat[];
28
28
  /** The bot's own user id, once any command has learned it — the key its messages are stored under. */
29
29
  botId(): string | undefined;
30
30
  rememberBot(id: string): void;
@@ -26,9 +26,11 @@ export class ChatRegistry {
26
26
  constructor(app, profile, env = process.env) {
27
27
  this.#path = botFiles(app, profile, env).registry;
28
28
  }
29
- list() {
29
+ list(filter = {}) {
30
30
  const { chats } = this.#read();
31
- return Array.isArray(chats) ? chats : [];
31
+ return (Array.isArray(chats) ? chats : []).filter((chat) => (filter.id === undefined || chat.id === filter.id) &&
32
+ (filter.kind === undefined || chat.kind === filter.kind) &&
33
+ (filter.title === undefined || chat.title?.toLocaleLowerCase() === filter.title?.toLocaleLowerCase()));
32
34
  }
33
35
  /** The bot's own user id, once any command has learned it — the key its messages are stored under. */
34
36
  botId() {
@@ -5,9 +5,11 @@ import { guardedWrite } from "../../sends/guarded.js";
5
5
  import { newOperationId } from "../../sends/send-id.js";
6
6
  import { REMOTE_READ, REMOTE_WRITE } from "../effects.js";
7
7
  import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
8
+ import { listQuery, typedQuery, withQuery } from "../list-query.js";
8
9
  import { wholeList } from "../messenger/chat-answers.js";
9
10
  import { botContext, online } from "./context.js";
10
11
  import { botExamples } from "./examples.js";
12
+ import { BOT_MENU_QUERY, BOT_WEBHOOKS_QUERY } from "./list-queries.js";
11
13
  import { botCan } from "./messages.js";
12
14
  import { botFiles } from "./registry.js";
13
15
  import { PressLog } from "./updates.js";
@@ -31,9 +33,10 @@ const botWrite = (context, key, write) => guardedWrite(context.guard(), { operat
31
33
  /** `bot commands`: the menu people see when they type `/`. */
32
34
  export const botMenuCommand = (bot) => {
33
35
  const command = new Command("commands").description("the bot's command menu — what people see after /");
34
- annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "commands list") })
36
+ withQuery(annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "commands list") }), BOT_MENU_QUERY)
35
37
  .description("the commands in the menu now")
36
- .action(async function () {
38
+ .action(async function (words) {
39
+ listQuery(typedQuery(words), BOT_MENU_QUERY, "bot commands list");
37
40
  const context = online(botContext(this, bot), this);
38
41
  await context.run(async (events) => {
39
42
  const adapter = await context.authenticated({ events });
@@ -111,9 +114,10 @@ export const botWebhooksCommand = (bot) => {
111
114
  const command = new Command("webhooks")
112
115
  .description("where the messenger pushes this bot's updates — while one is set, `bot watch` gets nothing")
113
116
  .summary("where the messenger pushes this bot's updates");
114
- annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "webhooks list") })
117
+ withQuery(annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "webhooks list") }), BOT_WEBHOOKS_QUERY)
115
118
  .description("the webhooks this bot has")
116
- .action(async function () {
119
+ .action(async function (words) {
120
+ listQuery(typedQuery(words), BOT_WEBHOOKS_QUERY, "bot webhooks list");
117
121
  const context = online(botContext(this, bot), this);
118
122
  await context.run(async (events) => {
119
123
  const adapter = await context.authenticated({ events });
@@ -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 { botTemplate } from "../entities/list-results.js";
3
4
  export { syncProgress } from "../entities/store-records.js";
4
5
  export { isCliFailure, isCommanderFailure } from "../errors/failures.js";
5
6
  export { type AppErrors, failureContext } from "../errors/reasons.js";
@@ -111,6 +112,7 @@ export { type ModeProblem, type PrivateFiles, privateFiles, withSqliteSidecars }
111
112
  export { reactionsCommand } from "./messenger/reactions-command.js";
112
113
  export { callsCommand, stickersCommand } from "./messenger/records-command.js";
113
114
  export { repliesCommand } from "./messenger/replies-command.js";
115
+ export { buildReport as buildDoctorReport, type Report as DoctorReport, type ReportContext as DoctorReportContext, reportFileName as doctorReportFileName, } from "./messenger/report.js";
114
116
  export { reviewCommand } from "./messenger/review.js";
115
117
  export { scheduleCommand } from "./messenger/schedule-command.js";
116
118
  export { allAnswer, allHitItem, type HitItem, type MessageHitItem, messageHitItem, type NoteHitItem, noteHitItem, } from "./messenger/search-answers.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 { botTemplate } from "../entities/list-results.js";
3
4
  export { syncProgress } from "../entities/store-records.js";
4
5
  export { isCliFailure, isCommanderFailure } from "../errors/failures.js";
5
6
  export { failureContext } from "../errors/reasons.js";
@@ -105,6 +106,7 @@ export { privateFiles, withSqliteSidecars } from "./messenger/private-files.js";
105
106
  export { reactionsCommand } from "./messenger/reactions-command.js";
106
107
  export { callsCommand, stickersCommand } from "./messenger/records-command.js";
107
108
  export { repliesCommand } from "./messenger/replies-command.js";
109
+ export { buildReport as buildDoctorReport, reportFileName as doctorReportFileName, } from "./messenger/report.js";
108
110
  export { reviewCommand } from "./messenger/review.js";
109
111
  export { scheduleCommand } from "./messenger/schedule-command.js";
110
112
  export { allAnswer, allHitItem, messageHitItem, noteHitItem, } from "./messenger/search-answers.js";
@@ -0,0 +1,9 @@
1
+ import { type QueryRegistry } from "@wirecat/cli-base/query";
2
+ import type { Schedule } from "../../background/schedules.js";
3
+ import { type QueryWords } from "../list-query.js";
4
+ export declare const SCHEDULES_QUERY: QueryRegistry;
5
+ export declare const scheduleFilter: (words: QueryWords) => Partial<Pick<Schedule, "name" | "kind">>;
6
+ export declare const TOPICS_QUERY: QueryRegistry;
7
+ export declare const topicTitle: (words: QueryWords) => string | undefined;
8
+ export declare const CALLS_QUERY: QueryRegistry;
9
+ export declare const STICKERS_QUERY: QueryRegistry;
@@ -0,0 +1,30 @@
1
+ import { queryFieldsOf } from "@wirecat/cli-base/query";
2
+ import { callRecord, scheduledJob, stickerInventory, topic } from "../../entities/index.js";
3
+ import { queryTerms, unfilteredQuery } from "../list-query.js";
4
+ const termsOnly = (registry) => ({
5
+ ...registry,
6
+ fields: registry.fields.map((field) => field.native
7
+ ? { ...field, operators: field.operators.filter((operator) => operator === "term" || operator === "phrase") }
8
+ : field),
9
+ });
10
+ export const SCHEDULES_QUERY = termsOnly({
11
+ entity: "scheduled_job",
12
+ backend: "native",
13
+ fields: queryFieldsOf(scheduledJob, {
14
+ native: ["name", "kind"],
15
+ examples: { name: "name:daily", kind: "kind:command" },
16
+ }),
17
+ });
18
+ export const scheduleFilter = (words) => {
19
+ const terms = queryTerms(words, SCHEDULES_QUERY, "schedule list");
20
+ const name = terms.get("name"), kind = terms.get("kind");
21
+ return { ...(name === undefined ? {} : { name }), ...(kind === "agent" || kind === "command" ? { kind } : {}) };
22
+ };
23
+ export const TOPICS_QUERY = termsOnly({
24
+ entity: "topic",
25
+ backend: "native",
26
+ fields: queryFieldsOf(topic, { native: ["title"], examples: { title: 'title:"Book club"' } }),
27
+ });
28
+ export const topicTitle = (words) => queryTerms(words, TOPICS_QUERY, "topics list").get("title");
29
+ export const CALLS_QUERY = unfilteredQuery("call_record", callRecord);
30
+ export const STICKERS_QUERY = unfilteredQuery("sticker_inventory", stickerInventory);
@@ -2,4 +2,4 @@ import { type QueryRegistry } from "@wirecat/cli-base/query";
2
2
  import type { RecipientFilter } from "../../sends/recipients.js";
3
3
  import { type QueryWords } from "../list-query.js";
4
4
  export declare const RECIPIENTS_QUERY: QueryRegistry;
5
- export declare const recipientFilter: (words: QueryWords) => RecipientFilter;
5
+ export declare const recipientFilter: (words: QueryWords, command?: string) => RecipientFilter;
@@ -11,8 +11,8 @@ export const RECIPIENTS_QUERY = {
11
11
  ? { ...field, operators: field.operators.filter((operator) => operator === "term" || operator === "phrase") }
12
12
  : field),
13
13
  };
14
- export const recipientFilter = (words) => {
15
- const terms = queryTerms(words, RECIPIENTS_QUERY, "recipients list");
14
+ export const recipientFilter = (words, command = "recipients list") => {
15
+ const terms = queryTerms(words, RECIPIENTS_QUERY, command);
16
16
  const id = terms.get("id"), title = terms.get("title");
17
17
  return { ...(id === undefined ? {} : { id }), ...(title === undefined ? {} : { title }) };
18
18
  };
@@ -6,8 +6,10 @@ import { sendTime } from "../../domain/send-time.js";
6
6
  import { capability } from "../../ports/messenger.js";
7
7
  import { ownerOnlyOption, REMOTE_READ, REMOTE_WRITE } from "../effects.js";
8
8
  import { itemOf, listOf, renderAnswer, snakeKeys } from "../envelope.js";
9
+ import { listQuery, typedQuery, withQuery } from "../list-query.js";
9
10
  import { positiveCount } from "../paging.js";
10
11
  import { messengerContext } from "./context.js";
12
+ import { CALLS_QUERY, STICKERS_QUERY } from "./list-result-queries.js";
11
13
  const kindsOf = (typed) => {
12
14
  const kinds = typed === undefined ? [...MEDIA_KINDS] : typed.split(",").map((kind) => kind.trim());
13
15
  for (const kind of kinds) {
@@ -49,10 +51,14 @@ export const mediaCommand = (messenger) => annotate(new Command("media"), { effe
49
51
  /** `stickers list` — the sets the account added, or one set's stickers with the ids `messages send --sticker` takes. */
50
52
  export const stickersCommand = (messenger) => {
51
53
  const stickers = new Command("stickers").description("the stickers the account has added");
52
- annotate(stickers.command("list"), { effects: REMOTE_READ })
54
+ withQuery(annotate(stickers.command("list"), {
55
+ effects: REMOTE_READ,
56
+ examples: [`${messenger.app.command} personal stickers list`],
57
+ }), STICKERS_QUERY)
53
58
  .description("sticker sets, or with --set the stickers in one; reading changes nothing")
54
59
  .option("--set <id>", "the stickers in this set")
55
- .action(async function () {
60
+ .action(async function (words) {
61
+ listQuery(typedQuery(words), STICKERS_QUERY, "stickers list");
56
62
  const context = messengerContext(this, messenger);
57
63
  const { set } = this.opts();
58
64
  const items = await context.withMessenger((adapter) => set === undefined
@@ -69,10 +75,14 @@ export const stickersCommand = (messenger) => {
69
75
  /** `calls list` — the account's call history, newest first. */
70
76
  export const callsCommand = (messenger) => {
71
77
  const calls = new Command("calls").description("the account's calls");
72
- annotate(calls.command("list"), { effects: REMOTE_READ })
78
+ withQuery(annotate(calls.command("list"), {
79
+ effects: REMOTE_READ,
80
+ examples: [`${messenger.app.command} personal calls list`],
81
+ }), CALLS_QUERY)
73
82
  .description("calls made and received, newest first; reading changes nothing")
74
83
  .option("--limit <n>", "how many to show", positiveCount("--limit"))
75
- .action(async function () {
84
+ .action(async function (words) {
85
+ listQuery(typedQuery(words), CALLS_QUERY, "calls list");
76
86
  const context = messengerContext(this, messenger);
77
87
  const limit = context.settings.limit;
78
88
  const page = await context.withMessenger((adapter) => capability(adapter, "calls", "list calls")({ limit }));
@@ -1,9 +1,9 @@
1
1
  import { type RunMetadata } from "../../runs/run.js";
2
2
  import type { SendEntry } from "../../sends/journal.js";
3
- export interface Report {
3
+ export interface Report<Doctor extends object = Record<string, unknown>> {
4
4
  createdAt: string;
5
5
  /** What `doctor --json` answers — versions, paths, counts and the messenger's own checks. */
6
- doctor: Record<string, unknown>;
6
+ doctor: Doctor;
7
7
  /** The run the report is about: the one asked for, or the newest that failed. */
8
8
  run: {
9
9
  metadata: RunMetadata;
@@ -12,13 +12,25 @@ export interface Report {
12
12
  /** The newest write attempts — outcomes and ids, never text (`src/sends/journal.ts`). */
13
13
  sends: SendEntry[];
14
14
  }
15
+ /** Optional technical context supplied by a consumer; it is redacted with the rest of the report. */
16
+ export interface ReportContext {
17
+ createdAt?: never;
18
+ doctor?: never;
19
+ run?: never;
20
+ sends?: never;
21
+ version?: string;
22
+ runtime?: string;
23
+ platform?: string;
24
+ arch?: string;
25
+ profile?: string | null;
26
+ }
15
27
  /**
16
28
  * **Everything a report holds is already free of content** — the doctor, the run log and the send
17
29
  * journal are built that way. Two things are added: every id becomes a label, and the home
18
- * directory is hidden, since paths name the person's account on this machine. Copied from max-cli.
30
+ * directory is hidden, since paths name the person's account on this machine.
19
31
  */
20
- export declare const buildReport: ({ doctor, runsDir, runId, command, sends, now, home, }: {
21
- doctor: Record<string, unknown>;
32
+ export declare const buildReport: <Doctor extends object, Context extends ReportContext = Record<never, never>>({ doctor, runsDir, runId, command, sends, now, home, context, eventFields, }: {
33
+ doctor: Doctor;
22
34
  runsDir: string;
23
35
  runId?: string;
24
36
  /** What to type to list runs, for the error when `runId` names none. */
@@ -26,7 +38,10 @@ export declare const buildReport: ({ doctor, runsDir, runId, command, sends, now
26
38
  sends: SendEntry[];
27
39
  now?: Date;
28
40
  home: string | undefined;
29
- }) => Report;
41
+ context?: Context;
42
+ /** Retain allowlisted recorded fields, including time and severity, for an existing consumer contract. */
43
+ eventFields?: "report" | "recorded";
44
+ }) => Report<Doctor> & Omit<Context, keyof Report>;
30
45
  /**
31
46
  * Every field of a journal line that names a chat, a message or a write. A send's `operationId` is
32
47
  * its `sendId`, so one left raw would undo the other's label.
@@ -1,6 +1,7 @@
1
1
  import { createHash, randomBytes } from "node:crypto";
2
2
  import { join } from "node:path";
3
3
  import { CliError } from "@wirecat/cli-base";
4
+ import { LOG_ATTRIBUTES } from "../../runs/log-attributes.js";
4
5
  import { findRun, listRuns, readEvents } from "../../runs/run.js";
5
6
  const RECENT_SENDS = 20;
6
7
  /** Only these fields of a run event travel; a field added later is left out until it is named here. */
@@ -18,21 +19,22 @@ const EVENT_FIELDS = [
18
19
  /**
19
20
  * **Everything a report holds is already free of content** — the doctor, the run log and the send
20
21
  * journal are built that way. Two things are added: every id becomes a label, and the home
21
- * directory is hidden, since paths name the person's account on this machine. Copied from max-cli.
22
+ * directory is hidden, since paths name the person's account on this machine.
22
23
  */
23
- export const buildReport = ({ doctor, runsDir, runId, command, sends, now = new Date(), home, }) => {
24
+ export const buildReport = ({ doctor, runsDir, runId, command, sends, now = new Date(), home, context, eventFields = "report", }) => {
24
25
  const chosen = runId === undefined ? newestFailed(runsDir) : findRun(runsDir, runId);
25
26
  if (runId !== undefined && !chosen)
26
27
  throw new CliError("not_found", `no run ${runId} — \`${command} runs list\` names them`);
27
28
  const label = labeller();
28
29
  const account = doctor.account;
29
30
  const report = {
31
+ ...context,
30
32
  createdAt: now.toISOString(),
31
33
  doctor: {
32
34
  ...doctor,
33
35
  ...(account?.remembered ? { account: { ...account, remembered: label(account.remembered) } } : {}),
34
36
  },
35
- run: chosen ? { metadata: chosen.metadata, events: readEvents(chosen.dir).map(eventOf(label)) } : null,
37
+ run: chosen ? { metadata: chosen.metadata, events: readEvents(chosen.dir).map(eventOf(label, eventFields)) } : null,
36
38
  sends: sends.slice(-RECENT_SENDS).map((entry) => labelled(entry, label)),
37
39
  };
38
40
  return JSON.parse(hideHome(JSON.stringify(report), home));
@@ -85,8 +87,21 @@ const labeller = () => {
85
87
  const salt = randomBytes(16);
86
88
  return (id) => `id:${createHash("sha256").update(salt).update(id).digest("hex").slice(0, 12)}`;
87
89
  };
88
- const eventOf = (label) => (event) => {
89
- const kept = Object.fromEntries(Object.entries(event).filter(([key]) => EVENT_FIELDS.includes(key)));
90
+ const RECORDED_FIELDS = new Set([...LOG_ATTRIBUTES, "time", "severity"]);
91
+ const RECORDED_ID_FIELDS = new Set([
92
+ ...SEND_ID_FIELDS.map((key) => key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)),
93
+ "actor_id",
94
+ "target_id",
95
+ ]);
96
+ const eventOf = (label, fields) => (event) => {
97
+ const kept = Object.fromEntries(Object.entries(event)
98
+ .filter(([key]) => (fields === "recorded" ? RECORDED_FIELDS.has(key) : EVENT_FIELDS.includes(key)))
99
+ .map(([key, value]) => [
100
+ key,
101
+ fields === "recorded" && RECORDED_ID_FIELDS.has(key) && value !== undefined && value !== null
102
+ ? label(String(value))
103
+ : value,
104
+ ]));
90
105
  const ids = kept.ids;
91
106
  if (typeof ids !== "object" || ids === null)
92
107
  return kept;
@@ -13,8 +13,10 @@ import { storePath } from "../../store/path.js";
13
13
  import { environmentOf, setExitCode } from "../context.js";
14
14
  import { grantsAuthority, LOCAL_READ, LOCAL_WRITE, REMOTE_WRITE } from "../effects.js";
15
15
  import { itemOf, listOf, renderAnswer, snakeKeys } from "../envelope.js";
16
+ import { withQuery } from "../list-query.js";
16
17
  import { lineOf } from "../steps.js";
17
18
  import { messengerContext } from "./context.js";
19
+ import { SCHEDULES_QUERY, scheduleFilter } from "./list-result-queries.js";
18
20
  /** Each run of an agent is a paid model call that reads chats; keeping the store current is `serve`'s job. */
19
21
  const AGENT_MINIMUM_MINUTES = 60;
20
22
  const COMMAND_MINIMUM_MINUTES = 1;
@@ -156,11 +158,12 @@ export const scheduleCommand = (messenger) => {
156
158
  createdAt: new Date().toISOString(),
157
159
  });
158
160
  });
159
- annotate(command.command("list"), { effects: LOCAL_READ })
161
+ withQuery(annotate(command.command("list"), { effects: LOCAL_READ }), SCHEDULES_QUERY)
160
162
  .description("the schedules, when they run and how their last run went")
161
- .action(function () {
163
+ .action(function (words) {
164
+ const filter = scheduleFilter(words);
162
165
  const { context, state } = prepare(this);
163
- const rows = listSchedules(state).map((schedule) => ({
166
+ const rows = listSchedules(state, filter).map((schedule) => ({
164
167
  name: schedule.name,
165
168
  kind: schedule.kind,
166
169
  when: describeWhen(schedule.when),
@@ -2,4 +2,4 @@ import { type QueryRegistry } from "@wirecat/cli-base/query";
2
2
  import type { SendFilter } from "../../sends/journal.js";
3
3
  import { type QueryWords } from "../list-query.js";
4
4
  export declare const SENDS_QUERY: QueryRegistry;
5
- export declare const sendFilter: (words: QueryWords) => SendFilter | undefined;
5
+ export declare const sendFilter: (words: QueryWords, command?: string) => SendFilter | undefined;
@@ -17,8 +17,8 @@ export const SENDS_QUERY = {
17
17
  ? { ...field, operators: field.operators.filter((operator) => operator === "term" || operator === "phrase") }
18
18
  : field),
19
19
  };
20
- export const sendFilter = (words) => {
21
- const terms = queryTerms(words, SENDS_QUERY, "sends list");
20
+ export const sendFilter = (words, command = "sends list") => {
21
+ const terms = queryTerms(words, SENDS_QUERY, command);
22
22
  if (terms.size === 0)
23
23
  return undefined;
24
24
  const outcome = sendAttempt.entries.outcome.options.find((value) => value === terms.get("outcome"));
@@ -3,9 +3,9 @@ import type { CacheDatabase } from "../../store/driver.js";
3
3
  import type { Messenger } from "./context.js";
4
4
  /** `doctor`'s short summary of the store. Must answer for a broken file, so an error is a field. */
5
5
  export declare const storeSummary: (env: NodeJS.ProcessEnv) => Promise<{
6
- error?: undefined;
7
6
  path: string;
8
7
  exists: boolean;
8
+ error?: undefined;
9
9
  } | {
10
10
  path: string;
11
11
  exists: boolean;
@@ -4,22 +4,26 @@ import { Command } from "commander";
4
4
  import { capability } from "../../ports/messenger.js";
5
5
  import { ownerOnlyOption, REMOTE_READ, REMOTE_WRITE } from "../effects.js";
6
6
  import { itemOf, listOf, renderAnswer, snakeKeys } from "../envelope.js";
7
+ import { typedQuery, withQuery } from "../list-query.js";
7
8
  import { window, withPaging } from "../paging.js";
8
9
  import { lines, pageOf, topicAnswer } from "./chat-answers.js";
9
10
  import { messengerContext } from "./context.js";
10
- const listed = (messenger) => async function (chat) {
11
- const [, query] = this.args;
11
+ import { TOPICS_QUERY, topicTitle } from "./list-result-queries.js";
12
+ const listed = (messenger) => async function (chat, value) {
13
+ const searching = this.name() === "topics";
14
+ const words = !searching && Array.isArray(value) ? value : [];
15
+ const query = searching && typeof value === "string" ? value : topicTitle(words);
12
16
  const context = messengerContext(this, messenger);
13
17
  if (context.settings.offline) {
14
18
  throw new CliError("validation_error", "`topics` asks the messenger; not with --offline");
15
19
  }
16
20
  const wanted = { ...window(context.settings), ...(query ? { search: query } : {}) };
17
21
  const found = await context.withMessenger((adapter) => capability(adapter, "topics", "list forum topics")(chat, wanted));
18
- const command = query === undefined ? "topics list" : "search topics";
22
+ const command = searching ? "search topics" : "topics list";
19
23
  renderAnswer(this, context, listOf(command, {
20
24
  items: found.items.map(topicAnswer),
21
25
  ...pageOf(context.settings, found),
22
- args: { chat, ...(query === undefined ? {} : { text: query }) },
26
+ args: { chat, ...(searching ? { text: query } : typedQuery(words) ? { query: typedQuery(words) } : {}) },
23
27
  }), lines(({ id, title, closed, pinned, unread_count }) => [id, title, closed ? "closed" : "", pinned ? "pinned" : "", unread_count ? `${unread_count} unread` : ""].join(" ")));
24
28
  };
25
29
  /** `search topics`: a forum group's topics whose title matches, asked of the messenger. */
@@ -30,9 +34,9 @@ export const topicsSearchCommand = (messenger) => withPaging(annotate(new Comman
30
34
  /** `topics list` and the writes — a forum group's topics, with the ids its messages carry as `threadId`. */
31
35
  export const topicsCommand = (messenger) => {
32
36
  const topics = annotate(new Command("topics"), { offline: false }).description("the topics of a forum group");
33
- topics.addCommand(withPaging(annotate(new Command("list"), { effects: REMOTE_READ })
37
+ topics.addCommand(withQuery(withPaging(annotate(new Command("list"), { effects: REMOTE_READ })
34
38
  .description("a forum group's topics, newest activity first")
35
- .argument("<chat>", messenger.chatArgument)).action(listed(messenger)));
39
+ .argument("<chat>", messenger.chatArgument)), TOPICS_QUERY).action(listed(messenger)));
36
40
  if (messenger.topicShow)
37
41
  annotate(topics.command("show"), { effects: REMOTE_READ })
38
42
  .description("one forum topic: its title, state and last activity")
@@ -6,6 +6,7 @@ export const NOT_FILES = new Set([
6
6
  "location",
7
7
  "contact",
8
8
  "control",
9
+ "call",
9
10
  "inline_keyboard",
10
11
  ]);
11
12
  /** The stored kinds `has:<kind>` matches: MAX stores a file as `file`, Telegram as `document`. */
@@ -39,6 +39,7 @@ import { imageEmbedding } from "./image-embedding.js";
39
39
  import { inviteLink } from "./invite-link.js";
40
40
  import { job } from "./job.js";
41
41
  import { joinRequest } from "./join-request.js";
42
+ import { botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, callRecord, scheduledJob, stickerInventory } from "./list-results.js";
42
43
  import { messageEvent, serveSummary, watchedMessage, watchItem } from "./listener.js";
43
44
  import { mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer } from "./media-archive.js";
44
45
  import { meeting } from "./meeting.js";
@@ -84,7 +85,7 @@ import { topic } from "./topic.js";
84
85
  * subset of its fields, never a renamed one. Commands move onto these one by one; until then, a schema
85
86
  * is the target, not a description of today's output.
86
87
  */
87
- export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, cachedChatMetadata, 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, searchHistoryClear, sendAttempt, serveSummary, 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, };
88
+ 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, };
88
89
  export declare const ENTITIES: {
89
90
  readonly meeting_ingestion: v.StrictObjectSchema<{
90
91
  readonly meetings: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
@@ -4741,6 +4742,88 @@ export declare const ENTITIES: {
4741
4742
  readonly account: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
4742
4743
  readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4743
4744
  }, undefined>;
4745
+ readonly bot_profile: v.StrictObjectSchema<{
4746
+ readonly name: v.StringSchema<undefined>;
4747
+ readonly token: v.StringSchema<undefined>;
4748
+ readonly bot: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
4749
+ readonly id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
4750
+ readonly problem: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
4751
+ }, undefined>;
4752
+ readonly bot_template: v.StrictObjectSchema<{
4753
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4754
+ readonly status: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4755
+ readonly language: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4756
+ readonly category: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4757
+ }, undefined>;
4758
+ readonly bot_seen_chat: v.StrictObjectSchema<{
4759
+ readonly title: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
4760
+ readonly kind: v.OptionalSchema<v.PicklistSchema<["dialog", "group", "channel", "saved", "unknown"], undefined>, undefined>;
4761
+ readonly unread_count: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
4762
+ readonly unread_mentions: v.OptionalSchema<v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
4763
+ readonly last_message_at: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>, undefined>;
4764
+ readonly participants_count: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
4765
+ readonly muted: v.OptionalSchema<v.OptionalSchema<v.BooleanSchema<undefined>, undefined>, undefined>;
4766
+ readonly archived: v.OptionalSchema<v.OptionalSchema<v.BooleanSchema<undefined>, undefined>, undefined>;
4767
+ readonly marked_unread: v.OptionalSchema<v.OptionalSchema<v.BooleanSchema<undefined>, undefined>, undefined>;
4768
+ readonly membership_state: v.OptionalSchema<v.OptionalSchema<v.PicklistSchema<["joined", "left", "public", "imported", "archived", "external"], undefined>, undefined>, undefined>;
4769
+ readonly scope: v.OptionalSchema<v.OptionalSchema<v.PicklistSchema<["personal", "work"], undefined>, undefined>, undefined>;
4770
+ readonly provider_metadata: v.OptionalSchema<v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, undefined>, undefined>;
4771
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
4772
+ readonly parent_chat_id: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>, undefined>;
4773
+ readonly muted_until: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>, undefined>;
4774
+ readonly first_seen_at: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
4775
+ readonly last_seen_at: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
4776
+ }, undefined>;
4777
+ readonly bot_admin: v.StrictObjectSchema<{
4778
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
4779
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4780
+ readonly username: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4781
+ readonly role: v.PicklistSchema<["owner", "admin"], undefined>;
4782
+ readonly rights: v.ArraySchema<v.PicklistSchema<["read", "members", "admins", "info", "pin", "link", "post", "edit", "delete"], undefined>, undefined>;
4783
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4784
+ }, undefined>;
4785
+ readonly bot_menu_entry: v.StrictObjectSchema<{
4786
+ readonly name: v.StringSchema<undefined>;
4787
+ readonly description: v.NullableSchema<v.StringSchema<undefined>, undefined>;
4788
+ }, undefined>;
4789
+ readonly bot_webhook: v.StrictObjectSchema<{
4790
+ readonly url: v.StringSchema<undefined>;
4791
+ readonly types: v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
4792
+ }, undefined>;
4793
+ readonly scheduled_job: v.StrictObjectSchema<{
4794
+ readonly name: v.StringSchema<undefined>;
4795
+ readonly kind: v.PicklistSchema<["command", "agent"], undefined>;
4796
+ readonly when: v.StringSchema<undefined>;
4797
+ readonly last: v.NullableSchema<v.StrictObjectSchema<{
4798
+ readonly 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`">]>;
4799
+ readonly exit_code: v.NumberSchema<undefined>;
4800
+ readonly output: v.StringSchema<undefined>;
4801
+ readonly trace_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
4802
+ readonly reason: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
4803
+ readonly error_code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
4804
+ readonly failing_since: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
4805
+ readonly failures: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
4806
+ }, undefined>, undefined>;
4807
+ }, undefined>;
4808
+ readonly call_record: v.StrictObjectSchema<{
4809
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
4810
+ readonly chat_id: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
4811
+ readonly caller_id: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
4812
+ readonly direction: v.PicklistSchema<["incoming", "outgoing"], undefined>;
4813
+ readonly outcome: v.PicklistSchema<["answered", "missed", "declined"], undefined>;
4814
+ readonly kind: v.PicklistSchema<["audio", "video"], undefined>;
4815
+ readonly 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`">]>;
4816
+ readonly duration_seconds: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
4817
+ }, undefined>;
4818
+ readonly sticker_inventory: v.StrictObjectSchema<{
4819
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
4820
+ readonly title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
4821
+ readonly count: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
4822
+ readonly link: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
4823
+ readonly set_id: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>, undefined>;
4824
+ readonly emoji: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
4825
+ readonly url: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
4826
+ }, undefined>;
4744
4827
  readonly note: v.StrictObjectSchema<{
4745
4828
  readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
4746
4829
  readonly kind: v.OptionalSchema<v.PicklistSchema<["note", "document"], undefined>, undefined>;
@@ -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 { botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, callRecord, scheduledJob, stickerInventory, } from "./list-results.js";
44
45
  import { messageEvent, serveSummary, watchedMessage, watchItem } from "./listener.js";
45
46
  import { mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer } from "./media-archive.js";
46
47
  import { event, meeting, meetingDetails, meetingHit, meetingLink, meetingParticipants, meetingPassage, meetingProjectEvidence, meetingReview, meetingSpeaker, meetingStats, meetingSummary, meetingTranscript, } from "./meeting.js";
@@ -90,7 +91,7 @@ import { topic } from "./topic.js";
90
91
  * subset of its fields, never a renamed one. Commands move onto these one by one; until then, a schema
91
92
  * is the target, not a description of today's output.
92
93
  */
93
- export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, cachedChatMetadata, 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, searchHistoryClear, sendAttempt, serveSummary, 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, };
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, };
94
95
  export const ENTITIES = {
95
96
  sync_progress: syncProgress,
96
97
  ...MEETING_RESULT_ENTITIES,
@@ -166,6 +167,15 @@ export const ENTITIES = {
166
167
  account_privacy: accountPrivacy,
167
168
  account_privacy_change: accountPrivacyChange,
168
169
  account_profile: accountProfile,
170
+ bot_profile: botProfile,
171
+ bot_template: botTemplate,
172
+ bot_seen_chat: botSeenChat,
173
+ bot_admin: botAdmin,
174
+ bot_menu_entry: botMenuEntry,
175
+ bot_webhook: botWebhook,
176
+ scheduled_job: scheduledJob,
177
+ call_record: callRecord,
178
+ sticker_inventory: stickerInventory,
169
179
  note,
170
180
  "note.hit": v.pick(note, [
171
181
  "kind",
@@ -0,0 +1,83 @@
1
+ import * as v from "valibot";
2
+ export declare const botProfile: v.StrictObjectSchema<{
3
+ readonly name: v.StringSchema<undefined>;
4
+ readonly token: v.StringSchema<undefined>;
5
+ readonly bot: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
6
+ readonly id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
7
+ readonly problem: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
8
+ }, undefined>;
9
+ export declare const botSeenChat: v.StrictObjectSchema<{
10
+ readonly title: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
11
+ readonly kind: v.OptionalSchema<v.PicklistSchema<["dialog", "group", "channel", "saved", "unknown"], undefined>, undefined>;
12
+ readonly unread_count: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
13
+ readonly unread_mentions: v.OptionalSchema<v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
14
+ readonly last_message_at: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>, undefined>;
15
+ readonly participants_count: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
16
+ readonly muted: v.OptionalSchema<v.OptionalSchema<v.BooleanSchema<undefined>, undefined>, undefined>;
17
+ readonly archived: v.OptionalSchema<v.OptionalSchema<v.BooleanSchema<undefined>, undefined>, undefined>;
18
+ readonly marked_unread: v.OptionalSchema<v.OptionalSchema<v.BooleanSchema<undefined>, undefined>, undefined>;
19
+ readonly membership_state: v.OptionalSchema<v.OptionalSchema<v.PicklistSchema<["joined", "left", "public", "imported", "archived", "external"], undefined>, undefined>, undefined>;
20
+ readonly scope: v.OptionalSchema<v.OptionalSchema<v.PicklistSchema<["personal", "work"], undefined>, undefined>, undefined>;
21
+ readonly provider_metadata: v.OptionalSchema<v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, undefined>, undefined>;
22
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
23
+ readonly parent_chat_id: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>, undefined>;
24
+ readonly muted_until: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>, undefined>;
25
+ readonly first_seen_at: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
26
+ readonly last_seen_at: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
27
+ }, undefined>;
28
+ export declare const botAdmin: v.StrictObjectSchema<{
29
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
30
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
31
+ readonly username: v.NullableSchema<v.StringSchema<undefined>, undefined>;
32
+ readonly role: v.PicklistSchema<["owner", "admin"], undefined>;
33
+ readonly rights: v.ArraySchema<v.PicklistSchema<["read", "members", "admins", "info", "pin", "link", "post", "edit", "delete"], undefined>, undefined>;
34
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
35
+ }, undefined>;
36
+ export declare const botMenuEntry: v.StrictObjectSchema<{
37
+ readonly name: v.StringSchema<undefined>;
38
+ readonly description: v.NullableSchema<v.StringSchema<undefined>, undefined>;
39
+ }, undefined>;
40
+ export declare const botWebhook: v.StrictObjectSchema<{
41
+ readonly url: v.StringSchema<undefined>;
42
+ readonly types: v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
43
+ }, undefined>;
44
+ export declare const scheduledJob: v.StrictObjectSchema<{
45
+ readonly name: v.StringSchema<undefined>;
46
+ readonly kind: v.PicklistSchema<["command", "agent"], undefined>;
47
+ readonly when: v.StringSchema<undefined>;
48
+ readonly last: v.NullableSchema<v.StrictObjectSchema<{
49
+ readonly 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`">]>;
50
+ readonly exit_code: v.NumberSchema<undefined>;
51
+ readonly output: v.StringSchema<undefined>;
52
+ readonly trace_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
53
+ readonly reason: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
54
+ readonly error_code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
55
+ readonly failing_since: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
56
+ readonly failures: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
57
+ }, undefined>, undefined>;
58
+ }, undefined>;
59
+ export declare const botTemplate: v.StrictObjectSchema<{
60
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
61
+ readonly status: v.NullableSchema<v.StringSchema<undefined>, undefined>;
62
+ readonly language: v.NullableSchema<v.StringSchema<undefined>, undefined>;
63
+ readonly category: v.NullableSchema<v.StringSchema<undefined>, undefined>;
64
+ }, undefined>;
65
+ export declare const callRecord: v.StrictObjectSchema<{
66
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
67
+ readonly chat_id: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
68
+ readonly caller_id: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
69
+ readonly direction: v.PicklistSchema<["incoming", "outgoing"], undefined>;
70
+ readonly outcome: v.PicklistSchema<["answered", "missed", "declined"], undefined>;
71
+ readonly kind: v.PicklistSchema<["audio", "video"], undefined>;
72
+ readonly 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`">]>;
73
+ readonly duration_seconds: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
74
+ }, undefined>;
75
+ export declare const stickerInventory: v.StrictObjectSchema<{
76
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
77
+ readonly title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
78
+ readonly count: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
79
+ readonly link: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
80
+ readonly set_id: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>, undefined>;
81
+ readonly emoji: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
82
+ readonly url: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
83
+ }, undefined>;
@@ -0,0 +1,69 @@
1
+ import * as v from "valibot";
2
+ import { chat } from "./chat.js";
3
+ import { id, text, time } from "./fields.js";
4
+ export const botProfile = v.strictObject({
5
+ name: text,
6
+ token: text,
7
+ bot: v.optional(text),
8
+ id: v.optional(id),
9
+ problem: v.optional(text),
10
+ });
11
+ export const botSeenChat = v.strictObject({
12
+ ...v.partial(v.omit(chat, ["ref", "provider", "account", "description", "invite_link", "settings", "members"]))
13
+ .entries,
14
+ id,
15
+ parent_chat_id: v.optional(v.nullable(id)),
16
+ muted_until: v.optional(v.nullable(time)),
17
+ first_seen_at: v.optional(time),
18
+ last_seen_at: v.optional(time),
19
+ });
20
+ export const botAdmin = v.strictObject({
21
+ id,
22
+ name: v.nullable(text),
23
+ username: v.nullable(text),
24
+ role: v.picklist(["owner", "admin"]),
25
+ rights: v.array(v.picklist(["read", "members", "admins", "info", "pin", "link", "post", "edit", "delete"])),
26
+ title: v.nullable(text),
27
+ });
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)) });
30
+ export const scheduledJob = v.strictObject({
31
+ name: text,
32
+ kind: v.picklist(["command", "agent"]),
33
+ when: text,
34
+ last: v.nullable(v.strictObject({
35
+ at: time,
36
+ exit_code: v.number(),
37
+ output: text,
38
+ trace_id: v.optional(text),
39
+ reason: v.optional(text),
40
+ error_code: v.optional(text),
41
+ failing_since: v.optional(time),
42
+ failures: v.optional(v.number()),
43
+ })),
44
+ });
45
+ export const botTemplate = v.strictObject({
46
+ name: v.nullable(text),
47
+ status: v.nullable(text),
48
+ language: v.nullable(text),
49
+ category: v.nullable(text),
50
+ });
51
+ export const callRecord = v.strictObject({
52
+ id,
53
+ chat_id: v.nullable(id),
54
+ caller_id: v.nullable(id),
55
+ direction: v.picklist(["incoming", "outgoing"]),
56
+ outcome: v.picklist(["answered", "missed", "declined"]),
57
+ kind: v.picklist(["audio", "video"]),
58
+ at: time,
59
+ duration_seconds: v.nullable(v.number()),
60
+ });
61
+ export const stickerInventory = v.strictObject({
62
+ id,
63
+ title: v.optional(text),
64
+ count: v.optional(v.number()),
65
+ link: v.optional(v.nullable(text)),
66
+ set_id: v.optional(v.nullable(id)),
67
+ emoji: v.optional(v.array(text)),
68
+ url: v.optional(v.nullable(text)),
69
+ });
@@ -81,11 +81,11 @@ export const meetingHitSearchRequest = (query, options, signal) => {
81
81
  /** Parsed dates must become ISO values again so the CLI can replay its own continuation. */
82
82
  export const meetingSearchArguments = (query, options) => Object.fromEntries(Object.entries({
83
83
  query,
84
- meeting_id: options.meetingId,
85
- identity_id: options.identityId,
86
- person_id: options.personId,
87
- event_id: options.eventId,
88
- series_id: options.seriesId,
84
+ meeting_id: options.meetingId?.toString(),
85
+ identity_id: options.identityId?.toString(),
86
+ person_id: options.personId?.toString(),
87
+ event_id: options.eventId?.toString(),
88
+ series_id: options.seriesId?.toString(),
89
89
  project: options.project,
90
90
  tag: options.tag,
91
91
  topic: options.topic,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.408.0",
3
+ "version": "0.410.0",
4
4
  "description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Viacheslav Ptsarev",
@@ -209,7 +209,7 @@
209
209
  "@types/node": "^22.20.4",
210
210
  "@types/pngjs": "6.0.5",
211
211
  "@vitest/coverage-v8": "^5.0.2",
212
- "@wirecat/cli-base": "0.50.2",
212
+ "@wirecat/cli-base": "0.50.4",
213
213
  "commander": "15.0.0",
214
214
  "cspell": "10.3.6",
215
215
  "drizzle-kit": "1.0.0-rc.4",