@wirecat/cli-core 0.490.0 → 0.491.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,7 +5,14 @@ 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
- ## Unreleased
8
+ ## 0.491.0 — 31.10.2026
9
+
10
+ ### Fixed
11
+
12
+ - **A budgeted mail sync now finishes locating a large folder stored before email locations existed.** It listed
13
+ the same newest messages every run, so a 16,100-message INBOX never got every UID stored and never switched to
14
+ the quick UID listing. Each budgeted run now leaves out the mail already done and located and lists the next
15
+ part; once the rest is listed whole, the folder is located. Such a run checks no deletions.
9
16
 
10
17
  ## 0.490.0 — 31.10.2026
11
18
 
package/dist/mail/sync.js CHANGED
@@ -147,6 +147,8 @@ const syncRound = async (source, store, { account, since, max = 200, maxBodyChar
147
147
  /** Every folder's stored point, valid or not: the widest window outlives what invalidates the rest. */
148
148
  const storedPoints = new Map();
149
149
  const resumed = new Set();
150
+ /** Backfilling folders listed without the mail already done and located: their listing proves no deletion. */
151
+ const narrowed = new Set();
150
152
  let mboxPoint;
151
153
  let mboxStamp;
152
154
  // A rerun lists only what the last left; --rescan, a rule change or a new UIDVALIDITY lists everything again.
@@ -254,6 +256,15 @@ const syncRound = async (source, store, { account, since, max = 200, maxBodyChar
254
256
  resumed.add(folder);
255
257
  wanted = { ...searched, uids: searched.uids.filter((uid) => !within(point.done, Number(uid))) };
256
258
  }
259
+ else if (backfill && plan !== undefined) {
260
+ // A budgeted run lists newest first, so a backfill that starts over every run never reaches the oldest mail.
261
+ const placed = new Set((await store.mail.folderEmails(accountId, folder, searched.validity)).map(({ uid }) => uid));
262
+ const left = searched.uids.filter((uid) => !(placed.has(Number(uid)) && within(point.done, Number(uid))));
263
+ if (left.length < searched.uids.length) {
264
+ narrowed.add(folder);
265
+ wanted = { ...searched, uids: left };
266
+ }
267
+ }
257
268
  }
258
269
  if (plan !== undefined) {
259
270
  plan.modes.set(folder, resumed.has(folder) ? "resumed" : "full");
@@ -364,6 +375,8 @@ const syncRound = async (source, store, { account, since, max = 200, maxBodyChar
364
375
  ? "folders this run did not list by UID are not checked for deletions; --rescan lists every message and checks them"
365
376
  : undefined);
366
377
  }
378
+ else if (narrowed.size > 0)
379
+ skipped = "this run listed only mail whose place is not stored yet; once every place is, deletions are checked";
367
380
  else if (resumed.size > 0)
368
381
  skipped =
369
382
  "this run listed only mail not read before; a full listing, at least daily or with --rescan, checks deletions";
@@ -487,6 +500,7 @@ const syncRound = async (source, store, { account, since, max = 200, maxBodyChar
487
500
  // A narrower whole listing, like the timer's 30 days, does not replace a wider one that is still fresh.
488
501
  const keepFull = before !== undefined &&
489
502
  (resumed.has(folder) ||
503
+ narrowed.has(folder) ||
490
504
  (Date.parse(before.full.since) < since.getTime() && startedAt - Date.parse(before.full.at) < FULL_PASS_MS));
491
505
  const merged = mergeRanges(before?.done ?? [], rangesOf(done));
492
506
  const widest = before === undefined || since.getTime() <= Date.parse(before.window.since);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.490.0",
3
+ "version": "0.491.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",