@wirecat/cli-core 0.392.0 → 0.393.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ 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.393.0 — 23.10.2026
9
+
10
+ ### Added
11
+
12
+ - Tag commands include concrete examples in help and command discovery.
13
+
14
+ - Chat commands include concrete examples in help and command discovery.
15
+ - Contact commands include concrete examples in help and command discovery.
16
+ - **`@wirecat/cli-base` 0.50.0 is accepted beside 0.49.** The peer range is now `>=0.49.0 <0.51.0`, so a CLI that
17
+ takes cli-base 0.50.0 for `adaptOpenApi` (whatsapp-cli's bot API) keeps one copy of cli-base instead of two.
18
+ Nothing in cli-core calls what 0.50.0 added.
19
+
8
20
  ## 0.392.0 — 23.10.2026
9
21
 
10
22
  ### Added
@@ -6,6 +6,7 @@ import { LOCAL_READ, REMOTE_READ } from "../effects.js";
6
6
  import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
7
7
  import { withQuery } from "../list-query.js";
8
8
  import { withPaging } from "../paging.js";
9
+ import { commandAt } from "../steps.js";
9
10
  import { groupCommands } from "./admin-commands.js";
10
11
  import { foldersCommand } from "./admin-folders-command.js";
11
12
  import { moderateCommand, rulesCommand } from "./admin-moderation-command.js";
@@ -102,6 +103,55 @@ export const chatsCommand = (messenger) => {
102
103
  if (messenger.personalBots === true)
103
104
  for (const command of botChatCommands(messenger))
104
105
  chats.addCommand(command);
106
+ const examples = {
107
+ "admins add": `"Book club" "Alex Example"${messenger.pickAdminRights === false ? "" : ` --can ${messenger.adminRights?.[0] ?? "info"}`}`,
108
+ "admins remove": '"Book club" "Alex Example"',
109
+ create: '"Book club" "Alex Example"',
110
+ "documents list": '"Project room" --limit 10',
111
+ events: '"Book club"',
112
+ "folders create": '"Reading" --chat "Book club"',
113
+ "folders delete": '"Reading"',
114
+ "folders join": "https://t.me/addlist/example",
115
+ "folders list": "",
116
+ "folders order": '"Reading" "Work"',
117
+ "folders show": '"Reading"',
118
+ "folders update": '"Reading" --title "Books"',
119
+ inspect: "https://example.com/invite/book-club",
120
+ join: "https://example.com/invite/book-club",
121
+ leave: '"Book club"',
122
+ "link create": '"Book club"',
123
+ "link list": '"Book club"',
124
+ "link reset": '"Book club"',
125
+ "link revoke": '"Book club" https://example.com/invite/book-club',
126
+ "link show": '"Book club"',
127
+ list: "--limit 10",
128
+ "mark-read": '"Book club" --until-id 101',
129
+ "members add": '"Book club" "Alex Example"',
130
+ "members audit": '"Book club"',
131
+ "members fetch": '"Book club"',
132
+ "members history": '"Book club"',
133
+ "members list": '"Book club"',
134
+ "members remove": '"Book club" "Alex Example"',
135
+ moderate: '"Book club" --dry-run',
136
+ "requests accept": '"Book club" "Alex Example"',
137
+ "requests decline": '"Book club" "Alex Example"',
138
+ "requests list": '"Book club"',
139
+ "rules set": '"Book club" links report',
140
+ "rules show": '"Book club"',
141
+ "rules unset": '"Book club" links',
142
+ "send-as": '"Project room"',
143
+ show: '"Book club"',
144
+ "tracking add": '"Book club"',
145
+ "tracking list": "",
146
+ "tracking remove": '"Book club"',
147
+ "tracking show": '"Book club"',
148
+ update: '"Book club" --title "Reading group"',
149
+ };
150
+ for (const [path, args] of Object.entries(examples)) {
151
+ const command = commandAt(chats, path);
152
+ if (command)
153
+ annotate(command, { examples: [`${messenger.app.command} personal chats ${path} ${args}`.trimEnd()] });
154
+ }
105
155
  return chats;
106
156
  };
107
157
  /** Where the history is pushed, the chat list and a chat's card answer from the store and never connect. */
@@ -15,7 +15,7 @@ import { itemOf, listOf, renderAnswer, snakeKeys } from "../envelope.js";
15
15
  import { listQuery, nativeTerms, typedQuery, withQuery } from "../list-query.js";
16
16
  import { positiveCount, window, withPaging } from "../paging.js";
17
17
  import { casKey } from "../registry-keys.js";
18
- import { nextStep } from "../steps.js";
18
+ import { commandAt, nextStep } from "../steps.js";
19
19
  import { contactWriteCommands } from "./admin-contacts-command.js";
20
20
  import { contactAnswer, lines, pageOf } from "./chat-answers.js";
21
21
  import { messengerContext } from "./context.js";
@@ -250,5 +250,35 @@ export const contactsCommand = (messenger) => {
250
250
  contacts.addCommand(command);
251
251
  for (const command of contactWriteCommands(messenger))
252
252
  contacts.addCommand(command);
253
+ const examples = {
254
+ add: '"Alex Example"',
255
+ "alias rm": '"Alex Example"',
256
+ "alias set": '"Alex Example" "Reading partner"',
257
+ block: '"Alex Example"',
258
+ check: '"Alex Example"',
259
+ context: '"Alex Example" --limit 10',
260
+ import: "./contacts.csv",
261
+ link: '"Alex Example" zoom:101',
262
+ list: "--limit 10",
263
+ lookup: "",
264
+ "notes add": '"Alex Example" --file ./note.txt',
265
+ "notes edit": '"Alex Example" 1 --revision 1 --file ./note.txt',
266
+ "notes list": '"Alex Example"',
267
+ "notes remove": '"Alex Example" 1',
268
+ "notes show": '"Alex Example" 1',
269
+ profile: '"Alex Example"',
270
+ remove: '"Alex Example"',
271
+ rename: '"Alex Example" Alex Example',
272
+ show: '"Alex Example"',
273
+ sync: "",
274
+ timeline: '"Alex Example" --limit 10',
275
+ unblock: '"Alex Example"',
276
+ unlink: '"Alex Example"',
277
+ };
278
+ for (const [path, args] of Object.entries(examples)) {
279
+ const command = commandAt(contacts, path);
280
+ if (command)
281
+ annotate(command, { examples: [`${messenger.app.command} personal contacts ${path} ${args}`.trimEnd()] });
282
+ }
253
283
  return contacts;
254
284
  };
@@ -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;
@@ -28,8 +28,9 @@ const sourceOf = (value) => {
28
28
  };
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
+ const tool = `${messenger.app.command} personal`;
31
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
- changesStore(annotate(tags.command("auto"), { effects: FETCH }))
33
+ changesStore(annotate(tags.command("auto"), { effects: FETCH, examples: [`${tool} tags auto --chat "Book club" --dry-run`] }))
33
34
  .description("derive local group/channel tags from cached metadata using keyword rules")
34
35
  .option("--chat <chat>", "a stored group/channel; repeat to select several", (value, previous) => [...previous, value], [])
35
36
  .option("--limit <number>", "process at most 1–500 chats", positiveCount("--limit"), 50)
@@ -43,7 +44,10 @@ export const tagsCommand = (messenger) => {
43
44
  const done = await context.withServices((services) => services.metadata.auto({ chats: chat, limit: Number(limit), refresh: syncFirst, dryRun }));
44
45
  renderAnswer(this, context, itemOf(snakeKeys(done)));
45
46
  });
46
- targetOptions(annotate(tags.command("add"), { effects: LOCAL_WRITE }).description("put tags on one chat, person, message or task"), messenger, "tag").action(async function (given) {
47
+ targetOptions(annotate(tags.command("add"), {
48
+ effects: LOCAL_WRITE,
49
+ examples: [`${tool} tags add reading --chat "Book club"`],
50
+ }).description("put tags on one chat, person, message or task"), messenger, "tag").action(async function (given) {
47
51
  const context = messengerContext(this, messenger);
48
52
  refuseLocalWrite(context, messenger.app.command, "tags.add");
49
53
  const target = this.opts();
@@ -52,7 +56,10 @@ export const tagsCommand = (messenger) => {
52
56
  if (done.unchanged.length && context.format === "pretty")
53
57
  context.renderer.note(`already there: ${done.unchanged.join(", ")}`);
54
58
  });
55
- targetOptions(annotate(tags.command("remove"), { effects: LOCAL_WRITE }).description("take tags off one chat, person, message or task"), messenger, "untag")
59
+ targetOptions(annotate(tags.command("remove"), {
60
+ effects: LOCAL_WRITE,
61
+ examples: [`${tool} tags remove reading --chat "Book club"`],
62
+ }).description("take tags off one chat, person, message or task"), messenger, "untag")
56
63
  .option("--source <manual|auto>", "remove only this ownership claim", sourceOf)
57
64
  .action(async function (given) {
58
65
  const context = messengerContext(this, messenger);
@@ -63,7 +70,10 @@ export const tagsCommand = (messenger) => {
63
70
  if (done.unchanged.length && context.format === "pretty")
64
71
  context.renderer.note(`not there: ${done.unchanged.join(", ")}`);
65
72
  });
66
- withQuery(annotate(tags.command("list"), { effects: LOCAL_READ }).description("what is tagged: this account's chats, messages and tasks, and the people of its messenger"), TAGGING_QUERY).action(async function (words) {
73
+ withQuery(annotate(tags.command("list"), {
74
+ effects: LOCAL_READ,
75
+ 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) {
67
77
  const context = messengerContext(this, messenger);
68
78
  const query = listQuery(typedQuery(words), TAGGING_QUERY, "tags list");
69
79
  const found = await context.withServices((services) => services.tags.list({ ...(query ? { query } : {}), ...pageOf(context.settings) }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.392.0",
3
+ "version": "0.393.0",
4
4
  "description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Viacheslav Ptsarev",
@@ -207,7 +207,7 @@
207
207
  "@types/node": "^22.20.4",
208
208
  "@types/pngjs": "6.0.5",
209
209
  "@vitest/coverage-v8": "^5.0.2",
210
- "@wirecat/cli-base": "0.49.0",
210
+ "@wirecat/cli-base": "0.50.0",
211
211
  "commander": "15.0.0",
212
212
  "cspell": "10.3.6",
213
213
  "drizzle-kit": "1.0.0-rc.4",
@@ -227,7 +227,7 @@
227
227
  },
228
228
  "peerDependencies": {
229
229
  "@napi-rs/canvas": ">=0.1.69 <2",
230
- "@wirecat/cli-base": ">=0.49.0 <0.50.0",
230
+ "@wirecat/cli-base": ">=0.49.0 <0.51.0",
231
231
  "commander": ">=15"
232
232
  },
233
233
  "bin": {