@wirecat/cli-base 0.52.0 → 0.53.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
@@ -8,6 +8,16 @@ Versions before 0.8.0 are in the [git tags](https://github.com/WireCatLabs/cli-b
8
8
  Every entry says what changed as a caller sees it, why, and what to watch for — the rules are
9
9
  [`docs/dev/CONVENTIONS.md`](docs/dev/CONVENTIONS.md#the-changelog).
10
10
 
11
+ ## 0.53.0 — 25.10.2026
12
+
13
+ ### Added
14
+
15
+ - **A rule for the provider registry** (`WC-ARCH-21`, [Architecture](docs/standards/architecture.md)): a CLI registers its provider in the store on every run, and a row whose provider no one registered is skipped, never searched as messages. It matches cli-core's stored registry. The Data model, Store and Security pages also list what the approved Wave 3 design adds and is not built yet: files, calendars, contacts by address, one link log and review list, a CLI's own SQLite file, and the sign-in module. The Data model page now names the attendee table `calendar_entry_participants`, lists `meeting_participants` among the known gaps, and names cli-core's schema test as the check of `WC-DATA-2` to `WC-DATA-4`.
16
+
17
+ ### Changed — may break callers
18
+
19
+ - **Every handwritten list needs a query declaration.** The command lint checks lists that lack answer metadata too. Release this with the matching cli-core list-query changes and consumer updates.
20
+
11
21
  ## 0.52.0 — 25.10.2026
12
22
 
13
23
  ### Added
@@ -16,6 +26,7 @@ Every entry says what changed as a caller sees it, why, and what to watch for
16
26
  - **`cli-dev <command> --help`** prints the usage, as `cli-dev --help` does, instead of failing on an unknown option.
17
27
 
18
28
  - **A data-model page in the standards** (`WC-DATA-1` to `WC-DATA-7`, [Data model](docs/standards/data-model.md)). It says which records cli-core owns and which stay private to a CLI, keeps a source's records (a calendar entry, a Drive file, a mail contact) apart from the owner's entities (an event, a document, a person), puts every provider id in `external_id`, lists the standard field names, and makes every link record how it was made, with no link when two candidates tie. Nothing changes in code; older tables follow the rules when they next change.
29
+
19
30
  ## 0.51.1 — 24.10.2026
20
31
 
21
32
  ### Fixed
package/dist/dev/lint.js CHANGED
@@ -342,10 +342,10 @@ const CHECKS = {
342
342
  .map(({ target, option }) => ({ target, message: `${longName(option.flags)} has no role in the vocabulary` }));
343
343
  },
344
344
  "list-without-query": (document) => handwrittenLeaves(document)
345
- .filter((command) => command.name === "list" && command.output !== undefined && command.query === undefined)
345
+ .filter((command) => command.name === "list" && command.query === undefined)
346
346
  .map((command) => ({
347
347
  target: label(command),
348
- message: `answers with ${command.output?.entity} but takes no query`,
348
+ message: "list declares no query",
349
349
  })),
350
350
  "query-example": (document) => walk(document.commands).flatMap((command) => command.query
351
351
  ? exampleProblems(command.query).map(({ field, problem }) => ({
@@ -32,7 +32,7 @@ rules it keeps. A new CLI is ready for its first release when every check under
32
32
  | [MCP](mcp.md) | `MCP` | 13 | The MCP tools, how they come from commands, what each permission shows |
33
33
  | [Accounts](accounts.md) | `ACCT` | 11 | The explicit profile, reads across accounts, scope flags, linked identities |
34
34
  | [Permissions](permissions.md) | `PERM` | 21 | Levels, keys, defaults, hard limits, the write guard and its journal |
35
- | [Architecture](architecture.md) | `ARCH` | 16 | Layers, dependency direction, vendor types, what goes in which package |
35
+ | [Architecture](architecture.md) | `ARCH` | 17 | Layers, dependency direction, vendor types, what goes in which package |
36
36
  | [Lifecycle](lifecycle.md) | `LIFE` | 13 | Opening late, who closes, one-shot exits, long-running commands, the `serve` relay, resumable syncs |
37
37
  | [Store](store.md) | `STORE` | 14 | Store areas, account scope, migrations, test isolation |
38
38
  | [Data model](data-model.md) | `DATA` | 7 | Core entities, entities and source records, `external_id`, field names, links and duplicates |
@@ -204,6 +204,24 @@ at start-up and the `serve` relay are in [Lifecycle](lifecycle.md); the store's
204
204
  - **Exceptions:** none.
205
205
  - **Applies to:** cli-base. **Since:** cli-base 0.41.0. **Rulings:** NEED-15.
206
206
 
207
+ ### WC-ARCH-21 · A CLI registers its provider in the store; an unknown provider's rows are skipped, never guessed
208
+
209
+ Every run, a CLI writes its provider's entry — `{ name, kind, aliases, command }` — with `registerProvider` from
210
+ `@wirecat/cli-core/store`. cli-core reads its built-in providers plus the stored entries when the store opens, so
211
+ every other CLI knows the new provider's kind without a cli-core release. A row whose provider no entry names is left
212
+ out of search and listed under `skipped`, with the hint to run that CLI once.
213
+
214
+ - **Why:** a new source joins search and memo without editing cli-core, and a provider nobody described is never read
215
+ as something it is not (until this rule, an unlisted provider was searched as a messenger).
216
+ - **Enforced by:** `cli-core: src/store/sqlite/providers.test.ts`.
217
+ - **Example:** cal registers `{ name: "google-calendar", kind: "events", aliases: ["cal"], command: "cal" }` each
218
+ time it starts. On a machine where cal has never run, a search across accounts lists cal's accounts under
219
+ `skipped` instead of reading their rows as messages.
220
+ - **Exceptions:** the built-in providers of cli-core need no entry. Two entries that disagree on a kind are an error
221
+ naming both.
222
+ - **Applies to:** cli-core and every CLI with a provider of its own. **Since:** cli-base 0.53.1. **Rulings:** none
223
+ (Wave 3 requirements 3.2).
224
+
207
225
  ## Sources
208
226
 
209
227
  These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
@@ -33,6 +33,13 @@ is rewritten only to follow it:
33
33
  and nothing joins the two (WC-DATA-6).
34
34
  - `events` rows made from Zoom meetings have no source record of their own besides the meeting (WC-DATA-2 holds:
35
35
  `meetings` is that record).
36
+ - Local folders are accounts with provider `folder` (an Obsidian vault and a plain folder look the same), and Drive's
37
+ stand-in account uses it too (WC-DATA-3).
38
+ - Contacts live in `identities`, with no address column: an address is only the `external_id` of provider `email`
39
+ (WC-DATA-6).
40
+ - `documents` keeps its source columns (`account_id`, `external_id`, `url`, `mime`, `front_matter`…) next to the
41
+ entity's own fields (WC-DATA-2).
42
+ - `meeting_participants` is unique on the meeting and the contact; its `external_id` is in no unique key (WC-DATA-3).
36
43
 
37
44
  ## Rules
38
45
 
@@ -59,7 +66,7 @@ to its entity. One entity may combine source records from several sources and ac
59
66
 
60
67
  - **Why:** the same meeting in two calendars and in Zoom is one event to the owner; the same document in Drive and on
61
68
  disk is one document.
62
- - **Enforced by:** review only.
69
+ - **Enforced by:** `cli-core: src/store/sqlite/schema.test.ts`, for the entity tables only; which table is which kind is review.
63
70
  - **Example:** a Google Calendar entry is a `calendar_entries` row with `event_id`; the Zoom recording of that meeting
64
71
  is a `meetings` row with the same `event_id`.
65
72
  - **Exceptions:** an entity the owner makes has no source record; a source record may wait unlinked until matching
@@ -73,7 +80,7 @@ record has no account). Never in a column named after the provider (`google_id`,
73
80
  `metadata`. A second id the provider also uses gets a named column of its own (`ical_uid`).
74
81
 
75
82
  - **Why:** one place to look for every provider's id, and one unique key to update a record by.
76
- - **Enforced by:** review only.
83
+ - **Enforced by:** `cli-core: src/store/sqlite/schema.test.ts`.
77
84
  - **Example:** a Drive file: `files.external_id = '<Drive file id>'`; a Google calendar entry:
78
85
  `calendar_entries.external_id = '<event id>'`, `ical_uid = '<iCalUID>'`.
79
86
  - **Exceptions:** a local file has no provider id; its `external_id` is its path relative to its folder root.
@@ -103,7 +110,7 @@ Times are UTC milliseconds ([Time](time.md)).
103
110
 
104
111
  - **Why:** a reader of any table knows what a field holds, and a new table does not invent a third name for "edited
105
112
  at".
106
- - **Enforced by:** review only.
113
+ - **Enforced by:** `cli-core: src/store/sqlite/schema.test.ts`.
107
114
  - **Example:** `files.external_updated_at`, not `modified_at` or `modifiedAt` in JSON.
108
115
  - **Exceptions:** existing columns keep their names until their table changes for another reason.
109
116
  - **Applies to:** cli-core. **Since:** cli-base 0.52.0. **Rulings:** NEED-1732.
@@ -141,17 +148,32 @@ link is made and the pair goes to the owner's review list. Title or time overlap
141
148
 
142
149
  ## Planned — not built yet
143
150
 
144
- From the Wave 3 requirements (cli-private `plans/2026-10-24-open-cli-core-design.md`, under the owner's review):
145
-
146
- - a `files` table as the source record of `documents`: a materialised `path` plus `parent_id` to the folder's own
147
- row, so a folder is found by path prefix and a document by part of its path (NEED-1739);
148
- - memo's vault files as documents; an Obsidian vault is provider `obsidian` with its own metadata (tags, aliases,
149
- wiki links), a plain folder is `local`; `notes` are only the owner's notes on entities (NEED-1738);
150
- - a cli-core helper that opens a CLI's own SQLite file (NEED-1737);
151
- - `calendars`, `calendar_entries` and `calendar_attendees` on the `events` hub;
152
- - an `email` column on contacts, so one address joins one person across sources;
153
- - one link log for events and documents, and one review list for ambiguous pairs;
154
- - renaming `identities` to `contacts`.
151
+ From the Wave 3 requirements, approved by the owner on 2026-10-24 (cli-private
152
+ `plans/2026-10-24-open-cli-core-design.md`, sections 3.3–3.6). Each item moves into the rules in the pull request that
153
+ builds it.
154
+
155
+ - **Files.** A `files` table holds the source records of `documents`: one row per item in one place (a local file, a
156
+ Drive file or folder, later a Notion page). It has `account_id`, `external_id` (a local file's path relative to its
157
+ root), `kind` (`file`, `folder`, `page`), `name`, `path` and `path_folded` from the account root, `parent_id` to the
158
+ folder's own row, `document_id`, the file facts and the provider's times (NEED-1739).
159
+ - **Matching a file to a document:** the same account and `external_id` is the same file; a `content_hash` equal to
160
+ the preferred file of exactly one live document joins that document; more than one candidate goes to the review
161
+ list; otherwise a new document. The document shows its most recently changed file, unless the owner pins one.
162
+ - **Folder accounts by kind.** Provider `obsidian` for a vault (front matter, tags, aliases and wiki links kept as
163
+ Obsidian's own metadata), `local` for a plain folder; Drive files under a real `google-drive` account. memo's vault
164
+ files are documents; `notes` are only the owner's notes on entities (NEED-1738).
165
+ - **Calendars.** `calendars` and `calendar_entries` (source records) feed `events` and `event_series` (entities).
166
+ Attendees are `calendar_entry_participants`; changes to tracked fields go to `calendar_entry_revisions` first. An
167
+ entry joins an event by, in order: the same Google id; the same series slot (`original_starts_at`); the same
168
+ `ical_uid` in another calendar; a Zoom event with the same `join_key` and an overlapping time; else a new event.
169
+ - **History on delete.** An event deleted in Google keeps its past occurrences with `source_deleted_at`; future ones
170
+ become `cancelled`. Nothing is removed without an explicit owner command (NEED-1764).
171
+ - **Contacts by address.** A lower-cased `identities.email` column; contacts with the same address link to one
172
+ person (method `email`) unless the owner said otherwise; two persons with one address go to the review list.
173
+ - **One link log and one review list.** `entity_link_events` logs link changes for events and documents in the shape
174
+ of `identity_link_events`; one review list of ambiguous pairs for every entity, resolved by the owner.
175
+ - **A CLI's own SQLite file**, opened through a cli-core helper ([Store](store.md), NEED-1737).
176
+ - **Later:** renaming `identities` to `contacts`; dropping `documents`' source columns once nothing reads them.
155
177
 
156
178
  ## Sources
157
179
 
@@ -1,6 +1,6 @@
1
1
  # Security
2
2
 
3
- <!-- cspell:words zizmor -->
3
+ <!-- cspell:words zizmor PKCE -->
4
4
 
5
5
  ## Scope
6
6
 
@@ -271,6 +271,21 @@ not carried out. A name that matches is not proof of who someone is.
271
271
  tells an agent about it is [WC-MCP-11](mcp.md#wc-mcp-11--the-server-tells-the-agent-that-message-text-is-data).
272
272
  - **Applies to:** all CLIs. **Since:** cli-base 0.44.0. **Rulings:** none.
273
273
 
274
+ ## Planned — not built yet
275
+
276
+ From the Wave 3 requirements, approved by the owner on 2026-10-24 (sections 3.4 and 3.7). Each item moves into the
277
+ rules in the pull request that builds it.
278
+
279
+ - **One sign-in module** in cli-core, `@wirecat/cli-core/oauth`, with no store and no search: authorize (a loopback
280
+ address on `127.0.0.1` or a relay page, `state`, PKCE S256, a timeout, cancel, a paste fallback), exchange, refresh
281
+ and revoke, and a token keeper with a lock per profile across processes. A CLI declares its provider and may
282
+ replace any step, but keeps the explicit profile, the lock, and tokens that are never printed (NEED-1734).
283
+ - **Keys in one place:** one keyring naming scheme for new entries; today's entries of drive and zm are read as they
284
+ are, so no one signs in again.
285
+ - **Meeting secrets never reach the store:** passcodes, PINs, passwords and access codes from a calendar's conference
286
+ data, and the query string of any join URL. Lines of a description that carry a passcode, password or PIN are
287
+ removed.
288
+
274
289
  ## Sources
275
290
 
276
291
  These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
@@ -185,6 +185,17 @@ messages), or other people's data.
185
185
  - **Exceptions:** none.
186
186
  - **Applies to:** all CLIs that use the store, and cli-core. **Since:** cli-base 0.41.0. **Rulings:** none.
187
187
 
188
+ ## Planned — not built yet
189
+
190
+ From the Wave 3 requirements, approved by the owner on 2026-10-24 (NEED-1737). It moves into the rules in the pull
191
+ request that builds the helper.
192
+
193
+ - **A CLI's own tables live in its own SQLite file**, next to the shared store, with its own migrations. They refer to
194
+ core rows by id only, and no other CLI opens that file. A cli-core helper opens it (the path, the migrations, the
195
+ same driver); it is built when the first CLI needs private tables.
196
+ - **WC-STORE-5 gets a check:** a grit plugin, `no-sqlite-driver`, that refuses a CLI's import of a SQLite driver or
197
+ of `drizzle-orm`. cli-core, which owns the store, turns it off.
198
+
188
199
  ## Sources
189
200
 
190
201
  These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-base",
3
- "version": "0.52.0",
3
+ "version": "0.53.0",
4
4
  "description": "The parts every command line tool needs: output modes, terminal rendering, error model, exit codes, credentials, clocks",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Viacheslav Ptsarev",