@wirecat/cli-core 0.461.0 → 0.462.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
@@ -7,6 +7,25 @@ shape of this file.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 0.462.0 — 27.10.2026
11
+
12
+ ### Changed — may break callers
13
+
14
+ - **`skill show`, `skill status` and `skill install` answer `--json` in the one-thing envelope**
15
+ ([WC-OUT-4](https://github.com/WireCatLabs/cli-base/blob/main/docs/standards/output.md#wc-out-4--answer-every-json-request-with-one-envelope-a-list-or-one-thing)),
16
+ `{ item, meta }`, and `--jsonl` as one item line and the end line, like every other command and as their declared
17
+ output schema already said; they printed the bare object. MCP tool answers change the same way. `commands --json`
18
+ does not change. A caller reads the old fields under `item`: the `install/windows.ps1` installers of tg-cli, max-cli
19
+ and whatsapp-cli read `$skill.written`, and tests in tg-cli (`src/archive.test.ts`), max-cli
20
+ (`src/commands/skill.test.ts`) and cli-template (`src/roots.test.ts`) read the bare shape.
21
+
22
+ ### Fixed
23
+
24
+ - **An empty `messages` search no longer suggests `messages sync --all --background`.** `coverage.next` and the
25
+ `messages.sync` step now name one chat (`<cli> messages sync <chat>`: the selected chat, or the most active one
26
+ that was never fetched or is behind), and the search help says to offer it and run it only after the owner
27
+ approves. A sync downloads from the owner's account, so an agent must not start an unbounded one on its own.
28
+
10
29
  ## 0.461.0 — 27.10.2026
11
30
 
12
31
  ### Changed — may break callers
@@ -43,9 +43,9 @@ export const messagesSearchCommand = (messenger) => {
43
43
  .option("--timezone <zone>", "the IANA timezone for calendar date boundaries")
44
44
  .addHelpText("after", SAVE_HELP)
45
45
  .addHelpText("after", `${syncsFirst(messenger)
46
- ? `Search reads the local archive: a chat never fetched is not searched. Prepare it once with
47
- \`${messenger.app.command} messages sync --all --background\` (the last 90 days of every chat); the answer's
48
- coverage says what was searched and coverage.next what would improve it.`
46
+ ? `Search reads the local archive: a chat never fetched is not searched. The answer's coverage says what was
47
+ searched and coverage.next names one chat that would improve it. A sync downloads from the owner's account, so
48
+ offer \`${messenger.app.command} messages sync <chat>\` and run it only once the owner approves.`
49
49
  : `Search reads the local archive: what \`${messenger.app.command} serve\` has kept since the account was linked.
50
50
  Keep serve running so new messages are searchable.`} Notes are
51
51
  \`${messenger.app.command} search notes\`, messages and notes at once \`${messenger.app.command} search all\`; for mail,
@@ -72,12 +72,9 @@ export const coverageGaps = (found, shown) => {
72
72
  const stale = found.refreshed?.complete === false;
73
73
  if (!coverage?.next && !stale)
74
74
  return { next: [], missing: [] };
75
+ const chat = coverage?.chat ?? coverage?.attention[0]?.chatId;
75
76
  return {
76
- next: [
77
- nextStep("messages.sync", {
78
- args: coverage?.chat === undefined ? { all: true, background: true } : { chat: coverage.chat },
79
- }),
80
- ],
77
+ next: chat === undefined ? [] : [nextStep("messages.sync", { args: { chat } })],
81
78
  missing: [
82
79
  {
83
80
  field: "coverage",
@@ -2,6 +2,7 @@ import { annotate } from "@wirecat/cli-base/commands";
2
2
  import { skillCommand as sharedSkillCommand } from "@wirecat/cli-base/skill";
3
3
  import { environmentOf, outputFor } from "./context.js";
4
4
  import { grantsAuthority } from "./effects.js";
5
+ import { printItem } from "./envelope.js";
5
6
  /**
6
7
  * `skill show` and `skill install`. `skill` is the CLI's own SKILL.md, shipped beside `dist/` in the
7
8
  * package and in a checkout alike, so the skill printed is always this version's.
@@ -9,7 +10,10 @@ import { grantsAuthority } from "./effects.js";
9
10
  export const skillCommand = (app, skill) => {
10
11
  const command = sharedSkillCommand(app, skill, (command) => {
11
12
  const { env } = environmentOf(command);
12
- return { ...outputFor(command), ...(env ? { env } : {}) };
13
+ const output = outputFor(command);
14
+ // cli-base prints each answer bare; the envelope is cli-core's.
15
+ const renderer = { ...output.renderer, result: (value) => printItem(output, value) };
16
+ return { ...output, renderer, ...(env ? { env } : {}) };
13
17
  }, SHARED_SKILLS);
14
18
  // An installed skill is instructions every later agent follows.
15
19
  const install = command.commands.find((sub) => sub.name() === "install");
@@ -235,12 +235,9 @@ export const coverageOf = async (store, { scopeAccounts, selectedChat }, messeng
235
235
  const completeness = [];
236
236
  const stats = new Map();
237
237
  let inventoryComplete = scopeAccounts.length > 0;
238
- let ownInventory = true;
239
238
  for (const selected of scopeAccounts) {
240
239
  if (!(await store.sync.syncState(selected, CHAT_LIST_KEY))) {
241
240
  inventoryComplete = false;
242
- if (messenger.provider === undefined || selected.provider === messenger.provider)
243
- ownInventory = false;
244
241
  }
245
242
  const chatIds = selectedChat
246
243
  ? selected.provider === selectedChat.account.provider && selected.account === selectedChat.account.account
@@ -274,15 +271,11 @@ export const coverageOf = async (store, { scopeAccounts, selectedChat }, messeng
274
271
  const behindCount = own.filter(behind).length;
275
272
  // A chat held back to a window stays partial for good, so only what a fetch would change is advised.
276
273
  const command = messenger.app?.command;
277
- const next = command === undefined
274
+ // One named chat, never `--all`: a download is the owner's call and stays bounded to what they approve.
275
+ const syncChat = selectedChat ? (neverFetched || behindCount ? selectedChat : null) : (attention[0] ?? null);
276
+ const next = command === undefined || !syncChat || !syncsOneChat(messenger)
278
277
  ? null
279
- : selectedChat
280
- ? (neverFetched || behindCount) && syncsOneChat(messenger)
281
- ? `${command} messages sync ${selectedChat.chatId}`
282
- : null
283
- : (neverFetched || behindCount || !ownInventory) && messenger.history !== "store"
284
- ? `${command} messages sync --all --background`
285
- : null;
278
+ : `${command} messages sync ${syncChat.chatId}`;
286
279
  const state = selectedChat && completeness.length > 0 && completeness.every(({ state }) => state === "complete")
287
280
  ? "complete"
288
281
  : completeness.some(({ state }) => state !== "unknown")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.461.0",
3
+ "version": "0.462.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",