@wirecat/cli-core 0.397.0 → 0.399.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +12 -9
- package/dist/cli/analysis-choice.d.ts +1 -0
- package/dist/cli/analysis-choice.js +3 -0
- package/dist/cli/bot/admins.js +14 -4
- package/dist/cli/bot/command.js +38 -16
- package/dist/cli/bot/examples.d.ts +3 -0
- package/dist/cli/bot/examples.js +2 -0
- package/dist/cli/bot/mcp.js +4 -1
- package/dist/cli/bot/messages.js +17 -6
- package/dist/cli/bot/moderation.js +16 -4
- package/dist/cli/bot/people.js +16 -4
- package/dist/cli/bot/setup.js +27 -8
- package/dist/cli/bot/watch.js +7 -1
- package/dist/cli/commands-command.js +1 -1
- package/dist/cli/config-command.js +1 -1
- package/dist/cli/embedding-choice.d.ts +2 -1
- package/dist/cli/embedding-choice.js +4 -1
- package/dist/cli/guide.js +0 -1
- package/dist/cli/help/command-help.d.ts +9 -2
- package/dist/cli/help/command-help.js +22 -4
- package/dist/cli/help/first-screen.js +3 -3
- package/dist/cli/messenger/account-command.js +2 -1
- package/dist/cli/messenger/admin-commands.js +18 -9
- package/dist/cli/messenger/archive-commands.js +2 -2
- package/dist/cli/messenger/backfill-command.js +3 -3
- package/dist/cli/messenger/catch-up-answers.d.ts +4 -1
- package/dist/cli/messenger/catch-up-answers.js +11 -3
- package/dist/cli/messenger/chats-command.js +2 -1
- package/dist/cli/messenger/chats-stats-command.js +1 -1
- package/dist/cli/messenger/complete-command.js +5 -1
- package/dist/cli/messenger/contacts-command.js +4 -3
- package/dist/cli/messenger/context.d.ts +7 -0
- package/dist/cli/messenger/conversations-command.js +27 -13
- package/dist/cli/messenger/doctor-command.js +2 -2
- package/dist/cli/messenger/flood-command.js +1 -1
- package/dist/cli/messenger/hearing-command.d.ts +1 -1
- package/dist/cli/messenger/hearing-command.js +1 -1
- package/dist/cli/messenger/inbox.js +7 -4
- package/dist/cli/messenger/lacks.d.ts +7 -0
- package/dist/cli/messenger/lacks.js +18 -1
- package/dist/cli/messenger/media-archive-move-command.js +0 -1
- package/dist/cli/messenger/media-archive-timer-command.js +2 -2
- package/dist/cli/messenger/messages-command.js +2 -1
- package/dist/cli/messenger/messages-stats-command.js +1 -1
- package/dist/cli/messenger/metadata-command.js +1 -1
- package/dist/cli/messenger/models-command.js +5 -2
- package/dist/cli/messenger/private-people-command.js +5 -3
- package/dist/cli/messenger/replies-command.js +1 -1
- package/dist/cli/messenger/replies-edit-command.d.ts +1 -1
- package/dist/cli/messenger/replies-edit-command.js +13 -5
- package/dist/cli/messenger/retention-command.js +1 -1
- package/dist/cli/messenger/review.js +13 -6
- package/dist/cli/messenger/schedule-command.js +3 -3
- package/dist/cli/messenger/search-command.js +2 -2
- package/dist/cli/messenger/searches-command.js +1 -1
- package/dist/cli/messenger/serve-command.js +5 -1
- package/dist/cli/messenger/serve-relay.d.ts +2 -0
- package/dist/cli/messenger/server-command.js +12 -3
- package/dist/cli/messenger/stats-command.js +1 -1
- package/dist/cli/messenger/store-maintenance-command.js +3 -3
- package/dist/cli/messenger/tags-command.js +11 -5
- package/dist/cli/messenger/transcribe-command.js +1 -1
- package/dist/cli/messenger/watch-command.js +5 -1
- package/dist/cli/runs/command.js +2 -3
- package/dist/cli/skill-command.js +1 -1
- package/dist/domain/models.d.ts +2 -0
- package/dist/mcp/prompts.js +8 -2
- package/dist/services/deps.d.ts +1 -1
- package/dist/services/deps.js +1 -1
- package/dist/services/inbox.js +5 -5
- package/dist/services/search-kind.js +1 -1
- package/package.json +4 -4
- package/parity.json +134 -234
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,71 @@ Notable changes to `@wirecat/cli-core` (`@wirecat/cli-messaging` up to 0.261.0,
|
|
|
5
5
|
minor version may break callers, and says how under "Changed — may break callers". `pnpm docs:check` checks the
|
|
6
6
|
shape of this file.
|
|
7
7
|
|
|
8
|
+
## 0.399.0 — 23.10.2026
|
|
9
|
+
|
|
10
|
+
### Changed — may break callers
|
|
11
|
+
|
|
12
|
+
- **Flags have one meaning.** Use `--analysis-provider` for analysis, `--embedding-provider` for vector computation, `--consent-provider` for revoking a recorded provider identity, `--claim` for tag ownership, `--answer-model` for removing stored answers and `--template-mode` for reply templates. `inbox` and `review` take `kind:group,channel` in their query. Group message lifetime is `--disappear-after`, a duration or `off`. Legacy CLI spellings remain hidden for one release and cannot be combined with their replacements. MCP callers use the canonical argument names and `query` for chat kinds; update saved MCP requests.
|
|
13
|
+
|
|
14
|
+
- cli-core requires cli-base 0.50.2 or newer within the 0.50 line for the approved option roles and messenger vocabulary.
|
|
15
|
+
|
|
16
|
+
- **Private contact notes use `--text-file`.** `--file` continues to work as a hidden compatibility alias; giving both is refused before any note is changed. New help and discovery reserve `--file` for message attachments.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **Count and grouping placeholders match the shared vocabulary.** Processing limits use `<n>` and statistics grouping uses `<group>` across supported fields and calendar units; accepted values and defaults stay the same.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **The shared `bot` commands have help examples and short summaries.** Each leaf under `bot` shows one to three
|
|
25
|
+
examples in the calling CLI's own words, and every summary fits 80 characters; `bot recipients add|remove` describe
|
|
26
|
+
their `<chat>`. A CLI that baselined these for `command-example-count`, `command-help-too-long` or
|
|
27
|
+
`missing-argument-help` sees "stale baseline entry" and removes the lines; tg, max and wa grow no baseline for them.
|
|
28
|
+
- **`Messenger.joinRequestsByLink`**: whether `chats requests accept|decline --all` can be narrowed with `--link`;
|
|
29
|
+
yes when unset. `joinRequestsAll` now turns on `--all` alone, so a messenger that answers every request at once
|
|
30
|
+
but does not say which invite link each came by (MAX) offers `--all` without `--link`.
|
|
31
|
+
|
|
32
|
+
## 0.398.0 — 23.10.2026
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- Top-level summaries, listeners and shell completion include examples in help and command discovery.
|
|
37
|
+
|
|
38
|
+
- Clearing a remembered flood hold includes an example in help and command discovery.
|
|
39
|
+
|
|
40
|
+
- **`Messenger.never`**: the adapter methods a messenger can never have, as opposed to `lacks`, what it does not have
|
|
41
|
+
yet. Their commands refuse as before and are also left out of help, `commands --json` and MCP. A command a
|
|
42
|
+
messenger only `lacks` stays in sight. For WhatsApp: `endOtherSessions` (only the phone ends other devices) and
|
|
43
|
+
`removeContact`.
|
|
44
|
+
|
|
45
|
+
- **`review --offline` reads the local store** instead of refusing, for every messenger. It shows only what was
|
|
46
|
+
already synced and says so (`missing` in JSON, a warning on the terminal); its next step starts from the same
|
|
47
|
+
point, and `--new` keeps its saved point, so an online review still sees what was never synced.
|
|
48
|
+
|
|
49
|
+
- **MCP offers more commands**, each limited by the profile's permissions: `runs list|show|path`, `store status|info|check|export|reindex`,
|
|
50
|
+
`store jobs cancel|retry|clear`, `attachments move`, `attachments jobs status`, `config show`, `commands schema`, `guide`,
|
|
51
|
+
`skill show`, `doctor report`, the `models` lists, `replies status|test|consents show`, `schedule list`,
|
|
52
|
+
`server status|logs`, and on the bot server `list`, `chats leave`, `chats admins add|remove`, `commands set|clear` and
|
|
53
|
+
`webhooks list|set|delete`. What stays off and why is in [the messenger rules](docs/dev/STANDARD.md#mcp).
|
|
54
|
+
|
|
55
|
+
### Security
|
|
56
|
+
|
|
57
|
+
- `@modelcontextprotocol/server` 2.3.0 clears the three high-severity advisories `npm audit` reported for every
|
|
58
|
+
WireCat CLI.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- **A pasted help example runs.** The `Example:` line of an account command's `--help`, generated or written, names
|
|
63
|
+
the profile `personal` (`tg personal messages list Team`), so it no longer fails with "name a profile".
|
|
64
|
+
|
|
65
|
+
- `search mail` with no mail in the store points at `memo sync --only mail`; it named a `--mail` option memo does not have.
|
|
66
|
+
|
|
67
|
+
- `parity.json` matches tg and max: `guide`, `mentions`, `runs search`, `tasks reject` and `--brief`/`--full` are in
|
|
68
|
+
both, and each gap planned for tg names its tg-cli backlog id.
|
|
69
|
+
|
|
70
|
+
- `search all --help` says the messenger's server is asked by default and names `--backend archive` and `--offline`
|
|
71
|
+
to keep it to the local store.
|
|
72
|
+
|
|
8
73
|
## 0.397.0 — 23.10.2026
|
|
9
74
|
|
|
10
75
|
### Changed — may break callers
|
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
# @wirecat/cli-core
|
|
6
6
|
|
|
7
|
-
The engine behind the WireCat command-line tools for Telegram, MAX, mail, notes
|
|
7
|
+
The engine behind the WireCat command-line tools for Telegram, MAX, WhatsApp, mail, notes, meetings and Google
|
|
8
|
+
Drive. Everything that
|
|
8
9
|
does not depend on one messenger lives here: the data model, a local SQLite store with full-text and semantic
|
|
9
10
|
search, a Lucene query language, the shared commands, an MCP server for AI agents, and the guard around every
|
|
10
11
|
write. A messenger plugs in as one adapter and gets all of it.
|
|
@@ -36,6 +37,7 @@ write. A messenger plugs in as one adapter and gets all of it.
|
|
|
36
37
|
| [Testing](docs/dev/TESTING.md) · [Parity audit](docs/dev/PARITY-AUDIT.md) | The sandbox, the coverage floor, the checks across tg and max |
|
|
37
38
|
| [Tool boundaries](docs/dev/TOOL-BOUNDARIES.md) | Which tool owns which command |
|
|
38
39
|
| [API reference](docs/REFERENCE.md) | Every entry point and the detailed contract of each feature |
|
|
40
|
+
| [Roadmap](docs/roadmap.md) | What is being built next for developers on this package |
|
|
39
41
|
| [Changelog](CHANGELOG.md) | What each version changed, and what may break callers |
|
|
40
42
|
|
|
41
43
|
## What it is
|
|
@@ -72,7 +74,7 @@ It runs on Node 22.16+ and 24+, and on Bun.
|
|
|
72
74
|
|
|
73
75
|
```mermaid
|
|
74
76
|
flowchart TB
|
|
75
|
-
tools["tg · max · memo · zm · drive"] --> interface
|
|
77
|
+
tools["tg · max · wa · memo · zm · drive"] --> interface
|
|
76
78
|
subgraph core ["@wirecat/cli-core"]
|
|
77
79
|
interface["Interface: CLI commands and MCP tools"] --> services["Services: one use case each"]
|
|
78
80
|
services --> ports["Ports: MessengerAdapter · MeetingSource · TaskStore"]
|
|
@@ -88,7 +90,7 @@ Five layers, and each calls only the layers below it: domain, adapters behind a
|
|
|
88
90
|
|
|
89
91
|
- **The CLI and the MCP server are two adapters over the same services.** A command and its MCP tool answer with
|
|
90
92
|
the same data, because one service produces it.
|
|
91
|
-
- **A port with one required core and optional groups.** `MessengerCore` is what every messenger must do.
|
|
93
|
+
- **A port with one required core and optional groups.** `MessengerCore` is what every messenger must do. The other
|
|
92
94
|
groups — server reads, polls, forums, reactions and the rest — are optional and reached through `capability()`.
|
|
93
95
|
A messenger without a group refuses the command before connecting; it never crashes and never silently drops an
|
|
94
96
|
option.
|
|
@@ -116,8 +118,9 @@ code and its document must agree. A search plan that reads an index once per mes
|
|
|
116
118
|
- **One query language for every list and every source.** A TypeScript port of the Apache Lucene 9.12.3 parsers,
|
|
117
119
|
with no runtime parser dependency. Phrases, `AND` / `OR` / `NOT`, `+required`, grouping, field groups like
|
|
118
120
|
`from:(alice OR bob)`, ranges `date:[2026-01-01 TO 2026-02-01}`, comparisons `size>10MB`, wildcards and regular
|
|
119
|
-
expressions. 27 fields: sender, chat, date, file name, MIME type, transcript, subject, label and more.
|
|
120
|
-
|
|
121
|
+
expressions. 27 fields: sender, chat, date, file name, MIME type, transcript, subject, label and more.
|
|
122
|
+
Proximity `"invoice paid"~3` finds the words close together in one message; the fuzzy operator `word~1` is
|
|
123
|
+
refused with an error that names the alternative.
|
|
121
124
|
[Syntax](docs/search/query-language.md) · [grammar](docs/search/query-language-spec.md)
|
|
122
125
|
- **Any three letters inside a word.** An FTS5 trigram index finds `port` inside `report`. A
|
|
123
126
|
second, word index ranks by BM25.
|
|
@@ -211,8 +214,9 @@ they deliberately differ. A rule changes in its own pull request, before the cod
|
|
|
211
214
|
- **Built for agents.** `--no-input` never prompts. Input and output are bounded (16 MiB in, 4 MiB out) and fail
|
|
212
215
|
visibly instead of truncating. One-shot commands time out after 30 seconds and close what they hold. `--dry-run`
|
|
213
216
|
previews any write.
|
|
214
|
-
- **The tool never picks an account.**
|
|
215
|
-
|
|
217
|
+
- **The tool never picks an account.** Every account command names its profile — the first word in tg, max and
|
|
218
|
+
wa, an option such as `--account` or `--profile` in the others; without one, the command stops and lists the
|
|
219
|
+
choices — even when there is only one.
|
|
216
220
|
- **Run records keep ids and timings, never content.** A failure is kept by default, so `runs show` can explain it
|
|
217
221
|
without anyone sending a log full of messages.
|
|
218
222
|
- **Tests that cannot touch real data.** A sandbox keeps every test away from the owner's store, and no test may
|
|
@@ -253,8 +257,7 @@ describe("the adapter keeps the port's promises", () => {
|
|
|
253
257
|
**Before 1.0, any release may break a caller.** Releases are frequent, sometimes several a day, and any of them
|
|
254
258
|
may change any entry point. Every such change is listed in the [changelog](CHANGELOG.md) under "Changed — may break
|
|
255
259
|
callers", with what to change. tg-cli and max-cli pin an exact version and move to a new one in their own pull request.
|
|
256
|
-
Pin an exact version too
|
|
257
|
-
release has.
|
|
260
|
+
Pin an exact version too.
|
|
258
261
|
The full list of entry points and what each holds is in the [API reference](docs/REFERENCE.md).
|
|
259
262
|
|
|
260
263
|
⚠ **Errors are recognised by shape, not by class** (`isCliFailure`). A package linked during development brings its
|
|
@@ -3,6 +3,7 @@ import type { AnalysisProvider } from "../analysis/provider.js";
|
|
|
3
3
|
import type { AppIdentity } from "../ports/app.js";
|
|
4
4
|
import type { Settings } from "./settings.js";
|
|
5
5
|
export interface AnalysisOptions {
|
|
6
|
+
analysisProvider?: string;
|
|
6
7
|
provider?: string;
|
|
7
8
|
model?: string;
|
|
8
9
|
baseUrl?: string;
|
|
@@ -2,6 +2,9 @@ import { CliError } from "@wirecat/cli-base";
|
|
|
2
2
|
import { endpoint } from "../analysis/settings.js";
|
|
3
3
|
import { embeddingKeys, endpointKeyName } from "../embeddings/keys.js";
|
|
4
4
|
export const analysisChoice = (options, app, settings, env, keyring) => {
|
|
5
|
+
if (options.analysisProvider !== undefined && options.provider !== undefined)
|
|
6
|
+
throw new CliError("validation_error", "give --analysis-provider or its legacy --provider spelling, not both");
|
|
7
|
+
options = { ...options, provider: options.analysisProvider ?? options.provider };
|
|
5
8
|
const configured = { ...settings.models?.default, ...settings.models?.analysis };
|
|
6
9
|
settings = {
|
|
7
10
|
...settings,
|
package/dist/cli/bot/admins.js
CHANGED
|
@@ -9,6 +9,7 @@ import { renderAnswer, snakeKeys } from "../envelope.js";
|
|
|
9
9
|
import { rightsOf } from "../messenger/admin-commands.js";
|
|
10
10
|
import { renderItem, wholeList } from "../messenger/chat-answers.js";
|
|
11
11
|
import { botContext, online } from "./context.js";
|
|
12
|
+
import { botExamples } from "./examples.js";
|
|
12
13
|
import { botCan } from "./messages.js";
|
|
13
14
|
const CHAT = "a chat id, or the title of a chat this bot has seen";
|
|
14
15
|
const PERSON = "the person's user id";
|
|
@@ -23,7 +24,7 @@ const personOf = (typed) => {
|
|
|
23
24
|
export const botAdminsCommand = (bot) => {
|
|
24
25
|
const offered = bot.adminRights ?? ADMIN_RIGHTS;
|
|
25
26
|
const command = new Command("admins").description("the admins of a chat the bot is an admin in");
|
|
26
|
-
annotate(command.command("list"), { effects: REMOTE_READ })
|
|
27
|
+
annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "chats admins list Team") })
|
|
27
28
|
.description("the chat's admins and what each may do")
|
|
28
29
|
.argument("<chat>", CHAT)
|
|
29
30
|
.action(async function (chat) {
|
|
@@ -35,7 +36,10 @@ export const botAdminsCommand = (bot) => {
|
|
|
35
36
|
renderAnswer(this, context, wholeList("bot chats admins list", admins.map(snakeKeys)));
|
|
36
37
|
});
|
|
37
38
|
});
|
|
38
|
-
annotate(command.command("add"), {
|
|
39
|
+
annotate(command.command("add"), {
|
|
40
|
+
effects: REMOTE_WRITE,
|
|
41
|
+
examples: botExamples(bot, "chats admins add Team 42 --title Helper"),
|
|
42
|
+
})
|
|
39
43
|
.description("make a member an admin with these rights")
|
|
40
44
|
.argument("<chat>", CHAT)
|
|
41
45
|
.argument("<person>", PERSON)
|
|
@@ -61,7 +65,10 @@ export const botAdminsCommand = (bot) => {
|
|
|
61
65
|
});
|
|
62
66
|
});
|
|
63
67
|
});
|
|
64
|
-
annotate(command.command("remove"), {
|
|
68
|
+
annotate(command.command("remove"), {
|
|
69
|
+
effects: REMOTE_WRITE,
|
|
70
|
+
examples: botExamples(bot, "chats admins remove Team 42"),
|
|
71
|
+
})
|
|
65
72
|
.description("take an admin's rights back; they stay a member")
|
|
66
73
|
.argument("<chat>", CHAT)
|
|
67
74
|
.argument("<person>", PERSON)
|
|
@@ -85,7 +92,10 @@ export const botAdminsCommand = (bot) => {
|
|
|
85
92
|
*/
|
|
86
93
|
export const botMembersCommand = (bot) => {
|
|
87
94
|
const command = new Command("members").description("the people in a chat the bot is an admin in");
|
|
88
|
-
annotate(command.command("remove"), {
|
|
95
|
+
annotate(command.command("remove"), {
|
|
96
|
+
effects: REMOTE_WRITE,
|
|
97
|
+
examples: botExamples(bot, "chats members remove Team 42 --block"),
|
|
98
|
+
})
|
|
89
99
|
.description("take a person out of a chat; their messages stay")
|
|
90
100
|
.argument("<chat>", CHAT)
|
|
91
101
|
.argument("<person>", PERSON)
|
package/dist/cli/bot/command.js
CHANGED
|
@@ -9,6 +9,7 @@ import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
|
|
|
9
9
|
import { renderItem, wholeList } from "../messenger/chat-answers.js";
|
|
10
10
|
import { botAdminsCommand, botMembersCommand } from "./admins.js";
|
|
11
11
|
import { botContext, online } from "./context.js";
|
|
12
|
+
import { botExamples } from "./examples.js";
|
|
12
13
|
import { botMcpCommand } from "./mcp.js";
|
|
13
14
|
import { botCan, botIdOf, botMessagesCommand } from "./messages.js";
|
|
14
15
|
import { botModerateCommand, botRulesCommand } from "./moderation.js";
|
|
@@ -25,7 +26,9 @@ const secretSources = (bot, tokens) => bot.secrets?.length
|
|
|
25
26
|
: {};
|
|
26
27
|
const authCommand = (bot, tokenVariable) => {
|
|
27
28
|
const auth = annotate(new Command("auth"), { mcp: false }).description("the bot token this profile uses");
|
|
28
|
-
const set = grantsAuthority(annotate(auth.command("set"), { effects: LOCAL_WRITE
|
|
29
|
+
const set = grantsAuthority(annotate(auth.command("set"), { effects: LOCAL_WRITE, examples: botExamples(bot, "auth set") }))
|
|
30
|
+
.description(`check a bot token with ${bot.name ?? "the messenger"}, then keep it — typed at a hidden prompt or piped on stdin`)
|
|
31
|
+
.summary("check a bot token, then keep it; or keep a named secret beside it");
|
|
29
32
|
const secrets = bot.secrets ?? [];
|
|
30
33
|
if (secrets.length > 0)
|
|
31
34
|
set.option("--secret <name>", `keep this secret instead of the token, the same way: ${secrets.map((one) => `${one.name} (${one.description})`).join("; ")}`);
|
|
@@ -68,7 +71,7 @@ const authCommand = (bot, tokenVariable) => {
|
|
|
68
71
|
});
|
|
69
72
|
});
|
|
70
73
|
});
|
|
71
|
-
annotate(auth.command("show"), { effects: LOCAL_READ })
|
|
74
|
+
annotate(auth.command("show"), { effects: LOCAL_READ, examples: botExamples(bot, "auth show") })
|
|
72
75
|
.description("where this profile's bot token comes from, and which bot it is")
|
|
73
76
|
.action(async function () {
|
|
74
77
|
const context = online(botContext(this, bot), this);
|
|
@@ -85,7 +88,7 @@ const authCommand = (bot, tokenVariable) => {
|
|
|
85
88
|
});
|
|
86
89
|
});
|
|
87
90
|
});
|
|
88
|
-
grantsAuthority(annotate(auth.command("remove"), { effects: LOCAL_WRITE }))
|
|
91
|
+
grantsAuthority(annotate(auth.command("remove"), { effects: LOCAL_WRITE, examples: botExamples(bot, "auth remove") }))
|
|
89
92
|
.description("forget this profile's bot token")
|
|
90
93
|
.action(async function () {
|
|
91
94
|
const context = botContext(this, bot);
|
|
@@ -97,7 +100,7 @@ const authCommand = (bot, tokenVariable) => {
|
|
|
97
100
|
});
|
|
98
101
|
return auth;
|
|
99
102
|
};
|
|
100
|
-
const meCommand = (bot) => annotate(new Command("me"), { effects: REMOTE_READ })
|
|
103
|
+
const meCommand = (bot) => annotate(new Command("me"), { effects: REMOTE_READ, examples: botExamples(bot, "me") })
|
|
101
104
|
.description("the bot this profile's token belongs to: id, name and username")
|
|
102
105
|
.action(async function () {
|
|
103
106
|
const context = online(botContext(this, bot), this);
|
|
@@ -111,8 +114,9 @@ const meCommand = (bot) => annotate(new Command("me"), { effects: REMOTE_READ })
|
|
|
111
114
|
}
|
|
112
115
|
});
|
|
113
116
|
});
|
|
114
|
-
const listCommand = (bot, tokenVariable) => annotate(new Command("list"), { effects: LOCAL_READ,
|
|
117
|
+
const listCommand = (bot, tokenVariable) => annotate(new Command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "list", "list --check") })
|
|
115
118
|
.description(`every name on this machine that has a bot token; --check asks ${bot.name ?? "the messenger"} which bot each is`)
|
|
119
|
+
.summary("every bot profile on this machine; --check asks which bot each is")
|
|
116
120
|
.option("--check", "ask the messenger who each bot is, with its token")
|
|
117
121
|
.action(async function () {
|
|
118
122
|
const context = botContext(this, bot);
|
|
@@ -154,14 +158,20 @@ const listCommand = (bot, tokenVariable) => annotate(new Command("list"), { effe
|
|
|
154
158
|
});
|
|
155
159
|
});
|
|
156
160
|
const recipientsCommand = (bot) => {
|
|
157
|
-
const command = new Command("recipients")
|
|
158
|
-
|
|
161
|
+
const command = new Command("recipients")
|
|
162
|
+
.description("the chats this bot may write to; with no list, every chat — `clear` removes the list")
|
|
163
|
+
.summary("the chats this bot may write to; with no list, every chat");
|
|
164
|
+
annotate(command.command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "recipients list") })
|
|
159
165
|
.description("the chats on the list, or nothing when there is no list")
|
|
160
166
|
.action(async function () {
|
|
161
167
|
const context = botContext(this, bot);
|
|
162
168
|
await context.run(async () => renderAnswer(this, context, wholeList("bot recipients list", (context.recipients().read() ?? []).map(snakeKeys))));
|
|
163
169
|
});
|
|
164
|
-
grantsAuthority(annotate(command.command("add
|
|
170
|
+
grantsAuthority(annotate(command.command("add"), {
|
|
171
|
+
effects: LOCAL_WRITE,
|
|
172
|
+
examples: botExamples(bot, "recipients add Team"),
|
|
173
|
+
}))
|
|
174
|
+
.argument("<chat>", "a chat id, `user:<id>`, or the title of a chat this bot has seen")
|
|
165
175
|
.description("allow a chat: its id, `user:<id>`, or the title of a chat this bot has seen")
|
|
166
176
|
.action(async function (chat) {
|
|
167
177
|
const context = botContext(this, bot);
|
|
@@ -172,13 +182,17 @@ const recipientsCommand = (bot) => {
|
|
|
172
182
|
renderAnswer(this, context, wholeList("bot recipients list", (context.recipients().read() ?? []).map(snakeKeys)));
|
|
173
183
|
});
|
|
174
184
|
});
|
|
175
|
-
grantsAuthority(annotate(command.command("remove
|
|
185
|
+
grantsAuthority(annotate(command.command("remove"), {
|
|
186
|
+
effects: LOCAL_WRITE,
|
|
187
|
+
examples: botExamples(bot, "recipients remove Team"),
|
|
188
|
+
}))
|
|
189
|
+
.argument("<chat>", "the chat id, or the title as the list shows it")
|
|
176
190
|
.description("take a chat off the list")
|
|
177
191
|
.action(async function (chat) {
|
|
178
192
|
const context = botContext(this, bot);
|
|
179
193
|
await context.run(async () => renderItem(this, context, { removed: context.recipients().remove(chat) ?? null }));
|
|
180
194
|
});
|
|
181
|
-
grantsAuthority(annotate(command.command("clear"), { effects: LOCAL_WRITE }))
|
|
195
|
+
grantsAuthority(annotate(command.command("clear"), { effects: LOCAL_WRITE, examples: botExamples(bot, "recipients clear") }))
|
|
182
196
|
.description("remove the list: the bot may write to any chat again")
|
|
183
197
|
.action(async function () {
|
|
184
198
|
const context = botContext(this, bot);
|
|
@@ -188,21 +202,24 @@ const recipientsCommand = (bot) => {
|
|
|
188
202
|
};
|
|
189
203
|
const sendsCommand = (bot) => new Command("sends")
|
|
190
204
|
.description("what this bot sent, edited and deleted from this machine — ids and outcomes, never text")
|
|
191
|
-
.
|
|
205
|
+
.summary("what this bot sent, edited and deleted from here — never the text")
|
|
206
|
+
.addCommand(annotate(new Command("list"), { effects: LOCAL_READ, examples: botExamples(bot, "sends list") })
|
|
192
207
|
.description("every send, edit and delete this bot made from this machine, with its outcome")
|
|
193
208
|
.action(async function () {
|
|
194
209
|
const context = botContext(this, bot);
|
|
195
210
|
await context.run(async () => renderAnswer(this, context, wholeList("bot sends list", context.journal().entries().map(snakeKeys))));
|
|
196
211
|
}));
|
|
197
212
|
const chatsCommand = (bot) => {
|
|
198
|
-
const command = new Command("chats")
|
|
199
|
-
|
|
213
|
+
const command = new Command("chats")
|
|
214
|
+
.description(`the chats this bot is in — ${bot.name ?? "the messenger"} gives a bot no list of them, so \`list\` shows the ones it has seen`)
|
|
215
|
+
.summary("the chats this bot is in, and what it does there");
|
|
216
|
+
annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "chats list") })
|
|
200
217
|
.description(`chats this bot has seen on this machine — not a complete list from ${bot.name ?? "the messenger"}`)
|
|
201
218
|
.action(async function () {
|
|
202
219
|
const context = botContext(this, bot);
|
|
203
220
|
await context.run(async () => renderAnswer(this, context, wholeList("bot chats list", context.registry.list().map(snakeKeys))));
|
|
204
221
|
});
|
|
205
|
-
annotate(command.command("show"), { effects: REMOTE_READ })
|
|
222
|
+
annotate(command.command("show"), { effects: REMOTE_READ, examples: botExamples(bot, "chats show Team") })
|
|
206
223
|
.description(`one chat from ${bot.name ?? "the messenger"}, and remember it`)
|
|
207
224
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
208
225
|
.action(async function (chat) {
|
|
@@ -216,7 +233,10 @@ const chatsCommand = (bot) => {
|
|
|
216
233
|
renderItem(this, context, found);
|
|
217
234
|
});
|
|
218
235
|
});
|
|
219
|
-
annotate(command.command("leave"), {
|
|
236
|
+
annotate(command.command("leave"), {
|
|
237
|
+
effects: REMOTE_WRITE,
|
|
238
|
+
examples: botExamples(bot, "chats leave Team"),
|
|
239
|
+
})
|
|
220
240
|
.description("take the bot out of a chat; only an admin of the chat can bring it back")
|
|
221
241
|
.argument("<chat>", "a chat id, or the title of a chat this bot has seen")
|
|
222
242
|
.action(async function (chat) {
|
|
@@ -230,8 +250,9 @@ const chatsCommand = (bot) => {
|
|
|
230
250
|
renderAnswer(this, context, itemOf({ operation_id: operationId, chat_id: ref, left: true }));
|
|
231
251
|
});
|
|
232
252
|
});
|
|
233
|
-
annotate(command.command("action"), { effects: REMOTE_WRITE })
|
|
253
|
+
annotate(command.command("action"), { effects: REMOTE_WRITE, examples: botExamples(bot, "chats action Team typing") })
|
|
234
254
|
.description("show what the bot is doing in a chat — typing, sending a photo — for a few seconds")
|
|
255
|
+
.summary("show what the bot is doing in a chat, for a few seconds")
|
|
235
256
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
236
257
|
.addArgument(new Argument("<action>", "what the chat sees").choices(BOT_ACTIONS))
|
|
237
258
|
.action(async function (chat, action) {
|
|
@@ -263,6 +284,7 @@ export const botCommand = (bot) => {
|
|
|
263
284
|
const tokenVariable = envName(bot.app, "BOT_TOKEN");
|
|
264
285
|
const command = new Command("bot")
|
|
265
286
|
.description(`a ${bot.name ?? "messenger"} bot, through the official Bot API and a bot token — not your personal account`)
|
|
287
|
+
.summary("a bot account, through the official Bot API and a bot token")
|
|
266
288
|
.addCommand(authCommand(bot, tokenVariable))
|
|
267
289
|
.addCommand(listCommand(bot, tokenVariable))
|
|
268
290
|
.addCommand(chatsCommand(bot))
|
package/dist/cli/bot/mcp.js
CHANGED
|
@@ -8,11 +8,13 @@ import { itemOf, renderAnswer } from "../envelope.js";
|
|
|
8
8
|
import { serverEntry } from "../messenger/mcp-command.js";
|
|
9
9
|
import { nextStep, rootOf } from "../steps.js";
|
|
10
10
|
import { botContext } from "./context.js";
|
|
11
|
+
import { botExamples } from "./examples.js";
|
|
11
12
|
/** `bot mcp`, mounted only for a messenger that hands in its `run` on `BotMessenger.mcp`. */
|
|
12
13
|
export const botMcpCommand = (bot) => {
|
|
13
14
|
const { app } = bot;
|
|
14
15
|
const command = annotate(new Command("mcp"), { effects: REMOTE_WRITE, lifetime: "persistent", mcp: false })
|
|
15
16
|
.description(`serve this bot to an agent over MCP, on stdin and stdout — \`claude mcp add sales-bot -- ${app.command} sales bot mcp\``)
|
|
17
|
+
.summary("serve this bot to an agent over MCP, on stdin and stdout")
|
|
16
18
|
.action(async function () {
|
|
17
19
|
const context = botContext(this, bot);
|
|
18
20
|
if (!context.tokens.read()) {
|
|
@@ -33,8 +35,9 @@ export const botMcpCommand = (bot) => {
|
|
|
33
35
|
...(mcp.skill ? { skill: mcp.skill } : {}),
|
|
34
36
|
}, context.streams.diagnostic);
|
|
35
37
|
});
|
|
36
|
-
command.addCommand(annotate(new Command("config"), { effects: LOCAL_READ })
|
|
38
|
+
command.addCommand(annotate(new Command("config"), { effects: LOCAL_READ, examples: botExamples(bot, "mcp config") })
|
|
37
39
|
.description("print the mcpServers entry for Claude Desktop, Cursor and others, with full paths; writes nothing")
|
|
40
|
+
.summary("print the mcpServers entry for an MCP client; writes nothing")
|
|
38
41
|
.action(function () {
|
|
39
42
|
const context = botContext(this, bot);
|
|
40
43
|
const { settings, env } = context;
|
package/dist/cli/bot/messages.js
CHANGED
|
@@ -14,6 +14,7 @@ import { messageItem } from "../messenger/message-items.js";
|
|
|
14
14
|
import { readAll } from "../messenger/stdin.js";
|
|
15
15
|
import { positiveCount } from "../paging.js";
|
|
16
16
|
import { botContext } from "./context.js";
|
|
17
|
+
import { botExamples } from "./examples.js";
|
|
17
18
|
/** The adapter's `method`, or a refusal naming what this messenger's bot cannot do. */
|
|
18
19
|
export const botCan = (adapter, method, bot, what) => {
|
|
19
20
|
const found = adapter[method];
|
|
@@ -59,7 +60,10 @@ const seen = (context, message) => {
|
|
|
59
60
|
if (/^-?\d+$/.test(message.chatId))
|
|
60
61
|
context.registry.observe([{ id: message.chatId }]);
|
|
61
62
|
};
|
|
62
|
-
const sendCommand = (bot) => annotate(new Command("send"), {
|
|
63
|
+
const sendCommand = (bot) => annotate(new Command("send"), {
|
|
64
|
+
effects: REMOTE_WRITE,
|
|
65
|
+
examples: botExamples(bot, 'messages send Team "Doors open at 9"', 'messages send Team "Here it is" --file report.pdf'),
|
|
66
|
+
})
|
|
63
67
|
.description("send a message as the bot; without [text], the text is read from stdin")
|
|
64
68
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
65
69
|
.argument("[text]", "the message")
|
|
@@ -120,9 +124,10 @@ const sendCommand = (bot) => annotate(new Command("send"), { effects: REMOTE_WRI
|
|
|
120
124
|
renderAnswer(this, context, written(context, botId, { operationId }, message));
|
|
121
125
|
});
|
|
122
126
|
});
|
|
123
|
-
const listCommand = (bot) => annotate(new Command("list"), { effects: REMOTE_READ })
|
|
127
|
+
const listCommand = (bot) => annotate(new Command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "messages list Team --limit 20") })
|
|
124
128
|
.description(`the latest messages in a chat; where ${bot.name ?? "the messenger"} gives a bot no history, and with --offline, ` +
|
|
125
129
|
"the ones this bot has seen on this machine")
|
|
130
|
+
.summary("the latest messages in a chat")
|
|
126
131
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
127
132
|
.option("--limit <n>", "how many, the newest", positiveCount("--limit"))
|
|
128
133
|
.action(async function (chat) {
|
|
@@ -155,7 +160,7 @@ const listCommand = (bot) => annotate(new Command("list"), { effects: REMOTE_REA
|
|
|
155
160
|
show(this, context, bot, botId, messages);
|
|
156
161
|
});
|
|
157
162
|
});
|
|
158
|
-
const showCommand = (bot) => annotate(new Command("show"), { effects: REMOTE_READ })
|
|
163
|
+
const showCommand = (bot) => annotate(new Command("show"), { effects: REMOTE_READ, examples: botExamples(bot, "messages show Team 101") })
|
|
159
164
|
.description("one message by its id in a chat")
|
|
160
165
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
161
166
|
.argument("<message>", "message id")
|
|
@@ -187,7 +192,10 @@ const showCommand = (bot) => annotate(new Command("show"), { effects: REMOTE_REA
|
|
|
187
192
|
show(this, context, bot, botId, [found], true);
|
|
188
193
|
});
|
|
189
194
|
});
|
|
190
|
-
const editCommand = (bot) => annotate(new Command("edit"), {
|
|
195
|
+
const editCommand = (bot) => annotate(new Command("edit"), {
|
|
196
|
+
effects: REMOTE_WRITE,
|
|
197
|
+
examples: botExamples(bot, 'messages edit Team 101 "Doors open at 10"'),
|
|
198
|
+
})
|
|
191
199
|
.description("replace the text of a message the bot sent")
|
|
192
200
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
193
201
|
.argument("<message>", "message id")
|
|
@@ -217,7 +225,7 @@ const editCommand = (bot) => annotate(new Command("edit"), { effects: REMOTE_WRI
|
|
|
217
225
|
renderAnswer(this, context, written(context, botId, { operationId }, message));
|
|
218
226
|
});
|
|
219
227
|
});
|
|
220
|
-
const deleteCommand = (bot) => annotate(new Command("delete"), { effects: REMOTE_WRITE })
|
|
228
|
+
const deleteCommand = (bot) => annotate(new Command("delete"), { effects: REMOTE_WRITE, examples: botExamples(bot, "messages delete Team 101") })
|
|
221
229
|
.description("delete messages in a chat the bot can delete in; it cannot be undone")
|
|
222
230
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
223
231
|
.argument("<messages...>", "message ids")
|
|
@@ -235,7 +243,10 @@ const deleteCommand = (bot) => annotate(new Command("delete"), { effects: REMOTE
|
|
|
235
243
|
});
|
|
236
244
|
});
|
|
237
245
|
const pinCommand = (bot, pin) => {
|
|
238
|
-
const command = annotate(new Command(pin ? "pin" : "unpin"), {
|
|
246
|
+
const command = annotate(new Command(pin ? "pin" : "unpin"), {
|
|
247
|
+
effects: REMOTE_WRITE,
|
|
248
|
+
examples: botExamples(bot, `messages ${pin ? "pin" : "unpin"} Team 101`),
|
|
249
|
+
})
|
|
239
250
|
.description(pin ? "pin a message in a chat; quietly unless --notify" : "unpin a message in a chat")
|
|
240
251
|
.argument("<chat>", "a chat id, user:<id> for a person, or the title of a chat this bot has seen")
|
|
241
252
|
.argument("<message>", "message id");
|
|
@@ -13,6 +13,7 @@ import { grantsAuthority, LOCAL_READ, LOCAL_WRITE, ownerOnlyOption, REMOTE_WRITE
|
|
|
13
13
|
import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
|
|
14
14
|
import { answerOf } from "../messenger/ask.js";
|
|
15
15
|
import { botContext, online } from "./context.js";
|
|
16
|
+
import { botExamples } from "./examples.js";
|
|
16
17
|
import { botCan, botIdOf } from "./messages.js";
|
|
17
18
|
import { botFiles } from "./registry.js";
|
|
18
19
|
const CHAT = "a group's id, or the title of a group this bot has seen";
|
|
@@ -34,15 +35,19 @@ const shown = (context, chatId, rules) => {
|
|
|
34
35
|
/** `bot chats rules show|set|unset`: kept on this machine, the chat named the bot's way. */
|
|
35
36
|
export const botRulesCommand = (bot) => {
|
|
36
37
|
const command = new Command("rules").description("a chat's moderation rules for this bot, kept on this machine");
|
|
37
|
-
annotate(command.command("show"), { effects: LOCAL_READ })
|
|
38
|
+
annotate(command.command("show"), { effects: LOCAL_READ, examples: botExamples(bot, "chats rules show Team") })
|
|
38
39
|
.description("the chat's rules; the defaults, marked not saved, if it has none yet")
|
|
39
40
|
.argument("<chat>", CHAT)
|
|
40
41
|
.action(function (chat) {
|
|
41
42
|
const context = botContext(this, bot);
|
|
42
43
|
renderAnswer(this, context, shown(context, context.chatRef(chat), rulesOf(context, bot)));
|
|
43
44
|
});
|
|
44
|
-
grantsAuthority(annotate(command.command("set"), {
|
|
45
|
+
grantsAuthority(annotate(command.command("set"), {
|
|
46
|
+
effects: LOCAL_WRITE,
|
|
47
|
+
examples: botExamples(bot, "chats rules set Team links delete"),
|
|
48
|
+
}))
|
|
45
49
|
.description(`change one rule — ${RULE_KEYS.join(", ")}`)
|
|
50
|
+
.summary("change one moderation rule of a chat")
|
|
46
51
|
.argument("<chat>", CHAT)
|
|
47
52
|
.argument("<key>", "the rule")
|
|
48
53
|
.argument("<value>", "its new value")
|
|
@@ -56,7 +61,10 @@ export const botRulesCommand = (bot) => {
|
|
|
56
61
|
rules.set(chatId, titleOf(context, chatId), key, value);
|
|
57
62
|
renderAnswer(this, context, shown(context, chatId, rules));
|
|
58
63
|
});
|
|
59
|
-
grantsAuthority(annotate(command.command("unset"), {
|
|
64
|
+
grantsAuthority(annotate(command.command("unset"), {
|
|
65
|
+
effects: LOCAL_WRITE,
|
|
66
|
+
examples: botExamples(bot, "chats rules unset Team links"),
|
|
67
|
+
}))
|
|
60
68
|
.description("put one rule back to its default")
|
|
61
69
|
.argument("<chat>", CHAT)
|
|
62
70
|
.argument("<key>", "the rule")
|
|
@@ -136,8 +144,12 @@ const yes = (answer) => /^\s*y(es)?\s*$/i.test(answer);
|
|
|
136
144
|
* `bot chats moderate`: the personal `chats moderate`, done by the bot. Typing it is the consent for
|
|
137
145
|
* what the rules name. A removal bans unless `--no-block`.
|
|
138
146
|
*/
|
|
139
|
-
export const botModerateCommand = (bot) => annotate(new Command("moderate"), {
|
|
147
|
+
export const botModerateCommand = (bot) => annotate(new Command("moderate"), {
|
|
148
|
+
effects: REMOTE_WRITE,
|
|
149
|
+
examples: botExamples(bot, "chats moderate Team --dry-run"),
|
|
150
|
+
})
|
|
140
151
|
.description("judge a group's new messages and joins by its rules, and act as they allow — as the bot")
|
|
152
|
+
.summary("act on a group's new messages and joins by its rules, as the bot")
|
|
141
153
|
.argument("<chat>", CHAT)
|
|
142
154
|
.option("--since-time <time>", "judge what came after this ISO 8601 time, or 2h / 1d ago; the saved point stays")
|
|
143
155
|
.option("--dry-run", "judge and plan; do nothing")
|
package/dist/cli/bot/people.js
CHANGED
|
@@ -11,6 +11,7 @@ import { messageItem } from "../messenger/message-items.js";
|
|
|
11
11
|
import { positiveCount } from "../paging.js";
|
|
12
12
|
import { asFirstWord } from "../profile.js";
|
|
13
13
|
import { botContext } from "./context.js";
|
|
14
|
+
import { botExamples } from "./examples.js";
|
|
14
15
|
import { botCan } from "./messages.js";
|
|
15
16
|
import { ChatRegistry, registryProfiles } from "./registry.js";
|
|
16
17
|
/** What "common chats" rests on: who has written where in this copy, not who is a member. */
|
|
@@ -122,13 +123,16 @@ const cardOf = async (store, context, bot, who, across, limit) => {
|
|
|
122
123
|
};
|
|
123
124
|
/** `bot contacts show`: one person this bot has seen write, from the local copy. */
|
|
124
125
|
export const botContactsCommand = (bot) => {
|
|
125
|
-
const command = new Command("contacts")
|
|
126
|
-
|
|
126
|
+
const command = new Command("contacts")
|
|
127
|
+
.description(`people this bot has seen write — from the local copy on this machine, never asking ${bot.name ?? "the messenger"} unless told to`)
|
|
128
|
+
.summary("the people this bot has seen write, from the local copy");
|
|
129
|
+
acrossOptions(annotate(command.command("show"), { effects: REMOTE_READ, examples: botExamples(bot, "contacts show @ann") }))
|
|
127
130
|
.argument("<who>", "an id, @username or part of a name")
|
|
128
131
|
.option("--limit <n>", "how many messages from the private chat", positiveCount("--limit"))
|
|
129
132
|
.option("--sync-first", "read the private chat with them again from the messenger first — one request")
|
|
130
133
|
.description("one person: the chats they wrote in (with their last message there) and the latest messages of their " +
|
|
131
134
|
"private chat with the bot")
|
|
135
|
+
.summary("one person: the chats they wrote in and their chat with the bot")
|
|
132
136
|
.action(async function (who, options) {
|
|
133
137
|
const context = botContext(this, bot);
|
|
134
138
|
const across = { allBots: options.allBots === true, bots: options.bots ?? [] };
|
|
@@ -186,7 +190,10 @@ const search = (context, bot, text, from, options) => {
|
|
|
186
190
|
/** `bot search messages`: the messages this bot's local copy holds. */
|
|
187
191
|
export const botSearchCommand = (bot) => {
|
|
188
192
|
const group = new Command("search").description("find what this bot's local copy holds, by text");
|
|
189
|
-
acrossOptions(annotate(group.command("messages"), {
|
|
193
|
+
acrossOptions(annotate(group.command("messages"), {
|
|
194
|
+
effects: REMOTE_READ,
|
|
195
|
+
examples: botExamples(bot, "search messages refund", "search messages invoice --from @ann"),
|
|
196
|
+
}))
|
|
190
197
|
.argument("[query...]", "the words to find")
|
|
191
198
|
.option("--limit <n>", "how many", positiveCount("--limit"))
|
|
192
199
|
.option("--page <n>", "which page, starting at 1", positiveCount("--page"))
|
|
@@ -195,6 +202,7 @@ export const botSearchCommand = (bot) => {
|
|
|
195
202
|
.description("search the messages this bot has read, sent or received on this machine — the local copy only, best " +
|
|
196
203
|
'match first; a Lucene query: every word must appear; "a phrase", -word, a OR b, from: chat: date: has:; ' +
|
|
197
204
|
"by text, by --from, or both")
|
|
205
|
+
.summary("search the messages this bot has seen, in the local copy, by text")
|
|
198
206
|
.action(async function (query, options) {
|
|
199
207
|
const context = botContext(this, bot);
|
|
200
208
|
const limit = options.limit ?? context.settings.limit;
|
|
@@ -222,12 +230,16 @@ export const botSearchCommand = (bot) => {
|
|
|
222
230
|
};
|
|
223
231
|
/** `bot messages between`, over the local copy, added to the shared `messages` group. */
|
|
224
232
|
export const addBotCopyReads = (messages, bot) => {
|
|
225
|
-
acrossOptions(annotate(messages.command("between"), {
|
|
233
|
+
acrossOptions(annotate(messages.command("between"), {
|
|
234
|
+
effects: REMOTE_READ,
|
|
235
|
+
examples: botExamples(bot, "messages between @ann @bob"),
|
|
236
|
+
}))
|
|
226
237
|
.argument("<people...>", "two or more people — an id, @username or part of a name each")
|
|
227
238
|
.option("--limit <n>", "how many of the latest messages from each chat", positiveCount("--limit"))
|
|
228
239
|
.description("what two or more people wrote in the chats they have all written in — from the local copy, grouped by " +
|
|
229
240
|
"chat, oldest first; --limit counts per chat. Common chats are the ones this copy saw each of them " +
|
|
230
241
|
`write in, not a member list from ${bot.name ?? "the messenger"}`)
|
|
242
|
+
.summary("what two or more people wrote in the chats they share, from the local copy")
|
|
231
243
|
.action(async function (references, options) {
|
|
232
244
|
const context = botContext(this, bot);
|
|
233
245
|
if (references.length < 2)
|