@wirecat/cli-core 0.398.0 → 0.400.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 (248) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/dist/analysis/consents.d.ts +11 -6
  3. package/dist/analysis/consents.js +5 -2
  4. package/dist/cli/analysis-choice.d.ts +1 -0
  5. package/dist/cli/analysis-choice.js +3 -0
  6. package/dist/cli/bot/admins.js +14 -4
  7. package/dist/cli/bot/command.js +38 -16
  8. package/dist/cli/bot/examples.d.ts +3 -0
  9. package/dist/cli/bot/examples.js +2 -0
  10. package/dist/cli/bot/mcp.js +6 -2
  11. package/dist/cli/bot/messages.js +17 -6
  12. package/dist/cli/bot/moderation.js +16 -4
  13. package/dist/cli/bot/people.js +16 -4
  14. package/dist/cli/bot/setup.js +27 -8
  15. package/dist/cli/bot/watch.js +7 -1
  16. package/dist/cli/config-command.js +20 -1
  17. package/dist/cli/context.d.ts +2 -0
  18. package/dist/cli/context.js +1 -1
  19. package/dist/cli/effects.d.ts +4 -1
  20. package/dist/cli/effects.js +10 -2
  21. package/dist/cli/embedding-choice.d.ts +2 -1
  22. package/dist/cli/embedding-choice.js +4 -1
  23. package/dist/cli/index.d.ts +1 -1
  24. package/dist/cli/index.js +1 -1
  25. package/dist/cli/json-fields.js +12 -1
  26. package/dist/cli/messenger/account-command.js +15 -6
  27. package/dist/cli/messenger/account-profile-query.d.ts +2 -0
  28. package/dist/cli/messenger/account-profile-query.js +13 -0
  29. package/dist/cli/messenger/account-sessions-command.js +1 -0
  30. package/dist/cli/messenger/admin-commands.js +30 -21
  31. package/dist/cli/messenger/admin-contacts-command.js +6 -3
  32. package/dist/cli/messenger/admin-folders-command.js +5 -5
  33. package/dist/cli/messenger/admin-moderation-command.js +4 -4
  34. package/dist/cli/messenger/admin-statistics-command.js +6 -14
  35. package/dist/cli/messenger/analysis-consents-query.d.ts +5 -0
  36. package/dist/cli/messenger/analysis-consents-query.js +20 -0
  37. package/dist/cli/messenger/archive-commands.js +3 -3
  38. package/dist/cli/messenger/attachments-command.js +3 -0
  39. package/dist/cli/messenger/backfill-command.js +5 -4
  40. package/dist/cli/messenger/catch-up-answers.d.ts +2 -1
  41. package/dist/cli/messenger/catch-up-answers.js +6 -2
  42. package/dist/cli/messenger/chat-queries.d.ts +1 -0
  43. package/dist/cli/messenger/chat-queries.js +12 -2
  44. package/dist/cli/messenger/chats-command.js +2 -2
  45. package/dist/cli/messenger/chats-documents-command.js +7 -5
  46. package/dist/cli/messenger/chats-members-command.js +7 -3
  47. package/dist/cli/messenger/chats-read-command.js +1 -1
  48. package/dist/cli/messenger/chats-stats-command.js +1 -1
  49. package/dist/cli/messenger/chats-tracking-command.js +14 -6
  50. package/dist/cli/messenger/contacts-command.js +11 -7
  51. package/dist/cli/messenger/context.d.ts +2 -0
  52. package/dist/cli/messenger/conversations-command.js +47 -29
  53. package/dist/cli/messenger/doctor-command.js +5 -1
  54. package/dist/cli/messenger/document-links-query.d.ts +2 -0
  55. package/dist/cli/messenger/document-links-query.js +9 -0
  56. package/dist/cli/messenger/download-command.js +1 -0
  57. package/dist/cli/messenger/flood-command.d.ts +2 -2
  58. package/dist/cli/messenger/flood-command.js +3 -3
  59. package/dist/cli/messenger/gaps-command.js +2 -2
  60. package/dist/cli/messenger/guard-commands.js +35 -13
  61. package/dist/cli/messenger/hearing-command.d.ts +1 -1
  62. package/dist/cli/messenger/hearing-command.js +1 -1
  63. package/dist/cli/messenger/images-command.js +1 -0
  64. package/dist/cli/messenger/inbox.js +6 -4
  65. package/dist/cli/messenger/media-archive-command.js +2 -0
  66. package/dist/cli/messenger/media-archive-move-command.js +1 -0
  67. package/dist/cli/messenger/media-archive-timer-command.js +1 -1
  68. package/dist/cli/messenger/mentions-command.js +15 -2
  69. package/dist/cli/messenger/messages-command.js +2 -0
  70. package/dist/cli/messenger/messages-delete-command.js +1 -0
  71. package/dist/cli/messenger/messages-edit-command.js +1 -0
  72. package/dist/cli/messenger/messages-evidence-command.js +3 -1
  73. package/dist/cli/messenger/messages-forward-command.js +1 -0
  74. package/dist/cli/messenger/messages-pin-command.js +3 -0
  75. package/dist/cli/messenger/messages-send-command.js +1 -0
  76. package/dist/cli/messenger/messages-stats-command.js +1 -1
  77. package/dist/cli/messenger/metadata-command.js +7 -2
  78. package/dist/cli/messenger/models-command.js +10 -2
  79. package/dist/cli/messenger/polls-command.js +4 -0
  80. package/dist/cli/messenger/private-people-command.js +8 -6
  81. package/dist/cli/messenger/rankings-command.js +6 -11
  82. package/dist/cli/messenger/reactions-command.js +2 -0
  83. package/dist/cli/messenger/recipients-query.d.ts +5 -0
  84. package/dist/cli/messenger/recipients-query.js +18 -0
  85. package/dist/cli/messenger/records-command.js +13 -6
  86. package/dist/cli/messenger/replies-edit-command.d.ts +1 -1
  87. package/dist/cli/messenger/replies-edit-command.js +13 -5
  88. package/dist/cli/messenger/retention-command.js +1 -1
  89. package/dist/cli/messenger/review.js +6 -4
  90. package/dist/cli/messenger/search-command.js +3 -1
  91. package/dist/cli/messenger/searches-command.js +6 -2
  92. package/dist/cli/messenger/sends-query.d.ts +5 -0
  93. package/dist/cli/messenger/sends-query.js +33 -0
  94. package/dist/cli/messenger/serve-command.js +1 -0
  95. package/dist/cli/messenger/serve-relay.d.ts +1 -0
  96. package/dist/cli/messenger/statistics-query.d.ts +14 -0
  97. package/dist/cli/messenger/statistics-query.js +143 -0
  98. package/dist/cli/messenger/stats-command.js +6 -6
  99. package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
  100. package/dist/cli/messenger/store-maintenance-command.js +10 -10
  101. package/dist/cli/messenger/tags-command.js +18 -6
  102. package/dist/cli/messenger/tasks-command.js +47 -8
  103. package/dist/cli/messenger/transcribe-command.js +2 -1
  104. package/dist/cli/messenger/watch-answers.d.ts +6 -0
  105. package/dist/cli/messenger/watch-answers.js +69 -0
  106. package/dist/cli/messenger/watch-command.d.ts +1 -1
  107. package/dist/cli/messenger/watch-command.js +56 -7
  108. package/dist/cli/program.js +5 -1
  109. package/dist/cli/runs/command.js +25 -38
  110. package/dist/cli/runs/query.d.ts +5 -0
  111. package/dist/cli/runs/query.js +32 -0
  112. package/dist/cli/runs/search-command.d.ts +4 -0
  113. package/dist/cli/runs/search-command.js +27 -0
  114. package/dist/cli/runs/search-query.d.ts +4 -0
  115. package/dist/cli/runs/search-query.js +50 -0
  116. package/dist/cli/runs/search.d.ts +2 -1
  117. package/dist/cli/runs/search.js +6 -6
  118. package/dist/domain/attachments.js +9 -1
  119. package/dist/domain/rankings-options.js +3 -3
  120. package/dist/entities/account-change.d.ts +89 -0
  121. package/dist/entities/account-change.js +20 -0
  122. package/dist/entities/account-profile.d.ts +7 -0
  123. package/dist/entities/account-profile.js +8 -0
  124. package/dist/entities/analysis-consent.d.ts +9 -0
  125. package/dist/entities/analysis-consent.js +4 -0
  126. package/dist/entities/attachment-results.d.ts +96 -0
  127. package/dist/entities/attachment-results.js +31 -0
  128. package/dist/entities/batch-result.d.ts +27 -0
  129. package/dist/entities/batch-result.js +18 -0
  130. package/dist/entities/chat-admin.d.ts +234 -0
  131. package/dist/entities/chat-admin.js +84 -0
  132. package/dist/entities/chat-change.d.ts +25 -0
  133. package/dist/entities/chat-change.js +11 -0
  134. package/dist/entities/chat-metadata.d.ts +34 -0
  135. package/dist/entities/chat-metadata.js +15 -0
  136. package/dist/entities/chat-moderation.d.ts +44 -0
  137. package/dist/entities/chat-moderation.js +37 -0
  138. package/dist/entities/chat-tracking.d.ts +26 -0
  139. package/dist/entities/chat-tracking.js +23 -0
  140. package/dist/entities/contact-activity.d.ts +52 -0
  141. package/dist/entities/contact-activity.js +42 -0
  142. package/dist/entities/contact-context.d.ts +1568 -0
  143. package/dist/entities/contact-context.js +191 -0
  144. package/dist/entities/contact-write.d.ts +22 -0
  145. package/dist/entities/contact-write.js +6 -0
  146. package/dist/entities/conversation-preparation.d.ts +63 -0
  147. package/dist/entities/conversation-preparation.js +23 -0
  148. package/dist/entities/conversation-results.d.ts +567 -0
  149. package/dist/entities/conversation-results.js +94 -0
  150. package/dist/entities/document-link.d.ts +13 -0
  151. package/dist/entities/document-link.js +11 -0
  152. package/dist/entities/extraction-report.d.ts +95 -0
  153. package/dist/entities/extraction-report.js +34 -0
  154. package/dist/entities/image-embedding.d.ts +9 -0
  155. package/dist/entities/image-embedding.js +10 -0
  156. package/dist/entities/index.d.ts +8006 -1928
  157. package/dist/entities/index.js +174 -3
  158. package/dist/entities/listener.d.ts +2150 -0
  159. package/dist/entities/listener.js +46 -0
  160. package/dist/entities/media-archive.d.ts +43 -0
  161. package/dist/entities/media-archive.js +32 -0
  162. package/dist/entities/meeting-task-proposal.d.ts +14 -0
  163. package/dist/entities/meeting-task-proposal.js +19 -0
  164. package/dist/entities/meeting.d.ts +1 -1
  165. package/dist/entities/meeting.js +1 -1
  166. package/dist/entities/mention.d.ts +63 -0
  167. package/dist/entities/mention.js +44 -0
  168. package/dist/entities/message-change.d.ts +19 -0
  169. package/dist/entities/message-change.js +6 -0
  170. package/dist/entities/message-context.d.ts +617 -0
  171. package/dist/entities/message-context.js +20 -0
  172. package/dist/entities/message-read.d.ts +73 -0
  173. package/dist/entities/message-read.js +58 -0
  174. package/dist/entities/message-transfer.d.ts +379 -0
  175. package/dist/entities/message-transfer.js +83 -0
  176. package/dist/entities/message-write.d.ts +191 -0
  177. package/dist/entities/message-write.js +8 -0
  178. package/dist/entities/model-key.d.ts +14 -0
  179. package/dist/entities/model-key.js +10 -0
  180. package/dist/entities/poll.d.ts +40 -0
  181. package/dist/entities/poll.js +16 -0
  182. package/dist/entities/private-contact.d.ts +10 -0
  183. package/dist/entities/private-contact.js +4 -0
  184. package/dist/entities/reaction-change.d.ts +7 -0
  185. package/dist/entities/reaction-change.js +8 -0
  186. package/dist/entities/recipient.d.ts +29 -0
  187. package/dist/entities/recipient.js +11 -0
  188. package/dist/entities/recorded-run.d.ts +103 -0
  189. package/dist/entities/recorded-run.js +44 -0
  190. package/dist/entities/saved-search.d.ts +4 -0
  191. package/dist/entities/saved-search.js +2 -0
  192. package/dist/entities/send-attempt.d.ts +31 -0
  193. package/dist/entities/send-attempt.js +29 -0
  194. package/dist/entities/store-maintenance.d.ts +319 -0
  195. package/dist/entities/store-maintenance.js +145 -0
  196. package/dist/entities/store-records.d.ts +442 -0
  197. package/dist/entities/store-records.js +99 -0
  198. package/dist/entities/tag-change.d.ts +74 -0
  199. package/dist/entities/tag-change.js +31 -0
  200. package/dist/entities/task-pair.d.ts +31 -0
  201. package/dist/entities/task-pair.js +23 -0
  202. package/dist/entities/task-results.d.ts +524 -0
  203. package/dist/entities/task-results.js +142 -0
  204. package/dist/errors/reasons.js +1 -0
  205. package/dist/mcp/agent.d.ts +3 -1
  206. package/dist/mcp/agent.js +9 -6
  207. package/dist/mcp/bot/server.d.ts +2 -0
  208. package/dist/mcp/bot/server.js +1 -0
  209. package/dist/mcp/prompts.js +8 -2
  210. package/dist/mcp/server.js +3 -1
  211. package/dist/mcp/tools/attachments.js +1 -0
  212. package/dist/meetings/cli/index.js +1 -1
  213. package/dist/meetings/cli/passage.js +1 -0
  214. package/dist/meetings/index.d.ts +2 -1
  215. package/dist/meetings/index.js +1 -0
  216. package/dist/meetings/links.d.ts +16 -0
  217. package/dist/meetings/mcp/index.d.ts +15 -15
  218. package/dist/meetings/read-answers.d.ts +167 -0
  219. package/dist/meetings/read-answers.js +183 -0
  220. package/dist/runs/run.d.ts +10 -2
  221. package/dist/runs/run.js +11 -3
  222. package/dist/sends/journal.d.ts +8 -1
  223. package/dist/sends/journal.js +9 -2
  224. package/dist/sends/permissions.d.ts +5 -1
  225. package/dist/sends/permissions.js +11 -1
  226. package/dist/sends/recipients.d.ts +8 -0
  227. package/dist/sends/recipients.js +9 -0
  228. package/dist/services/admin-statistics.js +3 -3
  229. package/dist/services/chat-documents.d.ts +1 -0
  230. package/dist/services/chat-documents.js +9 -3
  231. package/dist/services/chats.d.ts +1 -1
  232. package/dist/services/chats.js +5 -2
  233. package/dist/services/meeting-links.d.ts +2 -17
  234. package/dist/store/exports.d.ts +1 -1
  235. package/dist/store/exports.js +1 -1
  236. package/dist/store/messages.d.ts +3 -1
  237. package/dist/store/messages.js +2 -2
  238. package/dist/store/roster.d.ts +4 -1
  239. package/dist/store/roster.js +2 -2
  240. package/dist/store/sqlite/chats.d.ts +12 -0
  241. package/dist/store/sqlite/chats.js +1 -0
  242. package/dist/store/sqlite/document-links.d.ts +1 -1
  243. package/dist/store/sqlite/document-links.js +5 -5
  244. package/dist/store/sqlite/involvements.js +2 -1
  245. package/dist/store/sqlite/roster.d.ts +2 -1
  246. package/dist/store/sqlite/roster.js +3 -2
  247. package/package.json +3 -3
  248. package/parity.json +76 -108
@@ -1,6 +1,6 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
2
  import { annotate } from "@wirecat/cli-base/commands";
3
- import { Command } from "commander";
3
+ import { Command, Option } from "commander";
4
4
  import { analysisConsents } from "../../analysis/consents.js";
5
5
  import { openAnalysis, providerIdentity } from "../../analysis/provider.js";
6
6
  import { runAnalysis } from "../../analysis/runner.js";
@@ -18,6 +18,7 @@ import { listQuery, pagedList, pageOf, typedQuery, withQuery } from "../list-que
18
18
  import { positiveCount } from "../paging.js";
19
19
  import { readsStdin } from "../stdin-field.js";
20
20
  import { nextStep, rootOf, runnable, stepLine } from "../steps.js";
21
+ import { ANALYSIS_CONSENTS_QUERY, analysisConsentFilter } from "./analysis-consents-query.js";
21
22
  import { answerOf as askOwner } from "./ask.js";
22
23
  import { messengerContext, refuseLocalWrite } from "./context.js";
23
24
  import { conversationShown, foundConversations, readinessList, refreshedAnswer } from "./conversation-answers.js";
@@ -33,13 +34,16 @@ export const conversationsCommand = (messenger) => {
33
34
  const conversations = new Command("conversations")
34
35
  .summary("group stored messages into conversations")
35
36
  .description("the conversations inside a chat, found in the stored messages by replies, mentions and who wrote next");
36
- boundOptions(reachesOtherService(annotate(conversations.command("build"), { effects: REMOTE_WRITE }))
37
+ boundOptions(reachesOtherService(annotate(conversations.command("build"), { output: { entity: "conversation_build" }, effects: REMOTE_WRITE }))
37
38
  .summary("build conversation links from stored messages")
38
39
  .description("find a chat's conversations in what the store holds, replacing the last build; without --chat, every " +
39
40
  "chat that changed since its build and every group never built; never asks the messenger")
40
41
  .option("--chat <chat>", messenger.chatArgument)
41
42
  .option("--analyze", "link batches using the configured analysis provider; requires --chat and remembers consent for this chat/provider")
42
- .option("--provider <provider>", "analysis: agent, openai or anthropic")
43
+ .addOption(new Option("--analysis-provider <provider>", "analysis: agent, openai or anthropic").conflicts("provider"))
44
+ .addOption(new Option("--provider <provider>", "compatibility alias for --analysis-provider")
45
+ .hideHelp()
46
+ .conflicts("analysisProvider"))
43
47
  .option("--model <model>", "analysis model; overrides analysis_model")
44
48
  .option("--base-url <url>", "analysis API endpoint; overrides analysis_base_url")
45
49
  .option("--size <n>", "analysis answer messages per batch, 10–200; default 50", positiveCount("--size"))
@@ -95,7 +99,8 @@ export const conversationsCommand = (messenger) => {
95
99
  renderAnswer(this, context, itemOf(snakeKeys(result)));
96
100
  return;
97
101
  }
98
- if (options.provider !== undefined ||
102
+ if (options.analysisProvider !== undefined ||
103
+ options.provider !== undefined ||
99
104
  options.model !== undefined ||
100
105
  options.baseUrl !== undefined ||
101
106
  options.size !== undefined ||
@@ -126,7 +131,7 @@ export const conversationsCommand = (messenger) => {
126
131
  if (found.items.length === 0 && context.format === "pretty")
127
132
  context.renderer.note("no conversations match");
128
133
  });
129
- annotate(conversations.command("show"), { effects: LOCAL_READ })
134
+ annotate(conversations.command("show"), { output: { entity: "conversation", view: "details" }, effects: LOCAL_READ })
130
135
  .summary("one conversation and its messages")
131
136
  .description("one conversation's messages, oldest first — by its id, or the one a message is in")
132
137
  .argument("<conversation>", `a conversation id from \`conversations list\`; or ${messenger.chatArgument}, with a message`)
@@ -155,7 +160,7 @@ export const conversationsCommand = (messenger) => {
155
160
  else
156
161
  renderAnswer(this, context, conversationShown(account, { summary, messages }));
157
162
  });
158
- withModelOptions(annotate(conversations.command("related"), { effects: LOCAL_READ })
163
+ withModelOptions(annotate(conversations.command("related"), { output: { entity: "conversation_hit" }, effects: LOCAL_READ })
159
164
  .summary("conversations nearest in meaning to a message's conversation")
160
165
  .description("the conversations nearest in meaning to the one a message is in, in every built chat, best first — " +
161
166
  "from the vectors `conversations embed` stored; runs no model")
@@ -171,7 +176,7 @@ export const conversationsCommand = (messenger) => {
171
176
  if (found.hits.length === 0 && context.format === "pretty")
172
177
  context.renderer.note(`no other conversation has vectors of ${found.model}`);
173
178
  });
174
- withModelOptions(annotate(conversations.command("status"), { effects: LOCAL_READ })
179
+ withModelOptions(annotate(conversations.command("status"), { output: { entity: "conversation_readiness" }, effects: LOCAL_READ })
175
180
  .summary("which chats are ready for conversation search")
176
181
  .description("how fresh each built chat's conversations and vectors are: messages the build has not seen, chunks " +
177
182
  "with a current, stale or missing vector")
@@ -189,7 +194,7 @@ export const conversationsCommand = (messenger) => {
189
194
  .summary("batches waiting for an agent's conversation links")
190
195
  .description("windows of a chat for your own AI agent to link: which earlier message each one answers");
191
196
  const sizeOption = (command) => command.option("--size <n>", `messages to answer per batch, ${BATCH_SIZE.min}–${BATCH_SIZE.max}; ${BATCH_SIZE.default} by default`, positiveCount("--size"));
192
- sizeOption(annotate(batches.command("status"), { effects: LOCAL_READ })
197
+ sizeOption(annotate(batches.command("status"), { output: { entity: "conversation_batch_status" }, effects: LOCAL_READ })
193
198
  .summary("progress of conversation-link batches")
194
199
  .description("how many messages still wait for an answer, in how many batches, and how much text")
195
200
  .requiredOption("--chat <chat>", messenger.chatArgument)).action(async function () {
@@ -199,7 +204,7 @@ export const conversationsCommand = (messenger) => {
199
204
  renderAnswer(this, context, itemOf(snakeKeys(status)), () => `${status.messages} messages to answer, about ${status.batches} batches, ` +
200
205
  `${status.characters} characters (about ${status.tokensEstimate} tokens)\n`);
201
206
  });
202
- sizeOption(annotate(batches.command("next"), { effects: LOCAL_READ })
207
+ sizeOption(annotate(batches.command("next"), { output: { entity: "conversation_batch" }, effects: LOCAL_READ })
203
208
  .summary("get the next batch of messages to link")
204
209
  .description("the next window to answer, with the messages before it; message text goes to stdout only")
205
210
  .requiredOption("--chat <chat>", messenger.chatArgument)).action(async function () {
@@ -226,7 +231,7 @@ export const conversationsCommand = (messenger) => {
226
231
  const links = conversations
227
232
  .command("links")
228
233
  .description("your agent's answers: which earlier message each message of a batch answers");
229
- readsStdin(annotate(links.command("add"), { effects: LOCAL_WRITE }), {
234
+ readsStdin(annotate(links.command("add"), { output: { entity: "conversation_change" }, effects: LOCAL_WRITE }), {
230
235
  name: "answer",
231
236
  description: '{ "model", "skill"?, "answers": [{ "message", "parent", "confidence" }] }',
232
237
  json: true,
@@ -243,22 +248,23 @@ export const conversationsCommand = (messenger) => {
243
248
  const stored = await context.withServices((services) => services.conversations.addAnswers(batch, answer));
244
249
  renderAnswer(this, context, itemOf(stored, { next: [nextStep("conversations.build", { args: { chat: stored.chat } })] }), () => `${stored.stored} answers stored\n`);
245
250
  });
246
- annotate(links.command("clear"), { effects: LOCAL_WRITE })
251
+ annotate(links.command("clear"), { output: { entity: "conversation_change" }, effects: LOCAL_WRITE })
247
252
  .summary("remove an agent's saved conversation-link answers")
248
253
  .description("drop your agent's answers for a chat, or only one model's; messages are never touched")
249
254
  .requiredOption("--chat <chat>", messenger.chatArgument)
250
- .option("--model <model>", "only the answers this model gave")
255
+ .addOption(new Option("--answer-model <model>", "only the stored answers this model gave").conflicts("model"))
256
+ .addOption(new Option("--model <model>", "compatibility alias for --answer-model").hideHelp().conflicts("answerModel"))
251
257
  .action(async function () {
252
- const { chat, model } = this.opts();
258
+ const { chat, model, answerModel } = this.opts();
253
259
  const context = messengerContext(this, messenger);
254
260
  refuseLocalWrite(context, messenger.app.command, LINKS_KEY);
255
- const cleared = await context.withServices((services) => services.conversations.clearAnswers(chat, model));
261
+ const cleared = await context.withServices((services) => services.conversations.clearAnswers(chat, answerModel ?? model));
256
262
  renderAnswer(this, context, itemOf(cleared), () => `${cleared.cleared} answers dropped\n`);
257
263
  });
258
- const embed = withModelOptions(reachesOtherService(annotate(new Command("embed"), { effects: REMOTE_WRITE }))
264
+ const embed = withModelOptions(reachesOtherService(annotate(new Command("embed"), { output: { entity: "conversation_embedding" }, effects: REMOTE_WRITE }))
259
265
  .summary("prepare conversation vectors for meaning search")
260
266
  .description("compute a vector for each chunk of a chat's conversations for search by meaning — on this machine, or " +
261
- "with --provider through a service and your key; resumes where it stopped; without --chat, every " +
267
+ "with --embedding-provider through a service and your key; resumes where it stopped; without --chat, every " +
262
268
  "built chat with chunks left, on this machine only")
263
269
  .option("--chat <chat>", messenger.chatArgument))
264
270
  .option("--threads <n>", "local: threads in all (default: min(8, cores))", positiveCount("--threads"))
@@ -302,7 +308,7 @@ export const conversationsCommand = (messenger) => {
302
308
  next: done.skipped ? [nextStep("conversations.build", { args: { chat } })] : [],
303
309
  }), () => `${done.embedded} chunks embedded with ${done.model}${done.skipped ? `, ${done.skipped} changed since the build` : ""}\n`);
304
310
  });
305
- withModelOptions(annotate(embed.command("status"), { effects: LOCAL_READ })
311
+ withModelOptions(annotate(embed.command("status"), { output: { entity: "conversation_embedding_status" }, effects: LOCAL_READ })
306
312
  .summary("which conversation vectors are ready or stale")
307
313
  .description("how many chunks of a chat have a vector of the model, how many are left, and what is left costs")
308
314
  .option("--chat <chat>", messenger.chatArgument)).action(async function () {
@@ -316,7 +322,7 @@ export const conversationsCommand = (messenger) => {
316
322
  (status.priceAtMost ? `, at most ${dollars(status.priceAtMost.usd)}` : "") +
317
323
  "\n");
318
324
  });
319
- withModelOptions(destroysNothing(annotate(embed.command("clear"), { effects: LOCAL_WRITE }))
325
+ withModelOptions(destroysNothing(annotate(embed.command("clear"), { output: { entity: "conversation_change" }, effects: LOCAL_WRITE }))
320
326
  .summary("remove stored conversation vectors")
321
327
  .description("drop a chat's vectors, or only one model's; messages and conversations are never touched")
322
328
  .option("--chat <chat>", messenger.chatArgument)).action(async function () {
@@ -324,12 +330,16 @@ export const conversationsCommand = (messenger) => {
324
330
  const chat = chatOf(options);
325
331
  const context = messengerContext(this, messenger);
326
332
  refuseLocalWrite(context, messenger.app.command, EMBED_KEY);
327
- const given = options.model !== undefined || options.provider !== undefined || options.baseUrl !== undefined;
333
+ const given = options.model !== undefined ||
334
+ options.embeddingProvider !== undefined ||
335
+ options.provider !== undefined ||
336
+ options.baseUrl !== undefined;
328
337
  const model = given ? choiceOf(options, messenger, context, { needKey: false }) : undefined;
329
338
  const cleared = await context.withServices((services) => services.embeddings.clear(chat, model));
330
339
  renderAnswer(this, context, itemOf(cleared), () => `${cleared.cleared} vectors dropped\n`);
331
340
  });
332
341
  boundOptions(destroysNothing(annotate(conversations.command("rebuild"), {
342
+ output: { entity: "conversation_preparation" },
333
343
  effects: LOCAL_WRITE,
334
344
  examples: [`${messenger.app.command} conversations rebuild --max-chats 5`],
335
345
  }))
@@ -351,30 +361,34 @@ export const conversationsCommand = (messenger) => {
351
361
  const consents = conversations
352
362
  .command("consents")
353
363
  .description("remembered analysis permissions for this account's chats and provider endpoints");
354
- annotate(consents.command("list"), { effects: LOCAL_READ })
364
+ withQuery(annotate(consents.command("list"), { effects: LOCAL_READ }), ANALYSIS_CONSENTS_QUERY)
355
365
  .description("which chats and provider endpoints you allowed to analyse, and when")
356
- .action(async function () {
366
+ .action(async function (words) {
367
+ const filter = analysisConsentFilter(words);
357
368
  const context = messengerContext(this, messenger);
358
- const items = await context.withStore((store, account) => analysisConsents(store, account).list());
369
+ const items = await context.withStore((store, account) => analysisConsents(store, account).list(filter));
359
370
  renderAnswer(this, context, listOf("conversations consents list", {
360
371
  items: items.map(snakeKeys),
361
372
  limit: Math.max(1, items.length),
362
373
  has_more: false,
363
374
  }));
364
375
  });
365
- annotate(consents.command("revoke"), { effects: LOCAL_WRITE })
376
+ annotate(consents.command("revoke"), { effects: LOCAL_WRITE, output: { entity: "analysis_consent_revocation" } })
366
377
  .description("forget analysis permissions so the next analysis asks again")
367
378
  .option("--chat <chat>", "revoke only this chat's consents; defaults to every chat")
368
- .option("--provider <identity>", "exact provider identity from consents list; defaults to every provider")
379
+ .addOption(new Option("--consent-provider <identity>", "exact provider identity from consents list; defaults to every provider").conflicts("provider"))
380
+ .addOption(new Option("--provider <identity>", "compatibility alias for --consent-provider")
381
+ .hideHelp()
382
+ .conflicts("consentProvider"))
369
383
  .action(async function () {
370
- const { chat, provider } = this.opts();
384
+ const { chat, provider, consentProvider } = this.opts();
371
385
  const context = messengerContext(this, messenger);
372
386
  refuseLocalWrite(context, messenger.app.command, LINKS_KEY);
373
387
  await context.withStore(async (store, account) => {
374
388
  const chatId = chat === undefined
375
389
  ? undefined
376
390
  : (await servicesFor(storedDeps(messenger, store, account, context.guard)).conversations.batchStatus(chat, BATCH_SIZE.default)).chat;
377
- await analysisConsents(store, account).revoke(chatId, provider);
391
+ await analysisConsents(store, account).revoke(chatId, consentProvider ?? provider);
378
392
  });
379
393
  renderAnswer(this, context, itemOf({ revoked: true }));
380
394
  });
@@ -393,7 +407,10 @@ const chatOf = ({ chat }) => {
393
407
  };
394
408
  const withModelOptions = (command) => command
395
409
  .option("--model <model>", "local: a model id from `models text list` (default: e5-small); remote: the provider's model")
396
- .option("--provider <provider>", "embedding provider: local or openai; flags override profile settings")
410
+ .addOption(new Option("--embedding-provider <provider>", "embedding provider: local or openai; flags override profile settings").conflicts("provider"))
411
+ .addOption(new Option("--provider <provider>", "compatibility alias for --embedding-provider")
412
+ .hideHelp()
413
+ .conflicts("embeddingProvider"))
397
414
  .option("--base-url <url>", "a server with OpenAI's /v1/embeddings: Gemini, Jina, or Ollama and LM Studio on this machine")
398
415
  .option("--dims <n>", "remote: the vector size — needed with --base-url; shortens an OpenAI model's", positiveCount("--dims"));
399
416
  /** How much one run over many chats may do: the owner's machine, not a background job, pays for it. */
@@ -412,7 +429,7 @@ const bounds = ({ maxChats, maxChunks }) => ({
412
429
  /** Work nobody named chat by chat never sends chat text off the machine. */
413
430
  const localOnly = (model, what) => {
414
431
  if (typeof model !== "string") {
415
- throw new CliError("validation_error", `${what} uses the model on this machine only — drop --provider and --base-url, or embed one chat with --chat`);
432
+ throw new CliError("validation_error", `${what} uses the model on this machine only — drop --embedding-provider and --base-url, or embed one chat with --chat`);
416
433
  }
417
434
  };
418
435
  const renderRefreshed = (command, context, refreshed) => {
@@ -491,6 +508,7 @@ const answerOf = (text) => {
491
508
  };
492
509
  /** `messages links`: why a message sits where it does in its conversation. */
493
510
  export const linksCommand = (messenger) => annotate(new Command("links"), {
511
+ output: { entity: "message_links" },
494
512
  examples: [`${messenger.app.command} personal messages links "Book club" 101`],
495
513
  effects: LOCAL_READ,
496
514
  })
@@ -526,7 +544,7 @@ const readinessLine = ({ chat, state, graph, pending, vectors }, model) => graph
526
544
  `${pending.deleted} deleted · ${model}: ${vectors.current} current, ${vectors.stale} stale, ` +
527
545
  `${vectors.missing} missing of ${vectors.chunks} chunks`;
528
546
  /** `search conversations`: the conversations nearest to a query, in meaning and in words. */
529
- export const conversationsSearchCommand = (messenger) => syncOptions(boundOptions(withModelOptions(reachesOtherService(annotate(new Command("conversations"), { effects: REMOTE_READ })))), messenger)
547
+ export const conversationsSearchCommand = (messenger) => syncOptions(boundOptions(withModelOptions(reachesOtherService(annotate(new Command("conversations"), { output: { entity: "conversation_hit" }, effects: REMOTE_READ })))), messenger)
530
548
  .summary("find conversations by words and meaning")
531
549
  .description("the conversations nearest to a query in meaning and in words, best first, in one chat or every one — " +
532
550
  "meaning after `conversations embed`; runs on this machine")
@@ -74,7 +74,11 @@ const reportCommand = (messenger) => {
74
74
  `About a given run: ${create} --run <id> (ids: ${lineOf(this, "runs list")})`,
75
75
  ].join("\n"));
76
76
  });
77
- destroysNothing(annotate(report.command("create"), { effects: LOCAL_WRITE, mcp: false }))
77
+ destroysNothing(annotate(report.command("create"), {
78
+ effects: LOCAL_WRITE,
79
+ mcp: false,
80
+ examples: [`${app.command} personal doctor report create --output ./problem-report.json`],
81
+ }))
78
82
  .description("write a problem report to a file, and say where to send it")
79
83
  .option("--run <id>", "the run the report is about; the newest failed one if not given")
80
84
  .option("--output <file>", "where to write it; a new file in this directory if not given")
@@ -0,0 +1,2 @@
1
+ import { type QueryRegistry } from "@wirecat/cli-base/query";
2
+ export declare const DOCUMENT_LINKS_QUERY: QueryRegistry;
@@ -0,0 +1,9 @@
1
+ import { queryFieldsOf } from "@wirecat/cli-base/query";
2
+ import { documentLink } from "../../entities/index.js";
3
+ export const DOCUMENT_LINKS_QUERY = {
4
+ entity: "document_link",
5
+ backend: "native",
6
+ fields: queryFieldsOf(documentLink, { native: ["ref"], examples: { ref: 'ref:"msg:chat/500/7/1"' } }).map((field) => field.native
7
+ ? { ...field, operators: field.operators.filter((operator) => operator === "term" || operator === "phrase") }
8
+ : field),
9
+ };
@@ -18,6 +18,7 @@ import { messengerContext, refuseLocalWrite } from "./context.js";
18
18
  import { stopOnSignal } from "./patience.js";
19
19
  /** `messages download`: every file of one message, or with `--all` of a whole chat, never over a file already there. */
20
20
  export const downloadSubcommand = (messages, messenger) => annotate(messages.command("download"), {
21
+ output: { entity: "message_download" },
21
22
  examples: [`${messenger.app.command} personal messages download "Book club" 101 --output-dir ./downloads`],
22
23
  effects: FETCH,
23
24
  })
@@ -1,7 +1,7 @@
1
1
  import { Command } from "commander";
2
2
  import { type Messenger } from "./context.js";
3
3
  /**
4
- * The owner's way out of a remembered wait or a hold on writes, once they know it is over. No MCP
5
- * tool on purpose: an agent that could lift a hold would send straight into a spam limit again.
4
+ * The owner's way out of a remembered wait or a hold on writes, once they know it is over. An agent gets it only
5
+ * under `mcp.authority`: one that could lift a hold would send straight into a spam limit again.
6
6
  */
7
7
  export declare const floodCommand: (messenger: Messenger) => Command;
@@ -6,13 +6,13 @@ import { grantsAuthority, LOCAL_WRITE } from "../effects.js";
6
6
  import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
7
7
  import { messengerContext } from "./context.js";
8
8
  /**
9
- * The owner's way out of a remembered wait or a hold on writes, once they know it is over. No MCP
10
- * tool on purpose: an agent that could lift a hold would send straight into a spam limit again.
9
+ * The owner's way out of a remembered wait or a hold on writes, once they know it is over. An agent gets it only
10
+ * under `mcp.authority`: one that could lift a hold would send straight into a spam limit again.
11
11
  */
12
12
  export const floodCommand = (messenger) => {
13
13
  const { app } = messenger;
14
14
  const name = messenger.name ?? app.command;
15
- return annotate(new Command("flood"), { mcp: false })
15
+ return new Command("flood")
16
16
  .description(`the waits ${name} asked this profile to keep, and a hold on its writes`)
17
17
  .addCommand(grantsAuthority(annotate(new Command("clear"), { effects: LOCAL_WRITE, examples: [`${app.command} personal flood clear`] }))
18
18
  .summary("clear a profile's stored rate-limit hold")
@@ -21,7 +21,7 @@ const count = (value) => {
21
21
  };
22
22
  export const gapsCommand = (messenger) => {
23
23
  const group = new Command("gaps").description("inspect recorded interior coverage gaps and explicitly fetch them");
24
- annotate(group.command("plan"), { effects: LOCAL_READ })
24
+ annotate(group.command("plan"), { output: { entity: "store_gap_plan" }, effects: LOCAL_READ })
25
25
  .description("local coverage plan; missing message ids alone do not imply missing history")
26
26
  .argument("<chat>", messenger.chatArgument)
27
27
  .action(async function (chat) {
@@ -29,7 +29,7 @@ export const gapsCommand = (messenger) => {
29
29
  renderAnswer(this, context, itemOf(snakeKeys(await context.withServices((services) => services.gaps.plan(chat)))));
30
30
  });
31
31
  const fetching = messenger.fetching ?? FETCHING;
32
- annotate(group.command("repair"), { effects: FETCH })
32
+ annotate(group.command("repair"), { output: { entity: "store_gap_repair" }, effects: FETCH })
33
33
  .description("fetch bounded interior gaps and recheck coverage; never delete unseen messages")
34
34
  .argument("<chat>", messenger.chatArgument)
35
35
  .option("--limit <n>", "total messages in this repair, 500 by default", count)
@@ -5,10 +5,12 @@ import { SendJournal, sendsPathFor } from "../../sends/journal.js";
5
5
  import { RecipientList, recipientsPathFor } from "../../sends/recipients.js";
6
6
  import { FETCH, grantsAuthority, LOCAL_READ, LOCAL_WRITE } from "../effects.js";
7
7
  import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
8
- import { pagedList } from "../list-query.js";
8
+ import { pagedList, typedQuery, withQuery } from "../list-query.js";
9
9
  import { withPaging } from "../paging.js";
10
10
  import { wholeList } from "./chat-answers.js";
11
11
  import { messengerContext } from "./context.js";
12
+ import { RECIPIENTS_QUERY, recipientFilter } from "./recipients-query.js";
13
+ import { SENDS_QUERY, sendFilter } from "./sends-query.js";
12
14
  /**
13
15
  * The chats this profile may send to. Off until the first `add`; `clear` deletes it, which turns it off again. It stops
14
16
  * a model that a message talked into writing somewhere, not an agent set on getting around it.
@@ -17,19 +19,26 @@ export const recipientsCommand = (messenger) => {
17
19
  const tool = `${messenger.app.command} personal`;
18
20
  const listFor = (profile, env) => new RecipientList(recipientsPathFor(messenger.app, profile, env), messenger.app.command);
19
21
  const command = new Command("recipients").description("the chats this profile may send to, when the list is on");
20
- annotate(command.command("list"), { effects: LOCAL_READ, examples: [`${tool} recipients list`] })
22
+ withQuery(annotate(command.command("list"), { examples: [`${tool} recipients list`], effects: LOCAL_READ }), RECIPIENTS_QUERY)
21
23
  .description("the chats on the list; empty and off until the first add")
22
- .action(async function () {
24
+ .action(async function (words) {
25
+ const filter = recipientFilter(words);
23
26
  const context = messengerContext(this, messenger);
24
27
  const { settings, renderer, env } = context;
25
- const chats = listFor(settings.profile, env).read();
26
- renderAnswer(this, context, wholeList("recipients list", (chats ?? []).map(snakeKeys)));
27
- if (!chats)
28
+ const found = listFor(settings.profile, env).list(filter);
29
+ renderAnswer(this, context, wholeList("recipients list", found.items.map(snakeKeys)));
30
+ if (found.state === "off")
28
31
  renderer.note("the recipient list is off — this profile may send to any chat");
29
- else if (chats.length === 0)
32
+ else if (found.state === "empty")
30
33
  renderer.note("the recipient list is on and empty — this profile may send nowhere");
34
+ else if (found.items.length === 0)
35
+ renderer.note("no recipients match the query");
31
36
  });
32
- grantsAuthority(annotate(command.command("add"), { effects: FETCH, examples: [`${tool} recipients add "Book club"`] }))
37
+ grantsAuthority(annotate(command.command("add"), {
38
+ examples: [`${tool} recipients add "Book club"`],
39
+ effects: FETCH,
40
+ output: { entity: "recipient_change", view: "added" },
41
+ }))
33
42
  .argument("<chat>", messenger.chatArgument)
34
43
  .description("allow sending to this chat; the first add turns the list on")
35
44
  .action(async function (chat) {
@@ -44,7 +53,11 @@ export const recipientsCommand = (messenger) => {
44
53
  });
45
54
  renderAnswer(this, context, itemOf({ id: found.id, title: found.title, added }));
46
55
  });
47
- grantsAuthority(annotate(command.command("remove"), { effects: LOCAL_WRITE, examples: [`${tool} recipients remove "Book club"`] }))
56
+ grantsAuthority(annotate(command.command("remove"), {
57
+ examples: [`${tool} recipients remove "Book club"`],
58
+ effects: LOCAL_WRITE,
59
+ output: { entity: "recipient_change", view: "removed" },
60
+ }))
48
61
  .argument("<chat>", "chat id, or the title as the list shows it")
49
62
  .description("stop allowing this chat; the list stays on")
50
63
  .action(async function (chat) {
@@ -55,7 +68,11 @@ export const recipientsCommand = (messenger) => {
55
68
  throw new CliError("not_found", `${chat.trim()} is not on the recipient list of ${settings.profile}`);
56
69
  renderAnswer(this, context, itemOf({ id: gone.id, title: gone.title, removed: true }));
57
70
  });
58
- grantsAuthority(annotate(command.command("clear"), { effects: LOCAL_WRITE, examples: [`${tool} recipients clear`] }))
71
+ grantsAuthority(annotate(command.command("clear"), {
72
+ examples: [`${tool} recipients clear`],
73
+ effects: LOCAL_WRITE,
74
+ output: { entity: "recipient_change", view: "off" },
75
+ }))
59
76
  .description("delete the list, which turns it off: this profile may send to any chat again")
60
77
  .action(async function () {
61
78
  const context = messengerContext(this, messenger);
@@ -65,16 +82,21 @@ export const recipientsCommand = (messenger) => {
65
82
  return command;
66
83
  };
67
84
  /** Every attempt to send from this profile, kept whatever `--record` says. Never the text. */
68
- export const sendsCommand = (messenger) => new Command("sends").description("every attempt to send from this profile — never the text").addCommand(withPaging(annotate(new Command("list"), { effects: LOCAL_READ }).description("attempts to send, newest first: sent, refused, failed, or not known")).action(async function () {
85
+ export const sendsCommand = (messenger) => new Command("sends").description("every attempt to send from this profile — never the text").addCommand(withQuery(withPaging(annotate(new Command("list"), {
86
+ effects: LOCAL_READ,
87
+ examples: [`${messenger.app.command} personal sends list --limit 10`],
88
+ }).description("attempts to send, newest first: sent, refused, failed, or not known")), SENDS_QUERY).action(async function (words) {
89
+ const filter = sendFilter(words);
69
90
  const context = messengerContext(this, messenger);
70
91
  const { settings, renderer, env } = context;
71
- const entries = new SendJournal(sendsPathFor(messenger.app, settings.profile, env)).entries().reverse();
92
+ const entries = new SendJournal(sendsPathFor(messenger.app, settings.profile, env)).entries(filter).reverse();
72
93
  const from = settings.all ? 0 : (settings.page - 1) * settings.limit;
73
94
  const shown = settings.all ? entries : entries.slice(from, from + settings.limit);
74
95
  renderAnswer(this, context, pagedList("sends list", settings, {
75
96
  items: shown.map(snakeKeys),
97
+ args: words.length ? { query: typedQuery(words) } : {},
76
98
  has_more: from + shown.length < entries.length,
77
99
  }));
78
100
  if (entries.length === 0)
79
- renderer.note(`profile ${settings.profile} has not tried to send anything`);
101
+ renderer.note(filter ? "no send attempts match the query" : `profile ${settings.profile} has not tried to send anything`);
80
102
  }));
@@ -2,7 +2,7 @@ import type { Message } from "../../domain/models.js";
2
2
  import { type Hearing } from "../../speech/hearing.js";
3
3
  import type { Messenger, MessengerContext, ReadConnection } from "./context.js";
4
4
  export declare const TRANSCRIBE_OPTION: readonly ["--transcribe", "turn voice messages not heard yet into text — by the messenger where it can, else by a model on this machine; can take minutes"];
5
- export declare const MODEL_OPTION: readonly ["--model <id>", "which downloaded speech model hears them, with --transcribe; `models audio list` shows them"];
5
+ export declare const MODEL_OPTION: readonly ["--model <model>", "which downloaded speech model hears them, with --transcribe; `models audio list` shows them"];
6
6
  /**
7
7
  * Kept transcripts on every read; new ones with `--transcribe`, using the read's connection when
8
8
  * supplied. It is released before local recognition. `undefined` when there is no voice message, and then no file is opened.
@@ -5,7 +5,7 @@ export const TRANSCRIBE_OPTION = [
5
5
  "turn voice messages not heard yet into text — by the messenger where it can, else by a model on this machine; can take minutes",
6
6
  ];
7
7
  export const MODEL_OPTION = [
8
- "--model <id>",
8
+ "--model <model>",
9
9
  "which downloaded speech model hears them, with --transcribe; `models audio list` shows them",
10
10
  ];
11
11
  /**
@@ -13,6 +13,7 @@ const DEFAULT_LIMIT = 100;
13
13
  export const imagesCommand = (messenger) => {
14
14
  const images = new Command("images").description("search pictures by what they show, with a model on this machine");
15
15
  annotate(images.command("embed"), {
16
+ output: { entity: "image_embedding" },
16
17
  effects: FETCH,
17
18
  offline: false,
18
19
  examples: [`${messenger.app.command} images embed`, `${messenger.app.command} images embed --limit 500`],
@@ -1,6 +1,6 @@
1
1
  import { CliError } from "@wirecat/cli-base";
2
2
  import { annotate } from "@wirecat/cli-base/commands";
3
- import { Command } from "commander";
3
+ import { Command, Option } from "commander";
4
4
  import { renderMessages } from "../../render/messages.js";
5
5
  import { CHAT_KINDS } from "../../services/chats.js";
6
6
  import { kindsOf } from "../../services/inbox.js";
@@ -41,7 +41,7 @@ export const inboxCommand = (messenger) => annotate(new Command("inbox"), {
41
41
  .option("--new", "what arrived since the last check, each message once — for scheduled runs")
42
42
  .option("--limit <n>", "at most this many per chat, the newest", positiveCount("--limit"))
43
43
  .option("--all", "muted and archived chats too — left out unless they mention you or reply to you")
44
- .option("--kind <kinds>", `only chats of these kinds, comma-separated: ${CHAT_KINDS.join(", ")}`)
44
+ .addOption(new Option("--kind <kinds>", `compatibility spelling for kind:; ${CHAT_KINDS.join(", ")}`).hideHelp())
45
45
  .option(...TRANSCRIBE_OPTION)
46
46
  .option(...MODEL_OPTION)
47
47
  .addHelpText("after", "To mark a chat read, use `chats mark-read <chat>`. The other side sees it.")
@@ -51,8 +51,10 @@ export const inboxCommand = (messenger) => annotate(new Command("inbox"), {
51
51
  const context = messengerContext(this, messenger);
52
52
  const { app } = messenger;
53
53
  const { settings, renderer, format, env } = context;
54
- const kinds = kind === undefined ? undefined : kindsOf(kind);
55
- const { since, meta } = catchUpQuery(query, INBOX_QUERY, "inbox");
54
+ const { since, meta, kinds: queriedKinds } = catchUpQuery(query, INBOX_QUERY, "inbox");
55
+ if (kind !== undefined && queriedKinds !== undefined)
56
+ throw new CliError("validation_error", "give kind: or its legacy --kind spelling, not both");
57
+ const kinds = queriedKinds ?? (kind === undefined ? undefined : kindsOf(kind));
56
58
  if (fresh && since !== undefined)
57
59
  throw new CliError("validation_error", "--new keeps its own point — not with a date in the query");
58
60
  const saved = fresh && since === undefined
@@ -13,6 +13,7 @@ import { addMediaArchiveTimers } from "./media-archive-timer-command.js";
13
13
  import { stopOnSignal } from "./patience.js";
14
14
  export const addMediaArchiveCommands = (archive, messenger) => {
15
15
  annotate(archive.command("download"), {
16
+ output: { entity: "media_archive" },
16
17
  effects: FETCH,
17
18
  examples: [`${messenger.app.command} attachments download ./media-archive`],
18
19
  })
@@ -54,6 +55,7 @@ export const addMediaArchiveCommands = (archive, messenger) => {
54
55
  }
55
56
  });
56
57
  annotate(archive.command("check"), {
58
+ output: { entity: "media_archive_check" },
57
59
  effects: LOCAL_READ,
58
60
  examples: [`${messenger.app.command} attachments check ./media-archive`],
59
61
  })
@@ -8,6 +8,7 @@ import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
8
8
  import { messengerContext, refuseLocalWrite } from "./context.js";
9
9
  export const addMediaArchiveMove = (attachments, messenger) => {
10
10
  annotate(attachments.command("move"), {
11
+ output: { entity: "media_archive_move" },
11
12
  effects: LOCAL_WRITE,
12
13
  examples: [
13
14
  `${messenger.app.command} attachments move ./media-archive ./older-images --before-time 2026-10-01T00:00:00Z --dry-run`,
@@ -14,8 +14,8 @@ export const addMediaArchiveTimers = (attachments, messenger) => {
14
14
  const archive = attachments.command("jobs").description("daily media archive timers for this profile");
15
15
  for (const action of ["install", "start", "stop", "status", "uninstall"]) {
16
16
  const command = annotate(archive.command(action), {
17
+ output: { entity: "media_archive_timer" },
17
18
  effects: action === "status" ? LOCAL_READ : LOCAL_WRITE,
18
- ...(action === "status" ? {} : { mcp: false }),
19
19
  examples: [`${messenger.app.command} attachments jobs ${action} ./media-archive`],
20
20
  })
21
21
  .description({
@@ -16,6 +16,7 @@ export const mentionsCommand = (messenger) => {
16
16
  const tool = messenger.app.command;
17
17
  const mentions = new Command("mentions").description("phones, e-mail, links, documents, names and addresses in stored messages");
18
18
  annotate(mentions.command("list"), {
19
+ output: { entity: "mention" },
19
20
  effects: LOCAL_READ,
20
21
  query: MENTION_QUERY,
21
22
  examples: [
@@ -55,6 +56,7 @@ export const mentionsCommand = (messenger) => {
55
56
  context.renderer.note("more remain — a larger --limit shows them all and moves the --new point");
56
57
  });
57
58
  annotate(mentions.command("domains"), {
59
+ output: { entity: "mention_domain" },
58
60
  effects: LOCAL_READ,
59
61
  query: MENTION_QUERY,
60
62
  examples: [`${tool} mentions domains`, `${tool} mentions domains status:found`],
@@ -77,7 +79,11 @@ export const mentionsCommand = (messenger) => {
77
79
  `${firstAt.slice(0, 10)}…${lastAt.slice(0, 10)}\n`)
78
80
  .join(""));
79
81
  });
80
- annotate(mentions.command("places"), { effects: LOCAL_READ, examples: [`${tool} mentions places`] })
82
+ annotate(mentions.command("places"), {
83
+ output: { entity: "place" },
84
+ effects: LOCAL_READ,
85
+ examples: [`${tool} mentions places`],
86
+ })
81
87
  .summary("confirmed street addresses, most mentioned first")
82
88
  .description("confirmed addresses, in every account, most mentioned first; `mentions confirm <id>` adds one")
83
89
  .option("--limit <n>", "how many to show", positiveCount("--limit"))
@@ -90,7 +96,11 @@ export const mentionsCommand = (messenger) => {
90
96
  has_more: places.hasMore,
91
97
  }), () => places.items.map(({ id, address, mentions }) => `${id} ${address} ${mentions} mentioned\n`).join(""));
92
98
  });
93
- annotate(mentions.command("show"), { effects: LOCAL_READ, examples: [`${tool} mentions show 12`] })
99
+ annotate(mentions.command("show"), {
100
+ output: { entity: "mention", view: "details" },
101
+ effects: LOCAL_READ,
102
+ examples: [`${tool} mentions show 12`],
103
+ })
94
104
  .description("one mention, the text around it, and how many other places hold its value")
95
105
  .argument("<id>", "the mention's id, from mentions list", positiveCount("<id>"))
96
106
  .action(async function (id) {
@@ -101,6 +111,7 @@ export const mentionsCommand = (messenger) => {
101
111
  (found.candidates.length > 0 ? `may be ${found.candidates.join(", ")}\n` : ""));
102
112
  });
103
113
  annotate(mentions.command("confirm"), {
114
+ output: { entity: "mention_decision" },
104
115
  effects: LOCAL_WRITE,
105
116
  examples: [
106
117
  `${tool} mentions confirm 12 person:7`,
@@ -123,6 +134,7 @@ export const mentionsCommand = (messenger) => {
123
134
  renderAnswer(this, context, itemOf(snakeKeys(decided)));
124
135
  });
125
136
  annotate(mentions.command("reject"), {
137
+ output: { entity: "mention_decision" },
126
138
  effects: LOCAL_WRITE,
127
139
  examples: [`${tool} mentions reject 12`],
128
140
  })
@@ -140,6 +152,7 @@ export const mentionsCommand = (messenger) => {
140
152
  renderAnswer(this, context, itemOf(snakeKeys(decided)));
141
153
  });
142
154
  destroysNothing(annotate(mentions.command("rebuild"), {
155
+ output: { entity: "mention_rebuild" },
143
156
  effects: LOCAL_WRITE,
144
157
  examples: [`${tool} mentions rebuild`, `${tool} mentions rebuild person-name`],
145
158
  }))
@@ -110,6 +110,7 @@ export const messagesCommand = (messenger) => {
110
110
  };
111
111
  messages.addCommand(sendCommand(messenger));
112
112
  annotate(messages.command("show"), {
113
+ output: { entity: "message" },
113
114
  examples: [`${messenger.app.command} personal messages show "Book club" 101`],
114
115
  effects: REMOTE_READ,
115
116
  })
@@ -122,6 +123,7 @@ export const messagesCommand = (messenger) => {
122
123
  await readWindow(this, chat, message, { before: 0, after: 0 });
123
124
  });
124
125
  threadOptions(annotate(messages.command("context"), {
126
+ output: { entity: "message_context" },
125
127
  examples: [`${messenger.app.command} personal messages context "Book club" 101 --before-n 3 --after-n 3`],
126
128
  effects: REMOTE_READ,
127
129
  }))
@@ -14,6 +14,7 @@ import { messengerContext } from "./context.js";
14
14
  export const deleteCommand = (messenger) => annotate(new Command("delete"), {
15
15
  examples: [`${messenger.app.command} personal messages delete "Book club" 101`],
16
16
  effects: REMOTE_WRITE,
17
+ output: { entity: "message_deletion" },
17
18
  })
18
19
  .description("delete messages for you only; with --for-everyone, for everyone in the chat")
19
20
  .argument("<chat>", messenger.chatArgument)