@wirecat/cli-core 0.396.0 → 0.397.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 (75) hide show
  1. package/CHANGELOG.md +33 -1
  2. package/README.md +1 -0
  3. package/dist/background/daily-archive-timer.d.ts +40 -0
  4. package/dist/background/daily-archive-timer.js +181 -0
  5. package/dist/background/index.d.ts +2 -0
  6. package/dist/background/index.js +1 -0
  7. package/dist/cli/messenger/account-command.js +1 -0
  8. package/dist/cli/messenger/account-sessions-command.js +3 -1
  9. package/dist/cli/messenger/admin-commands.js +1 -0
  10. package/dist/cli/messenger/admin-contacts-command.js +9 -3
  11. package/dist/cli/messenger/archive-commands.js +3 -1
  12. package/dist/cli/messenger/attachments-command.js +17 -7
  13. package/dist/cli/messenger/backfill-command.js +4 -0
  14. package/dist/cli/messenger/chats-command.js +1 -0
  15. package/dist/cli/messenger/chats-members-command.js +4 -0
  16. package/dist/cli/messenger/chats-stats-command.js +1 -0
  17. package/dist/cli/messenger/chats-tracking-command.js +4 -1
  18. package/dist/cli/messenger/complete-command.js +1 -1
  19. package/dist/cli/messenger/contacts-command.js +9 -3
  20. package/dist/cli/messenger/conversations-command.js +18 -1
  21. package/dist/cli/messenger/counters-command.js +1 -0
  22. package/dist/cli/messenger/download-command.js +1 -0
  23. package/dist/cli/messenger/flood-command.js +1 -0
  24. package/dist/cli/messenger/guard-commands.js +5 -4
  25. package/dist/cli/messenger/inbox.js +1 -0
  26. package/dist/cli/messenger/mcp-command.js +6 -2
  27. package/dist/cli/messenger/media-archive-command.d.ts +3 -0
  28. package/dist/cli/messenger/media-archive-command.js +72 -0
  29. package/dist/cli/messenger/media-archive-move-command.d.ts +3 -0
  30. package/dist/cli/messenger/media-archive-move-command.js +40 -0
  31. package/dist/cli/messenger/media-archive-timer-command.d.ts +3 -0
  32. package/dist/cli/messenger/media-archive-timer-command.js +70 -0
  33. package/dist/cli/messenger/messages-comments-command.js +1 -0
  34. package/dist/cli/messenger/messages-delete-command.js +1 -1
  35. package/dist/cli/messenger/messages-search-command.js +1 -0
  36. package/dist/cli/messenger/messages-stats-command.js +1 -0
  37. package/dist/cli/messenger/models-command.js +3 -0
  38. package/dist/cli/messenger/private-people-command.js +12 -10
  39. package/dist/cli/messenger/rankings-command.js +2 -0
  40. package/dist/cli/messenger/reactions-command.js +8 -2
  41. package/dist/cli/messenger/retention-command.js +1 -0
  42. package/dist/cli/messenger/review.js +1 -0
  43. package/dist/cli/messenger/search-command.js +5 -1
  44. package/dist/cli/messenger/searches-command.js +24 -7
  45. package/dist/cli/messenger/server-command.js +7 -2
  46. package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
  47. package/dist/cli/messenger/store-maintenance-command.js +7 -0
  48. package/dist/cli/messenger/tags-command.js +6 -2
  49. package/dist/cli/messenger/tasks-command.js +10 -7
  50. package/dist/cli/messenger/transcribe-command.js +1 -0
  51. package/dist/cli/messenger/watch-command.js +1 -0
  52. package/dist/entities/contact-read.d.ts +119 -0
  53. package/dist/entities/contact-read.js +50 -0
  54. package/dist/entities/index.d.ts +120 -1
  55. package/dist/entities/index.js +5 -1
  56. package/dist/meetings/mcp/index.d.ts +15 -15
  57. package/dist/parity/catalogue.js +1 -1
  58. package/dist/parity/manifest.d.ts +3 -1
  59. package/dist/parity/manifest.js +2 -0
  60. package/dist/parity/wording.js +2 -0
  61. package/dist/sends/permissions.js +7 -0
  62. package/dist/services/index.d.ts +5 -0
  63. package/dist/services/index.js +2 -0
  64. package/dist/services/media-archive-files.d.ts +10 -0
  65. package/dist/services/media-archive-files.js +110 -0
  66. package/dist/services/media-archive-locks.d.ts +6 -0
  67. package/dist/services/media-archive-locks.js +71 -0
  68. package/dist/services/media-archive-manifest.d.ts +29 -0
  69. package/dist/services/media-archive-manifest.js +116 -0
  70. package/dist/services/media-archive-move.d.ts +21 -0
  71. package/dist/services/media-archive-move.js +163 -0
  72. package/dist/services/media-archive.d.ts +34 -0
  73. package/dist/services/media-archive.js +165 -0
  74. package/package.json +1 -1
  75. package/parity.json +50 -1
@@ -34,6 +34,7 @@ const maxMeetingsOf = (value) => {
34
34
  };
35
35
  const allCommand = (messenger) => {
36
36
  const command = annotate(new Command("all"), { effects: REMOTE_READ, partial: true })
37
+ .summary("search stored messages, notes and selected meeting transcripts")
37
38
  .description((messenger.serverSearch
38
39
  ? "search messenger messages and notes in the local store, and the messenger's server for messages " +
39
40
  "(--backend; notes are local only)"
@@ -95,6 +96,7 @@ const allCommand = (messenger) => {
95
96
  });
96
97
  };
97
98
  const notesCommand = (messenger) => annotate(new Command("notes"), { effects: LOCAL_READ, partial: true, output: { entity: "note", view: "hit" } })
99
+ .summary("find stored notes by words and filters")
98
100
  .description("search the notes — written in memo, or imported from a notes folder — by words and, with the local " +
99
101
  "text model, by meaning; each hit says which found it and what it links to")
100
102
  .argument("<query...>", 'strict Lucene query: words, "phrases", AND/OR/NOT, tag:, source:internal (written in memo) or source:file ' +
@@ -150,7 +152,9 @@ const notesCommand = (messenger) => annotate(new Command("notes"), { effects: LO
150
152
  * hierarchy"). `topics` only where the CLI has forum topics.
151
153
  */
152
154
  export const searchCommand = (messenger, { topics = false } = {}) => {
153
- const search = new Command("search").description("find things by text: one resource when you know it (messages, notes), or search all across messages and notes; for mail, the separate memo CLI: memo search mail");
155
+ const search = new Command("search")
156
+ .summary("search the local archive")
157
+ .description("find things by text: one resource when you know it (messages, notes), or search all across messages and notes; for mail, the separate memo CLI: memo search mail");
154
158
  search
155
159
  .addCommand(allCommand(messenger))
156
160
  .addCommand(messagesSearchCommand(messenger))
@@ -24,8 +24,16 @@ const line = ({ id, name, command, params, runs, lastRunAt }) => [
24
24
  export const SEARCHES_QUERY = unfilteredQuery("saved_search", savedSearch);
25
25
  /** Saved searches and the history of `search messages` and `stats messages show`, in the local store only. */
26
26
  export const searchesCommand = (messenger) => {
27
- const searches = new Command("searches").description("saved searches and the history of search messages and stats messages show, kept in the local store; --saved runs one");
28
- annotate(searches.command("create"), { effects: LOCAL_WRITE, output: { entity: "saved_search" } })
27
+ const tool = `${messenger.app.command} personal`;
28
+ const searches = new Command("searches")
29
+ .summary("saved searches and their run history")
30
+ .description("saved searches and the history of search messages and stats messages show, kept in the local store; --saved runs one");
31
+ annotate(searches.command("create"), {
32
+ effects: LOCAL_WRITE,
33
+ output: { entity: "saved_search" },
34
+ examples: [`${tool} searches create project-drafts draft --chat "Project room"`],
35
+ })
36
+ .summary("save a search and its query")
29
37
  .description("save a search under a name without running it; search messages --saved <name> runs it")
30
38
  .argument("<name>", "up to 64 letters a–z, digits and hyphens, not only digits")
31
39
  .argument("[query...]", "the query, as for search messages; none matches every stored message")
@@ -64,7 +72,11 @@ export const searchesCommand = (messenger) => {
64
72
  const saved = await context.withServices((services) => services.searches.create(name, params, { replace: replace === true }));
65
73
  renderAnswer(this, context, itemOf(savedSearchItem(saved)), () => `${line(saved)}\n`);
66
74
  });
67
- annotate(searches.command("show"), { effects: REMOTE_READ, output: { entity: "saved_search" } })
75
+ annotate(searches.command("show"), {
76
+ effects: REMOTE_READ,
77
+ output: { entity: "saved_search" },
78
+ examples: [`${tool} searches show project-drafts`],
79
+ })
68
80
  .description("one saved search or earlier run: its query, options and how often it ran")
69
81
  .argument("<name|id>", "a saved search's name, or the id of any row of searches history")
70
82
  .action(async function (reference) {
@@ -72,7 +84,7 @@ export const searchesCommand = (messenger) => {
72
84
  const found = await context.withServices((services) => services.searches.show(reference));
73
85
  renderAnswer(this, context, itemOf(savedSearchItem(found)), () => `${line(found)}\n`);
74
86
  });
75
- withQuery(annotate(searches.command("list"), { effects: LOCAL_READ }), SEARCHES_QUERY)
87
+ withQuery(annotate(searches.command("list"), { effects: LOCAL_READ, examples: [`${tool} searches list`] }), SEARCHES_QUERY)
76
88
  .description("the saved searches, by name")
77
89
  .action(async function (words) {
78
90
  const context = messengerContext(this, messenger);
@@ -83,9 +95,10 @@ export const searchesCommand = (messenger) => {
83
95
  if (found.length === 0 && context.format === "pretty")
84
96
  context.renderer.note("no saved searches — `searches create <name> <query>` saves one");
85
97
  });
86
- annotate(withPaging(annotate(searches.command("history"), { effects: LOCAL_READ })), {
98
+ annotate(withPaging(annotate(searches.command("history"), { effects: LOCAL_READ, examples: [`${tool} searches history --limit 10`] })), {
87
99
  output: { entity: "saved_search" },
88
100
  })
101
+ .summary("past searches and counts, without their results")
89
102
  .description("the searches and counts that ran, newest first — saved ones included; never their results")
90
103
  .action(async function () {
91
104
  const context = messengerContext(this, messenger);
@@ -98,7 +111,11 @@ export const searchesCommand = (messenger) => {
98
111
  if (found.items.length === 0 && context.format === "pretty")
99
112
  context.renderer.note("no searches ran yet");
100
113
  });
101
- annotate(searches.command("delete"), { effects: LOCAL_WRITE, output: { entity: "saved_search" } })
114
+ annotate(searches.command("delete"), {
115
+ effects: LOCAL_WRITE,
116
+ output: { entity: "saved_search" },
117
+ examples: [`${tool} searches delete project-drafts`],
118
+ })
102
119
  .description("delete a saved search, or one run from the history")
103
120
  .argument("<name|id>", "a saved search's name, or the id of any row of searches history")
104
121
  .action(async function (reference) {
@@ -107,7 +124,7 @@ export const searchesCommand = (messenger) => {
107
124
  const deleted = await context.withServices((services) => services.searches.delete(reference));
108
125
  renderAnswer(this, context, itemOf(savedSearchItem(deleted)), () => `deleted ${deleted.name ?? `run ${deleted.id}`}\n`);
109
126
  });
110
- annotate(searches.command("clear"), { effects: LOCAL_WRITE })
127
+ annotate(searches.command("clear"), { effects: LOCAL_WRITE, examples: [`${tool} searches clear`] })
111
128
  .description("empty the history; saved searches stay")
112
129
  .action(async function () {
113
130
  const context = messengerContext(this, messenger);
@@ -60,7 +60,9 @@ const lockProcess = (app, marker, serveArgv) => (context, system, logPath) => ({
60
60
  */
61
61
  export const serverCommand = (messenger, options = {}) => {
62
62
  const { app } = messenger;
63
- const command = annotate(new Command("server"), { mcp: false }).description(`\`${app.command} serve\` in the background: start, stop, restart, status, logs; install adds a systemd or launchd unit`);
63
+ const command = annotate(new Command("server"), { mcp: false })
64
+ .summary("manage this profile's background server")
65
+ .description(`\`${app.command} serve\` in the background: start, stop, restart, status, logs; install adds a systemd or launchd unit`);
64
66
  const marker = (profile) => `${app.envPrefix}_SERVER=${profile}`;
65
67
  const serveArgv = options.serveArgv ?? ["serve"];
66
68
  const prepare = (self) => {
@@ -181,7 +183,9 @@ export const serverCommand = (messenger, options = {}) => {
181
183
  return ["--idle", idle];
182
184
  };
183
185
  const withIdle = (sub) => options.idle ? sub.option("--idle <duration>", "stop after this long with nobody using it — 15m, 1h") : sub;
184
- withIdle(destroysNothing(annotate(command.command("start"), { effects: LOCAL_WRITE, examples: [`${app.command} personal server start`] })).description("start serve in the background — through the unit if one is installed — and answer once it connects")).action(async function () {
186
+ withIdle(destroysNothing(annotate(command.command("start"), { effects: LOCAL_WRITE, examples: [`${app.command} personal server start`] }))
187
+ .summary("start this profile's background server")
188
+ .description("start serve in the background — through the unit if one is installed — and answer once it connects")).action(async function () {
185
189
  await start(prepare(this), idleArgs(this));
186
190
  });
187
191
  destroysNothing(annotate(command.command("stop"), { effects: LOCAL_WRITE, examples: [`${app.command} personal server stop`] }))
@@ -199,6 +203,7 @@ export const serverCommand = (messenger, options = {}) => {
199
203
  await start(prepared, args);
200
204
  });
201
205
  annotate(command.command("status"), { effects: LOCAL_READ, examples: [`${app.command} personal server status`] })
206
+ .summary("this profile's background-server status")
202
207
  .description("whether serve runs for this profile, since when, who started it, and the unit if there is one")
203
208
  .action(async function () {
204
209
  const prepared = prepare(this);
@@ -2,9 +2,9 @@ import { Command } from "commander";
2
2
  import type { Messenger } from "./context.js";
3
3
  /** `doctor`'s short summary of the store. Must answer for a broken file, so an error is a field. */
4
4
  export declare const storeSummary: (env: NodeJS.ProcessEnv) => Promise<{
5
- error?: undefined;
6
5
  path: string;
7
6
  exists: boolean;
7
+ error?: undefined;
8
8
  } | {
9
9
  path: string;
10
10
  exists: boolean;
@@ -93,6 +93,7 @@ const refuseWhileServing = (command, messenger) => {
93
93
  }
94
94
  };
95
95
  const repairCommand = (messenger) => annotate(new Command("repair"), { effects: LOCAL_WRITE, mcp: false })
96
+ .summary("repair table shapes while keeping the old tables")
96
97
  .description("bring every table to this build's shape, deleting nothing: a table of the wrong shape is kept as a copy beside a new one")
97
98
  .option("--dry-run", "say what it would do, and change nothing")
98
99
  .action(async function () {
@@ -152,6 +153,7 @@ const copiesCommand = () => new Command("copies").description("the tables `store
152
153
  result(this, { path, deleted });
153
154
  }));
154
155
  const infoCommand = () => annotate(new Command("info"), { effects: LOCAL_READ, mcp: false })
156
+ .summary("the local archive's format, size and contents")
155
157
  .description("the store file: where it is, its size, its schema and how many rows it holds; changes nothing")
156
158
  .action(async function () {
157
159
  const path = storePath(environmentOf(this).env ?? process.env);
@@ -181,6 +183,7 @@ const infoCommand = () => annotate(new Command("info"), { effects: LOCAL_READ, m
181
183
  * newest message held, not `sync_ranges`: those are in message ids, which a chat list does not give.
182
184
  */
183
185
  const checkCommand = (messenger) => annotate(new Command("check"), { effects: LOCAL_READ, mcp: false })
186
+ .summary("check the local archive for problems")
184
187
  .description("whether the store is healthy — integrity, search indexes, disk, and which chats are behind")
185
188
  .action(async function () {
186
189
  const { renderer } = outputFor(this);
@@ -360,6 +363,7 @@ const chatsBehind = (database) => database
360
363
  refreshed: isoOf(row.refreshed),
361
364
  }));
362
365
  const migrateCommand = (messenger) => annotate(new Command("migrate"), { effects: LOCAL_WRITE, mcp: false })
366
+ .summary("migrate an older local archive")
363
367
  .description("bring the store up to this build's schema, then normalize, index and stem the messages and notes stored before it")
364
368
  .action(async function () {
365
369
  const { renderer } = outputFor(this);
@@ -428,6 +432,7 @@ const buildNoteIndex = (database, note, { reset = false } = {}) => {
428
432
  return { notesIndexed: drainNoteIndex(database, stemmerCache()) };
429
433
  };
430
434
  const reindexCommand = (messenger) => destroysNothing(annotate(new Command("reindex"), { effects: LOCAL_WRITE, mcp: false }))
435
+ .summary("rebuild the local archive's search indexes")
431
436
  .description("rebuild the word index, its typo vocabulary, the stems, the files' word index, the notes' indexes and who took part in what, from what is stored; loses nothing")
432
437
  .action(async function () {
433
438
  const { renderer } = outputFor(this);
@@ -540,6 +545,7 @@ const decryptCommand = () => annotate(new Command("decrypt"), { effects: LOCAL_W
540
545
  * `serve` runs: that opens the store on its first write, so until then it holds nothing to see.
541
546
  */
542
547
  const restoreCommand = (messenger) => annotate(new Command("restore"), { effects: LOCAL_WRITE, mcp: false })
548
+ .summary("restore a backup while keeping the current store")
543
549
  .description("put a backup in place of the store; the store it replaces is kept beside it, never deleted")
544
550
  .argument("<file>", "a file `store backup` wrote; one written with --encrypt asks for its password")
545
551
  .action(async function (file) {
@@ -656,6 +662,7 @@ const quiesce = async (path, messenger, then, warn, waitMs = STORE_LOCK_WAIT_MS)
656
662
  * schema. The backup is made before anything is deleted, and its path is said before the delete.
657
663
  */
658
664
  const resetCommand = (messenger) => annotate(new Command("reset"), { effects: LOCAL_WRITE, mcp: false })
665
+ .summary("back up the local archive and replace it with an empty one")
659
666
  .description("back the store up beside itself, then delete it and start an empty one at this build's schema; asks first, or --yes")
660
667
  .option("--no-backup", "delete the store without backing it up first")
661
668
  .action(async function ({ backup: keep }) {
@@ -29,7 +29,9 @@ const sourceOf = (value) => {
29
29
  /** The owner's labels, in the local store only: `tag:` in a search finds what they label. */
30
30
  export const tagsCommand = (messenger) => {
31
31
  const tool = `${messenger.app.command} personal`;
32
- const tags = new Command("tags").description("your own labels on chats, people, messages and tasks, kept in the local store and never sent; tag: in a search finds them");
32
+ const tags = new Command("tags")
33
+ .summary("tags on stored messages and other records")
34
+ .description("your own labels on chats, people, messages and tasks, kept in the local store and never sent; tag: in a search finds them");
33
35
  changesStore(annotate(tags.command("auto"), { effects: FETCH, examples: [`${tool} tags auto --chat "Book club" --dry-run`] }))
34
36
  .description("derive local group/channel tags from cached metadata using keyword rules")
35
37
  .option("--chat <chat>", "a stored group/channel; repeat to select several", (value, previous) => [...previous, value], [])
@@ -73,7 +75,9 @@ export const tagsCommand = (messenger) => {
73
75
  withQuery(annotate(tags.command("list"), {
74
76
  effects: LOCAL_READ,
75
77
  examples: [`${tool} tags list`, `${tool} tags list tag:reading`],
76
- }).description("what is tagged: this account's chats, messages and tasks, and the people of its messenger"), TAGGING_QUERY).action(async function (words) {
78
+ })
79
+ .summary("tagged chats, people, messages and tasks")
80
+ .description("what is tagged: this account's chats, messages and tasks, and the people of its messenger"), TAGGING_QUERY).action(async function (words) {
77
81
  const context = messengerContext(this, messenger);
78
82
  const query = listQuery(typedQuery(words), TAGGING_QUERY, "tags list");
79
83
  const found = await context.withServices((services) => services.tags.list({ ...(query ? { query } : {}), ...pageOf(context.settings) }));
@@ -129,7 +129,9 @@ export const tasksCommand = (messenger) => {
129
129
  const writerOf = (command) => readOnlyLockOf(messenger.app, environmentOf(command).env ?? process.env) || environmentOf(command).agent
130
130
  ? "agent"
131
131
  : "owner";
132
- const tasks = new Command("tasks").description("what waits on you — unanswered questions, mentions, requests, promises — kept in the local store; review and serve add them");
132
+ const tasks = new Command("tasks")
133
+ .summary("tasks found or kept in the local archive")
134
+ .description("what waits on you — unanswered questions, mentions, requests, promises — kept in the local store; review and serve add them");
133
135
  withQuery(annotate(tasks.command("list"), {
134
136
  effects: LOCAL_READ,
135
137
  examples: [`${tool} personal tasks list --limit 10`],
@@ -283,8 +285,8 @@ export const tasksCommand = (messenger) => {
283
285
  }))
284
286
  .summary("two tasks are not the same job: the pair is never offered again")
285
287
  .description("two tasks are not the same job: the pair leaves the list and is never offered again")
286
- .argument("<dup>", "the task listed as the duplicate, by its id or key")
287
- .argument("<task>", "the task it was paired with")
288
+ .argument("<task>", "the task listed as the duplicate, by its id or key")
289
+ .argument("<other-task>", "the task it was paired with")
288
290
  .action(decided("rejected", "tasks.duplicates.reject"));
289
291
  destroysNothing(annotate(duplicates.command("defer"), {
290
292
  effects: LOCAL_WRITE,
@@ -292,14 +294,14 @@ export const tasksCommand = (messenger) => {
292
294
  }))
293
295
  .summary("the fields and the text cannot tell: leave the pair to the owner")
294
296
  .description("the fields and the text cannot tell: leave the pair to the owner, who lists it with decision:unsure")
295
- .argument("<dup>", "the task listed as the duplicate, by its id or key")
296
- .argument("<task>", "the task it was paired with")
297
+ .argument("<task>", "the task listed as the duplicate, by its id or key")
298
+ .argument("<other-task>", "the task it was paired with")
297
299
  .action(decided("unsure", "tasks.duplicates.defer"));
298
300
  destroysNothing(annotate(tasks.command("merge"), { effects: LOCAL_WRITE, examples: [`${tool} tasks merge PR-14 --into PR-12`] }))
299
301
  .summary("one job seen twice: fold the duplicate into the task that stays")
300
302
  .description("one job seen twice: link every message of the duplicate to the task and close the duplicate dismissed, " +
301
303
  "duplicate-of the task; nothing is deleted, and tasks unmerge undoes it")
302
- .argument("<dup>", "the duplicate, by its id or key; it must be open")
304
+ .argument("<task>", "the duplicate, by its id or key; it must be open")
303
305
  .requiredOption("--into <id>", "the task that stays, by its id or key")
304
306
  .action(async function (dup) {
305
307
  const context = messengerContext(this, messenger);
@@ -312,7 +314,7 @@ export const tasksCommand = (messenger) => {
312
314
  destroysNothing(annotate(tasks.command("unmerge"), { effects: LOCAL_WRITE, examples: [`${tool} tasks unmerge PR-14`] }))
313
315
  .summary("undo a merge: reopen the task and remove its duplicate-of relation")
314
316
  .description("undo a merge: reopen the task and remove its duplicate-of relation; messages the merge linked stay linked")
315
- .argument("<dup>", "the merged task, by its id or key")
317
+ .argument("<task>", "the merged task, by its id or key")
316
318
  .action(async function (dup) {
317
319
  const context = messengerContext(this, messenger);
318
320
  refuseLocalWrite(context, messenger.app.command, "tasks.unmerge");
@@ -417,6 +419,7 @@ export const tasksCommand = (messenger) => {
417
419
  ],
418
420
  }))
419
421
  .summary("close a task: done, or dismissed when it needs no answer; an agent's unsure close waits on the owner")
422
+ .summary("close a task as done or dismissed")
420
423
  .description("close a task: done, or dismissed when it needs no answer. An agent (AI_AGENT or CLAUDECODE set) states its " +
421
424
  "--certainty; below config task_agent_close_min, or with task_agent_close off, the task stays open and the " +
422
425
  "close waits on the owner, who confirms it with tasks close or refuses it with tasks reject. A closed task " +
@@ -12,6 +12,7 @@ export const transcribeSubcommand = (messages, messenger) => annotate(messages.c
12
12
  examples: [`${messenger.app.command} personal messages transcribe "Book club" 101`],
13
13
  effects: REMOTE_READ,
14
14
  })
15
+ .summary("transcribe one voice message")
15
16
  .description(`a voice message as text — by ${messenger.name ?? messenger.app.command} where it can, else by a model on this machine`)
16
17
  .argument("<chat>", messenger.chatArgument)
17
18
  .argument("<message>", "the id of a voice message")
@@ -12,6 +12,7 @@ import { messengerContext } from "./context.js";
12
12
  * because a stream is not one value. Nothing is marked read.
13
13
  */
14
14
  export const watchCommand = (messenger) => annotate(new Command("watch"), { effects: REMOTE_READ, lifetime: "persistent" })
15
+ .summary("stream new messages until interrupted or timed out")
15
16
  .description("print new messages as they arrive, until Ctrl-C or --timeout (either ends it normally)")
16
17
  .option("--events", "also edits, deletions, reactions, poll votes and chat events; every line then names its event")
17
18
  .action(async function () {
@@ -0,0 +1,119 @@
1
+ import * as v from "valibot";
2
+ export declare const contactLookup: v.StrictObjectSchema<{
3
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
4
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5
+ readonly username: v.NullableSchema<v.StringSchema<undefined>, undefined>;
6
+ }, undefined>;
7
+ export declare const contactSync: v.StrictObjectSchema<{
8
+ readonly added: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
9
+ readonly changed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
10
+ readonly known: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
11
+ }, undefined>;
12
+ export declare const contactProfile: v.StrictObjectSchema<{
13
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
14
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
15
+ readonly usernames: v.ArraySchema<v.StringSchema<undefined>, undefined>;
16
+ readonly bio: v.NullableSchema<v.StringSchema<undefined>, undefined>;
17
+ readonly birthday: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
18
+ readonly phone: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
19
+ readonly flags: Omit<v.StrictObjectSchema<{
20
+ readonly bot: v.BooleanSchema<undefined>;
21
+ readonly verified: v.BooleanSchema<undefined>;
22
+ readonly premium: v.BooleanSchema<undefined>;
23
+ readonly scam: v.BooleanSchema<undefined>;
24
+ readonly fake: v.BooleanSchema<undefined>;
25
+ readonly restricted: v.BooleanSchema<undefined>;
26
+ readonly deleted: v.BooleanSchema<undefined>;
27
+ readonly support: v.BooleanSchema<undefined>;
28
+ }, undefined>, "entries" | "~run" | "~standard" | "~types"> & {
29
+ readonly entries: {
30
+ readonly bot: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
31
+ readonly verified: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
32
+ readonly premium: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
33
+ readonly scam: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
34
+ readonly fake: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
35
+ readonly restricted: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
36
+ readonly deleted: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
37
+ readonly support: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
38
+ };
39
+ readonly "~standard": v.StandardProps<{
40
+ bot?: boolean | undefined;
41
+ verified?: boolean | undefined;
42
+ premium?: boolean | undefined;
43
+ scam?: boolean | undefined;
44
+ fake?: boolean | undefined;
45
+ restricted?: boolean | undefined;
46
+ deleted?: boolean | undefined;
47
+ support?: boolean | undefined;
48
+ }, {
49
+ bot?: boolean | undefined;
50
+ verified?: boolean | undefined;
51
+ premium?: boolean | undefined;
52
+ scam?: boolean | undefined;
53
+ fake?: boolean | undefined;
54
+ restricted?: boolean | undefined;
55
+ deleted?: boolean | undefined;
56
+ support?: boolean | undefined;
57
+ }>;
58
+ readonly "~run": (dataset: v.UnknownDataset, config: v.Config<v.BaseIssue<unknown>>) => v.OutputDataset<{
59
+ bot?: boolean | undefined;
60
+ verified?: boolean | undefined;
61
+ premium?: boolean | undefined;
62
+ scam?: boolean | undefined;
63
+ fake?: boolean | undefined;
64
+ restricted?: boolean | undefined;
65
+ deleted?: boolean | undefined;
66
+ support?: boolean | undefined;
67
+ }, v.BooleanIssue | v.StrictObjectIssue>;
68
+ readonly "~types"?: {
69
+ readonly input: {
70
+ bot?: boolean | undefined;
71
+ verified?: boolean | undefined;
72
+ premium?: boolean | undefined;
73
+ scam?: boolean | undefined;
74
+ fake?: boolean | undefined;
75
+ restricted?: boolean | undefined;
76
+ deleted?: boolean | undefined;
77
+ support?: boolean | undefined;
78
+ };
79
+ readonly output: {
80
+ bot?: boolean | undefined;
81
+ verified?: boolean | undefined;
82
+ premium?: boolean | undefined;
83
+ scam?: boolean | undefined;
84
+ fake?: boolean | undefined;
85
+ restricted?: boolean | undefined;
86
+ deleted?: boolean | undefined;
87
+ support?: boolean | undefined;
88
+ };
89
+ readonly issue: v.BooleanIssue | v.StrictObjectIssue;
90
+ } | undefined;
91
+ };
92
+ readonly seen: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
93
+ readonly contact: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
94
+ readonly mutual_contact: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
95
+ readonly common_chats_count: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
96
+ readonly registered: v.OptionalSchema<v.NullableSchema<v.StrictObjectSchema<{
97
+ readonly at: v.StringSchema<undefined>;
98
+ readonly source: v.PicklistSchema<["telegram", "max", "estimate"], undefined>;
99
+ readonly precision: v.PicklistSchema<["day", "month"], undefined>;
100
+ }, undefined>, undefined>, undefined>;
101
+ readonly has_photo: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
102
+ readonly chats: v.ArraySchema<v.StrictObjectSchema<{
103
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
104
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
105
+ readonly kind: v.PicklistSchema<["dialog", "group", "channel", "saved", "unknown"], undefined>;
106
+ readonly their_messages: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
107
+ readonly first_at: 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>;
108
+ readonly last_at: 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>;
109
+ readonly complete: v.BooleanSchema<undefined>;
110
+ }, undefined>, undefined>;
111
+ readonly aliases: v.ArraySchema<v.StrictObjectSchema<{
112
+ readonly name: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
113
+ readonly username: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
114
+ readonly link: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
115
+ readonly first_seen_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`">]>;
116
+ readonly last_seen_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`">]>;
117
+ readonly source: v.PicklistSchema<["profile", "messages"], undefined>;
118
+ }, undefined>, undefined>;
119
+ }, undefined>;
@@ -0,0 +1,50 @@
1
+ import * as v from "valibot";
2
+ import { chat } from "./chat.js";
3
+ import { count, id, text, time } from "./fields.js";
4
+ export const contactLookup = v.strictObject({ id, name: v.nullable(text), username: v.nullable(text) });
5
+ export const contactSync = v.strictObject({ added: count, changed: count, known: count });
6
+ export const contactProfile = v.strictObject({
7
+ id,
8
+ name: v.nullable(text),
9
+ usernames: v.array(text),
10
+ bio: v.nullable(text),
11
+ birthday: v.optional(v.nullable(text)),
12
+ phone: v.optional(v.nullable(text)),
13
+ flags: v.partial(v.strictObject({
14
+ bot: v.boolean(),
15
+ verified: v.boolean(),
16
+ premium: v.boolean(),
17
+ scam: v.boolean(),
18
+ fake: v.boolean(),
19
+ restricted: v.boolean(),
20
+ deleted: v.boolean(),
21
+ support: v.boolean(),
22
+ })),
23
+ seen: v.optional(text),
24
+ contact: v.optional(v.boolean()),
25
+ mutual_contact: v.optional(v.boolean()),
26
+ common_chats_count: v.optional(v.nullable(count)),
27
+ registered: v.optional(v.nullable(v.strictObject({
28
+ at: text,
29
+ source: v.picklist(["telegram", "max", "estimate"]),
30
+ precision: v.picklist(["day", "month"]),
31
+ }))),
32
+ has_photo: v.optional(v.boolean()),
33
+ chats: v.array(v.strictObject({
34
+ id,
35
+ title: v.nullable(text),
36
+ kind: chat.entries.kind,
37
+ their_messages: count,
38
+ first_at: v.nullable(time),
39
+ last_at: v.nullable(time),
40
+ complete: v.boolean(),
41
+ })),
42
+ aliases: v.array(v.strictObject({
43
+ name: v.optional(text),
44
+ username: v.optional(text),
45
+ link: v.optional(text),
46
+ first_seen_at: time,
47
+ last_seen_at: time,
48
+ source: v.picklist(["profile", "messages"]),
49
+ })),
50
+ });
@@ -10,6 +10,7 @@ import { chatEvent } from "./chat-event.js";
10
10
  import { chatStats, taskStats } from "./chat-stats.js";
11
11
  import { contact } from "./contact.js";
12
12
  import { contactNote } from "./contact-note.js";
13
+ import { contactLookup, contactProfile, contactSync } from "./contact-read.js";
13
14
  import { conversation } from "./conversation.js";
14
15
  import { counterRefresh, counters } from "./counters.js";
15
16
  import { document } from "./document.js";
@@ -47,7 +48,7 @@ import { topic } from "./topic.js";
47
48
  * subset of its fields, never a renamed one. Commands move onto these one by one; until then, a schema
48
49
  * is the target, not a description of today's output.
49
50
  */
50
- export { account, accountSession, adminReport, agenda, attachment, chart, chat, chatEvent, chatStats, contact, contactNote, conversation, counterRefresh, counters, document, evidence, fact, folder, hit, identity, inviteLink, job, joinRequest, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, message, messageCounts, messageLink, model, note, officialStats, person, pollVote, ranking, reference, relationship, retention, savedSearch, tagging, task, taskStats, topic, };
51
+ export { account, accountSession, adminReport, agenda, attachment, chart, chat, chatEvent, chatStats, contact, contactLookup, contactNote, contactProfile, contactSync, conversation, counterRefresh, counters, document, evidence, fact, folder, hit, identity, inviteLink, job, joinRequest, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, message, messageCounts, messageLink, model, note, officialStats, person, pollVote, ranking, reference, relationship, retention, savedSearch, tagging, task, taskStats, topic, };
51
52
  export declare const ENTITIES: {
52
53
  readonly message: v.StrictObjectSchema<{
53
54
  readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
@@ -1726,6 +1727,124 @@ export declare const ENTITIES: {
1726
1727
  readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
1727
1728
  readonly updated_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`">]>;
1728
1729
  }, undefined>;
1730
+ readonly contact_lookup: v.StrictObjectSchema<{
1731
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
1732
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
1733
+ readonly username: v.NullableSchema<v.StringSchema<undefined>, undefined>;
1734
+ }, undefined>;
1735
+ readonly contact_profile: v.StrictObjectSchema<{
1736
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
1737
+ readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
1738
+ readonly usernames: v.ArraySchema<v.StringSchema<undefined>, undefined>;
1739
+ readonly bio: v.NullableSchema<v.StringSchema<undefined>, undefined>;
1740
+ readonly birthday: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
1741
+ readonly phone: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
1742
+ readonly flags: Omit<v.StrictObjectSchema<{
1743
+ readonly bot: v.BooleanSchema<undefined>;
1744
+ readonly verified: v.BooleanSchema<undefined>;
1745
+ readonly premium: v.BooleanSchema<undefined>;
1746
+ readonly scam: v.BooleanSchema<undefined>;
1747
+ readonly fake: v.BooleanSchema<undefined>;
1748
+ readonly restricted: v.BooleanSchema<undefined>;
1749
+ readonly deleted: v.BooleanSchema<undefined>;
1750
+ readonly support: v.BooleanSchema<undefined>;
1751
+ }, undefined>, "entries" | "~run" | "~standard" | "~types"> & {
1752
+ readonly entries: {
1753
+ readonly bot: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1754
+ readonly verified: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1755
+ readonly premium: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1756
+ readonly scam: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1757
+ readonly fake: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1758
+ readonly restricted: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1759
+ readonly deleted: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1760
+ readonly support: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1761
+ };
1762
+ readonly "~standard": v.StandardProps<{
1763
+ bot?: boolean | undefined;
1764
+ verified?: boolean | undefined;
1765
+ premium?: boolean | undefined;
1766
+ scam?: boolean | undefined;
1767
+ fake?: boolean | undefined;
1768
+ restricted?: boolean | undefined;
1769
+ deleted?: boolean | undefined;
1770
+ support?: boolean | undefined;
1771
+ }, {
1772
+ bot?: boolean | undefined;
1773
+ verified?: boolean | undefined;
1774
+ premium?: boolean | undefined;
1775
+ scam?: boolean | undefined;
1776
+ fake?: boolean | undefined;
1777
+ restricted?: boolean | undefined;
1778
+ deleted?: boolean | undefined;
1779
+ support?: boolean | undefined;
1780
+ }>;
1781
+ readonly "~run": (dataset: v.UnknownDataset, config: v.Config<v.BaseIssue<unknown>>) => v.OutputDataset<{
1782
+ bot?: boolean | undefined;
1783
+ verified?: boolean | undefined;
1784
+ premium?: boolean | undefined;
1785
+ scam?: boolean | undefined;
1786
+ fake?: boolean | undefined;
1787
+ restricted?: boolean | undefined;
1788
+ deleted?: boolean | undefined;
1789
+ support?: boolean | undefined;
1790
+ }, v.BooleanIssue | v.StrictObjectIssue>;
1791
+ readonly "~types"?: {
1792
+ readonly input: {
1793
+ bot?: boolean | undefined;
1794
+ verified?: boolean | undefined;
1795
+ premium?: boolean | undefined;
1796
+ scam?: boolean | undefined;
1797
+ fake?: boolean | undefined;
1798
+ restricted?: boolean | undefined;
1799
+ deleted?: boolean | undefined;
1800
+ support?: boolean | undefined;
1801
+ };
1802
+ readonly output: {
1803
+ bot?: boolean | undefined;
1804
+ verified?: boolean | undefined;
1805
+ premium?: boolean | undefined;
1806
+ scam?: boolean | undefined;
1807
+ fake?: boolean | undefined;
1808
+ restricted?: boolean | undefined;
1809
+ deleted?: boolean | undefined;
1810
+ support?: boolean | undefined;
1811
+ };
1812
+ readonly issue: v.BooleanIssue | v.StrictObjectIssue;
1813
+ } | undefined;
1814
+ };
1815
+ readonly seen: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
1816
+ readonly contact: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1817
+ readonly mutual_contact: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1818
+ readonly common_chats_count: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>, undefined>;
1819
+ readonly registered: v.OptionalSchema<v.NullableSchema<v.StrictObjectSchema<{
1820
+ readonly at: v.StringSchema<undefined>;
1821
+ readonly source: v.PicklistSchema<["telegram", "max", "estimate"], undefined>;
1822
+ readonly precision: v.PicklistSchema<["day", "month"], undefined>;
1823
+ }, undefined>, undefined>, undefined>;
1824
+ readonly has_photo: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
1825
+ readonly chats: v.ArraySchema<v.StrictObjectSchema<{
1826
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
1827
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
1828
+ readonly kind: v.PicklistSchema<["dialog", "group", "channel", "saved", "unknown"], undefined>;
1829
+ readonly their_messages: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
1830
+ readonly first_at: 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>;
1831
+ readonly last_at: 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>;
1832
+ readonly complete: v.BooleanSchema<undefined>;
1833
+ }, undefined>, undefined>;
1834
+ readonly aliases: v.ArraySchema<v.StrictObjectSchema<{
1835
+ readonly name: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
1836
+ readonly username: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
1837
+ readonly link: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
1838
+ readonly first_seen_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`">]>;
1839
+ readonly last_seen_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`">]>;
1840
+ readonly source: v.PicklistSchema<["profile", "messages"], undefined>;
1841
+ }, undefined>, undefined>;
1842
+ }, undefined>;
1843
+ readonly contact_sync: v.StrictObjectSchema<{
1844
+ readonly added: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
1845
+ readonly changed: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
1846
+ readonly known: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
1847
+ }, undefined>;
1729
1848
  readonly account: v.StrictObjectSchema<{
1730
1849
  readonly provider: v.StringSchema<undefined>;
1731
1850
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;