@wirecat/cli-core 0.509.0 → 0.511.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,18 @@ shape of this file.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 0.511.0 — 31.10.2026
11
+
12
+ ## 0.510.0 — 31.10.2026
13
+
14
+ ### Fixed
15
+
16
+ - **`search events --backend both` marks a repeating event the provider also found.** The stored search shows a series
17
+ as one hit, while a provider such as Google answers the series and each moved occurrence apart, so 0.508.0 left the
18
+ stored hit without `server` and listed the provider's copies again below it. A provider hit is now matched through
19
+ its stored copy's series, and the stored hit takes `server` once.
20
+ - **`search events --help`** says what `--backend both` does in words ("ask both").
21
+
10
22
  ## 0.509.0 — 31.10.2026
11
23
 
12
24
  ### Changed — may break callers
@@ -104,6 +116,10 @@ shape of this file.
104
116
  such queries went from 0 meaning hits to 10–17 of 20, with no hit breaking the query.
105
117
  ### Fixed
106
118
 
119
+ - **The parity manifest lists `projects` and `projects evidence`**, with their options and the new `--alias` and
120
+ `--context-query`. Without the rows, `cli-core-parity` failed max and tg once they mounted `projectsCommand` from
121
+ 0.504.0. All three are marked planned, so the check passes with or without the command; a follow-up marks max and
122
+ tg as having it once tg-cli#798 and max-cli#886 are merged.
107
123
  - **Search by meaning inside a filter ranks the filter's own messages.** With fields that hold at most 100,000
108
124
  messages (`RANK_WITHIN_MESSAGES`), `--discover` scores every one of them that has a vector, instead of taking the
109
125
  100 nearest messages overall and dropping those outside the filter. On the owner's store, `chat:<id>` with a chat of
@@ -226,7 +226,7 @@ const addCalendarCommandsDefinition = (program, deps) => {
226
226
  const search = example(annotate(searches.command("events"), { effects: deps.serverSearch ? LOCAL_OR_REMOTE_READ : LOCAL_READ })
227
227
  .description(deps.serverSearch
228
228
  ? "find stored events by words, and by meaning when its model is downloaded; with --backend server, ask " +
229
- "the provider instead, with --backend both, both"
229
+ "the provider instead, or with --backend both, ask both"
230
230
  : "find stored events by words, and by meaning when its model is downloaded")
231
231
  .argument("<query...>", "what to find in titles, descriptions, places and attendees"), "search events roadmap planning --json", ...(deps.serverSearch
232
232
  ? ["search events --backend server quarterly review", "search events --backend both quarterly review"]
@@ -35,7 +35,8 @@ type ServerFound = Awaited<ReturnType<typeof serverSearchAnswer>>;
35
35
  /**
36
36
  * `--backend both`: the stored search's hits in its own order, each one the provider also found marked `server`, then
37
37
  * what only the provider found, earliest first. One page and no cursor: the two sides rank and page differently.
38
- * A provider hit is matched by its stored copy, so an occurrence the store keeps under another id shows twice.
38
+ * A provider hit is matched through its stored copy: a series, or any of its occurrences, to the stored hit of that
39
+ * series. A provider hit the store does not hold is listed on its own.
39
40
  */
40
41
  export declare const bothSearchAnswer: (store: EventStore, accountId: number, archived: EventsFound, served: ServerFound, limit: number) => Promise<{
41
42
  query: string;
@@ -39,24 +39,34 @@ export const serverSearchAnswer = async (source, store, { accountId, account, qu
39
39
  hits.sort((a, b) => (a.starts_at ?? "").localeCompare(b.starts_at ?? ""));
40
40
  return { query, by: "server", hits: hits.slice(0, limit), has_more: more || hits.length > limit };
41
41
  };
42
+ /** As the stored search groups hits: the occurrences of one series are one hit. */
43
+ const groupOf = (eventId, eventSeriesId) => eventSeriesId !== null ? `s${eventSeriesId}` : eventId !== null ? `e${eventId}` : undefined;
42
44
  /**
43
45
  * `--backend both`: the stored search's hits in its own order, each one the provider also found marked `server`, then
44
46
  * what only the provider found, earliest first. One page and no cursor: the two sides rank and page differently.
45
- * A provider hit is matched by its stored copy, so an occurrence the store keeps under another id shows twice.
47
+ * A provider hit is matched through its stored copy: a series, or any of its occurrences, to the stored hit of that
48
+ * series. A provider hit the store does not hold is listed on its own.
46
49
  */
47
50
  export const bothSearchAnswer = async (store, accountId, archived, served, limit) => {
48
51
  const calendars = new Map((await store.calendars(accountId)).map((calendar) => [calendar.externalId, calendar]));
49
52
  const hits = archived.hits.map((hit) => ({ ...hit }));
50
- const byRef = new Map(hits.map((hit) => [hit.ref, hit]));
53
+ const byGroup = new Map();
54
+ for (const hit of hits) {
55
+ const details = await store.event(Number(hit.ref.slice("event:".length)));
56
+ const group = details && groupOf(details.event.id, details.event.eventSeriesId);
57
+ if (group)
58
+ byGroup.set(group, hit);
59
+ }
51
60
  const onlyServer = [];
52
61
  for (const hit of served.hits) {
53
62
  const calendar = calendars.get(hit.calendar);
54
63
  const entry = calendar ? await store.entry(calendar.id, hit.external_id) : null;
55
- const held = entry?.eventId == null ? undefined : byRef.get(`event:${entry.eventId}`);
56
- if (held)
57
- held.found_by = [...held.found_by, "server"];
58
- else
64
+ const group = entry ? groupOf(entry.eventId, entry.eventSeriesId) : undefined;
65
+ const held = group === undefined ? undefined : byGroup.get(group);
66
+ if (!held)
59
67
  onlyServer.push(hit);
68
+ else if (!held.found_by.includes("server"))
69
+ held.found_by = [...held.found_by, "server"];
60
70
  }
61
71
  const merged = [...hits, ...onlyServer];
62
72
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.509.0",
3
+ "version": "0.511.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",
package/parity.json CHANGED
@@ -23,6 +23,10 @@
23
23
  "--ai": {
24
24
  "meaning": "call the configured reply model with stored message data; requires reply consent, otherwise uses fallback"
25
25
  },
26
+ "--alias": {
27
+ "value": "<name>",
28
+ "meaning": "another name of the project, searched on its own; repeat for more"
29
+ },
26
30
  "--all": {
27
31
  "meaning": "every row, no paging",
28
32
  "note": "chats requests confirm and reject take every pending request instead — counted against the hourly limit first — so it differs on purpose (Help text rule 4)"
@@ -261,6 +265,10 @@
261
265
  "value": "<n>",
262
266
  "meaning": "messages before and after each hit"
263
267
  },
268
+ "--context-query": {
269
+ "value": "<words>",
270
+ "meaning": "more words that all appear in one text; repeat for another"
271
+ },
264
272
  "--correct": {
265
273
  "value": "<n>",
266
274
  "meaning": "with --quiz: the right answer's position, from 1"
@@ -3669,6 +3677,37 @@
3669
3677
  }
3670
3678
  }
3671
3679
  },
3680
+ "projects": {
3681
+ "in": [],
3682
+ "planned": {
3683
+ "max": "max-cli#886, on the cli-core release with this row",
3684
+ "tg": "tg-cli#798, on the cli-core release with this row",
3685
+ "wa": "wa backlog: mount projectsCommand once wa is on cli-core 0.504.0"
3686
+ }
3687
+ },
3688
+ "projects evidence": {
3689
+ "in": [],
3690
+ "planned": {
3691
+ "max": "max-cli#886, on the cli-core release with this row",
3692
+ "tg": "tg-cli#798, on the cli-core release with this row",
3693
+ "wa": "wa backlog: mount projectsCommand once wa is on cli-core 0.504.0"
3694
+ },
3695
+ "options": {
3696
+ "--after-n": "all",
3697
+ "--alias": "all",
3698
+ "--before-n": "all",
3699
+ "--before-time": "all",
3700
+ "--contact": "all",
3701
+ "--context-query": "all",
3702
+ "--cursor": "all",
3703
+ "--limit": "all",
3704
+ "--max-pages": "all",
3705
+ "--no-catch-up": "all",
3706
+ "--since-time": "all",
3707
+ "--sync-first": "all",
3708
+ "--sync-time": "all"
3709
+ }
3710
+ },
3672
3711
  "reactions": {
3673
3712
  "in": "all"
3674
3713
  },