@wirecat/cli-base 0.63.0 → 0.65.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 +232 -0
- package/dist/codegen/discovery.d.ts +3 -3
- package/dist/codegen/discovery.js +18 -9
- package/dist/codegen/index.d.ts +3 -1
- package/dist/codegen/index.js +3 -1
- package/dist/codegen/json-schema.d.ts +8 -0
- package/dist/codegen/json-schema.js +78 -0
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.js +1 -1
- package/dist/credentials.d.ts +1 -1
- package/dist/dev/bundle.d.ts +31 -0
- package/dist/dev/bundle.js +280 -0
- package/dist/dev/main.js +48 -1
- package/dist/skill/index.d.ts +1 -1
- package/dist/skill/index.js +2 -2
- package/dist/standards/audit.js +8 -0
- package/dist/standards/flags-calendar.d.ts +2 -0
- package/dist/standards/flags-calendar.js +72 -0
- package/dist/standards/flags-how.js +7 -1
- package/dist/standards/flags-what.js +7 -0
- package/dist/standards/vocabulary.js +13 -2
- package/docs/standards/README.md +5 -5
- package/docs/standards/accounts.md +44 -11
- package/docs/standards/architecture.md +19 -12
- package/docs/standards/ci.md +33 -12
- package/docs/standards/commands.md +35 -10
- package/docs/standards/data-model.md +5 -1
- package/docs/standards/docs.md +4 -1
- package/docs/standards/kit-surface.md +6 -5
- package/docs/standards/layout.md +32 -0
- package/docs/standards/lifecycle.md +69 -8
- package/docs/standards/mcp.md +48 -24
- package/docs/standards/new-cli.md +30 -16
- package/docs/standards/output.md +13 -2
- package/docs/standards/permissions.md +46 -3
- package/docs/standards/releases.md +21 -5
- package/docs/standards/security.md +16 -8
- package/docs/standards/store.md +4 -3
- package/docs/standards/testing.md +19 -8
- package/docs/standards/time.md +8 -1
- package/docs/standards/toolchain.md +24 -18
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,238 @@ 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.65.0 — 27.10.2026
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Calendar words for moving an event and for "this and all following".** Flag `--following` (`target`, switch):
|
|
16
|
+
this occurrence and every later one of a repeating event (`events update|delete --following`), beside `--series`.
|
|
17
|
+
`--scope` already means personal or work, so it is not reused. Flag `--to-calendar <id>` (`target`, id): the
|
|
18
|
+
calendar an event moves to (`events move --to-calendar`); `--calendar` keeps its meaning, the calendar the event is
|
|
19
|
+
on. The verb `move` now says what moves in general: a file to a folder, an event to a calendar. cli-core's shared
|
|
20
|
+
calendar commands use all three; gcal-cli carries `lint/overrides.json` entries for them until this release.
|
|
21
|
+
- **Every CLI that signs in has `session start`, `session status`, `session end` and a profile-free `session list`.**
|
|
22
|
+
[WC-ACCT-12](docs/standards/accounts.md#wc-acct-12--sign-in-is-session-start-status-and-end-and-session-list-names-the-profiles)
|
|
23
|
+
is the owner's ruling: `status` says whether one profile is signed in, `list` which profiles exist. Each
|
|
24
|
+
CLI's missing commands are listed as known gaps: tg, max and wa lack `session status` and list profiles with
|
|
25
|
+
`account list`; drive lacks `session status`; gcal lacks `session list`; zm lacks `session end` and `session list`;
|
|
26
|
+
memo has no `session` group.
|
|
27
|
+
- **A sync spends a request budget sized to its deadline and says how to continue.**
|
|
28
|
+
[WC-LIFE-16](docs/standards/lifecycle.md#wc-life-16--a-sync-spends-a-request-budget-sized-to-its-deadline-and-its-answer-says-how-to-continue)
|
|
29
|
+
describes what cli-core 0.464.0 (cli-core #2118) builds for the calendar sync: `floor((deadline − margin) /
|
|
30
|
+
requestMs)` requests, one `requestMs` per CLI, `--max-pages` only lowering it, a partial stop that exits 0 with the
|
|
31
|
+
exact command to continue, and progress in the sync's status command. The other syncs and gcal's own `requestMs`
|
|
32
|
+
are listed as gaps.
|
|
33
|
+
|
|
34
|
+
- **The command vocabulary has the verbs `serve` (run a server in this process and answer its clients until stopped)
|
|
35
|
+
and `revoke` (take back what was granted, so it stops working).** cli-core 0.463.0 names the MCP server
|
|
36
|
+
`mcp serve` and gives forgetting browser logins its own command, `mcp revoke`; `revoke` also covers
|
|
37
|
+
`chats link revoke` and the `consents revoke` commands that were baselined as unknown verbs.
|
|
38
|
+
|
|
39
|
+
### Changed — may break callers
|
|
40
|
+
|
|
41
|
+
- **A command that reads the service and only saves what it read is a read, also over MCP.**
|
|
42
|
+
[WC-CMD-17](docs/standards/commands.md#wc-cmd-17--declare-effects-on-every-command) defines a write, and WC-CMD-6,
|
|
43
|
+
WC-CMD-28, [WC-MCP-4](docs/standards/mcp.md#wc-mcp-4--read-runs-only-reading-commands-and-write-only-writing-ones)
|
|
44
|
+
and WC-OUT-9 point at it: `{ remote: "read", local: "write" }` (`sync`, `calendars list`) runs through the `read`
|
|
45
|
+
tool; `{ remote: "none", local: "write" }` (`store reindex`) stays a write. cli-base's `writes()` still counts every
|
|
46
|
+
local write, so cli-core serves `sync` through `write` until a follow-up changes it; watch for that release, which
|
|
47
|
+
moves those commands between tools.
|
|
48
|
+
- **Deadlines: 30 s for a one-shot command, 5 min for a cooperative one at a terminal and 45 s over MCP.**
|
|
49
|
+
[WC-LIFE-5](docs/standards/lifecycle.md#wc-life-5--bound-every-one-shot-command-by-a-deadline) and WC-LIFE-10 say
|
|
50
|
+
so, as cli-core 0.464.0 builds it, because MCP clients cut a tool call at about 60 s.
|
|
51
|
+
- **A non-messenger CLI allows ordinary writes, asks before deletes, and denies mail to other people and deleting
|
|
52
|
+
a whole series.**
|
|
53
|
+
[WC-PERM-22](docs/standards/permissions.md#wc-perm-22--a-cli-that-is-not-a-messenger-declares-its-own-keys-and-defaults-with-commandpermissions)
|
|
54
|
+
follows the owner's ruling, and a CLI's generic API path must check the shared keys (`events.notify`,
|
|
55
|
+
`events.delete.series`) too. Its example said sharing a calendar is `deny`; the owner made it `ask`. cli-core's
|
|
56
|
+
`CALENDAR_WRITE_DEFAULTS` and gcal's `api` defaults do not follow it yet; both are listed as gaps.
|
|
57
|
+
- **Meeting passcodes stay out of command output and agent answers, not only out of the store.**
|
|
58
|
+
[WC-SECR-23](docs/standards/security.md) covers answers that come straight from the provider: gcal's `api` answers
|
|
59
|
+
still keep a description's passcode lines, a listed gap.
|
|
60
|
+
- **Each CLI pins the command catalogue behind its MCP tools.** The [MCP](docs/standards/mcp.md) page no longer
|
|
61
|
+
claims `mcp-tools.json` pins the catalogue: with three tools it does not. `contracts/mcp-catalogue.json` does; tg and
|
|
62
|
+
max have it, and wa, zm, gcal and drive do not yet.
|
|
63
|
+
|
|
64
|
+
- **An MCP server serves the profiles it is told, and refuses without them.**
|
|
65
|
+
[WC-MCP-9](docs/standards/mcp.md#wc-mcp-9--a-server-serves-the-profiles-it-is-told-with-one-connection-for-each)
|
|
66
|
+
now allows one named profile (`<cli> <profile> mcp serve`), a list (`<cli> mcp serve --profiles work,personal`) or
|
|
67
|
+
every profile (`<cli> mcp serve --profiles all`), with one messenger connection per served profile. With no profile
|
|
68
|
+
and no `--profiles`, `mcp serve` fails with `validation_error` and lists the profiles; it never serves every profile
|
|
69
|
+
by default. With several profiles, each call names its profile. WC-ACCT-1, WC-ACCT-2 and WC-ACCT-5 say how
|
|
70
|
+
`--profiles` fits the profile rules, and a profile lock refuses `--profiles all`. The flag registry has `--profiles`.
|
|
71
|
+
The owner ruled it; cli-core does not build `--profiles` yet.
|
|
72
|
+
- **The handbook names the MCP server `mcp serve` and has no `mcp --revoke` exception.** The
|
|
73
|
+
[MCP](docs/standards/mcp.md) and [Lifecycle](docs/standards/lifecycle.md) pages say `mcp serve`, `mcp serve --http`,
|
|
74
|
+
`mcp serve --permission`, `bot mcp serve` and `mcp revoke`, as cli-core 0.463.0 builds them.
|
|
75
|
+
[WC-CMD-6](docs/standards/commands.md#wc-cmd-6--give-one-action-or-one-report-one-leaf-command) no longer lets
|
|
76
|
+
`--revoke` stay an option: forgetting every browser login is the `mcp revoke` command. A CLI with its own server
|
|
77
|
+
(drive, memo, zoom) moves to the same shape.
|
|
78
|
+
- **A lint baseline entry for `serve` or `revoke` goes stale, and `cli-dev lint` fails on it.** cli-core lists
|
|
79
|
+
`bot mcp serve`, `mcp serve`, `mcp revoke` and `replies consents revoke` in `lint/baseline/unknown-verb.json`;
|
|
80
|
+
tg-cli and max-cli list `replies consents revoke`. Remove those entries in the same change that takes this version.
|
|
81
|
+
- **The HTTP MCP server rule covers every CLI that offers `mcp serve --http`, not only the messenger CLIs.**
|
|
82
|
+
[WC-MCP-12](docs/standards/mcp.md#wc-mcp-12--an-mcp-server-over-http-follows-the-same-permissions-and-short-lived-logins)
|
|
83
|
+
now applies to cli-template and every CLI made from it, which have offered `mcp serve --http` with no rule over it.
|
|
84
|
+
The template already follows it; a CLI that changed its copy of the HTTP server checks it against the rule.
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
|
|
88
|
+
- **`cli-dev audit` compares gcal only on the commands it already shares with every CLI, for now.** cli-base 0.64.0
|
|
89
|
+
put gcal into the `all` parity group, and gcal's release audit then blocked on 20 `same-path-contract` differences
|
|
90
|
+
in `doctor`, `mcp`, `search` and `skill` that already exist among the other six published CLIs and that gcal
|
|
91
|
+
cannot remove alone (gcal-cli#13). gcal leaves `all` and has its own group, `gcal-shared`, with every CLI over
|
|
92
|
+
`commands`, `upgrade`, `notes` and `meetings`. It rejoins `all` once tg, max, wa, drive, zoom and memo release on
|
|
93
|
+
cli-core's shared `mcp serve`, `doctor` and `skill` ([#390](https://github.com/WireCatLabs/cli-base/issues/390)).
|
|
94
|
+
The other CLIs' audits are unchanged: a path is compared across every member of every group that covers it.
|
|
95
|
+
|
|
96
|
+
- **`cli-dev bundle`'s loader finds a server after a flag: `<cli> personal --read-only mcp serve`.** It looked for
|
|
97
|
+
`serve`, `watch` or `mcp` in the first three words of the command, and since cli-core 0.463 named the server
|
|
98
|
+
`mcp serve`, a flag before it pushed `serve` to the fourth word. Such a server loaded no chunks ahead and could fail
|
|
99
|
+
after an in-place upgrade (measured on drive: 91 of 138 chunks loaded, instead of 138). The loader now skips flags
|
|
100
|
+
and looks at four words. Rebuild a CLI with this release to take it.
|
|
101
|
+
- **The handbook no longer contradicts itself on gcal's audit findings.**
|
|
102
|
+
- WC-OUT-8 and WC-OUT-14: an answer with `meta.complete: false` is an answer on stdout, also after a non-zero
|
|
103
|
+
exit; only a run with no answer prints one JSON error with stdout empty.
|
|
104
|
+
- WC-CMD-10 names `--max-pages` a `budget` option, not a paging one, and says why the calendar `--id` exists beside
|
|
105
|
+
`--operation-id`; gcal's `events create`, with `--id` and no `--operation-id`, is a listed gap. WC-CMD-11 lists `--duration-minutes` as a known gap until the vocabulary has
|
|
106
|
+
`--duration <duration>`.
|
|
107
|
+
- WC-REL-16 says `packContents` checks the pack against the list it is given, so a check that passes the `files`
|
|
108
|
+
list itself cannot fail on a wrong list; the fix belongs in cli-template.
|
|
109
|
+
- WC-TIME-5 matches an all-day event by local dates, not UTC moments; cli-core's event filter is a listed gap.
|
|
110
|
+
- WC-ARCH-3 counts generated API types as vendor types, WC-ARCH-5 and WC-ARCH-6 cover calendar CLIs, and
|
|
111
|
+
WC-ARCH-21's example is gcal's real provider entry.
|
|
112
|
+
- WC-TOOL-16 puts a word waiting for the vocabulary in `lint/overrides.json` with a link and a date, never in the
|
|
113
|
+
baseline. The [Documents](docs/standards/docs.md#wc-doc-3--every-document-states-current-facts-rewrite-a-wrong-sentence-in-place)
|
|
114
|
+
rule on current facts sends a false template-owned file to cli-template.
|
|
115
|
+
- WC-DATA-3 makes a calendar entry's `external_id` unique per calendar, WC-STORE-3 lists the calendar areas as not
|
|
116
|
+
bound, WC-TEST-12 says what a reason names, and WC-TEST-14 counts the shared store as local state.
|
|
117
|
+
- The "who follows" lists name gcal.
|
|
118
|
+
|
|
119
|
+
- **The handbook's pages on the template match cli-template 0.9.0.** The [Kit surface](docs/standards/kit-surface.md)
|
|
120
|
+
table lists `LOCAL_WRITE` and `revokeAll`, which the template now imports, and counts imports loaded on demand.
|
|
121
|
+
[New CLI](docs/standards/new-cli.md) says the MCP server has three tools that reach every command, not a tool for
|
|
122
|
+
every command.
|
|
123
|
+
- **The handbook says where a lint violation that a shared package forces goes, and which cli-core files are not a
|
|
124
|
+
CLI's local state.** [WC-TOOL-16](docs/standards/toolchain.md) puts such a violation in the CLI's lint baseline
|
|
125
|
+
until the shared package catches up.
|
|
126
|
+
[WC-TEST-14](docs/standards/testing.md#wc-test-14--check-the-upgrade-from-the-previous-published-version) names
|
|
127
|
+
the update check, MCP logins and lock files that only cli-core writes as outside the upgrade contract; tests still
|
|
128
|
+
keep them in the sandboxed home.
|
|
129
|
+
|
|
130
|
+
## 0.64.0 — 27.10.2026
|
|
131
|
+
|
|
132
|
+
### Added
|
|
133
|
+
|
|
134
|
+
- **`cli-dev bundle --bin dist/bin/<cli>.js` builds the published bin as an esbuild bundle, the way tg-cli 0.100.0
|
|
135
|
+
ships.** It moves tg's `scripts/bundle.ts` into cli-base so every CLI builds the same way: code splitting that keeps
|
|
136
|
+
each lazy `import()` lazy; `import.meta.url` and run-time package lookups that stay at the original module's place
|
|
137
|
+
in the CLI, cli-core and cli-base; CommonJS named exports for a dynamic `import("yaml")`; kept names; native and
|
|
138
|
+
by-name packages left outside. The bin becomes a loader that answers `--version`, turns the compile cache on and,
|
|
139
|
+
under `serve`, `watch` and `mcp`, preloads every chunk so a running server survives an in-place upgrade. The build
|
|
140
|
+
fails when a bundled module would look in the wrong place. Add `esbuild` (an optional peer, `^0.28.0`) as a
|
|
141
|
+
devDependency and name the CLI's own outside packages with `--external`. The rule is
|
|
142
|
+
[WC-LAY-10](docs/standards/layout.md#wc-lay-10--ship-the-bin-as-a-bundle-that-cli-dev-bundle-builds).
|
|
143
|
+
- **WC-PERM-22 on the [Permissions](docs/standards/permissions.md) page: a CLI that is not a messenger declares its
|
|
144
|
+
own permission keys and defaults with cli-core's `commandPermissions`** (cli-core 0.450.0). It says how such a CLI
|
|
145
|
+
keys its commands, picks built-in defaults for what its writes do, and runs writes through the read-only lock and the
|
|
146
|
+
write guard. The example is a calendar: event writes ask, deleting a whole series and mailing attendees are denied
|
|
147
|
+
until the owner allows them. The page covered messenger CLIs only, and WC-PERM-6's "ask only before what cannot be
|
|
148
|
+
undone" read as if it applied to a calendar too; it now says it is the messengers' list. drive, zoom and memo do
|
|
149
|
+
not declare `commandPermissions` yet; the rule names them as known gaps.
|
|
150
|
+
- **`cli-dev audit` compares gcal (`@wirecat/gcal-cli`, the Google Calendar CLI) in the `all` parity group**, next to
|
|
151
|
+
tg, max, memo, drive, zm and wa, so its shared root commands are held to the same options and summaries. A run
|
|
152
|
+
without gcal's command tree skips it, as before; the weekly audit adds it once gcal is published on npm.
|
|
153
|
+
- **The command vocabulary has the words a calendar CLI needs.** Verbs `unsync` (stop syncing a thing; what is
|
|
154
|
+
stored stays), `review` (list what waits for the owner's decision) and `resolve` (settle one such thing with the
|
|
155
|
+
owner's choice); collections `calendars`, `events` and `people`. `events` was only a view word, so a command group
|
|
156
|
+
named `events` was reported by `unknown-resource`.
|
|
157
|
+
- **The vocabulary has the flags and the verb of calendar writes** (cli-core's `events create | update | delete |
|
|
158
|
+
respond`). Flags `--end-time`, `--start-date`, `--end-date`, `--location`, `--attendee` (repeat it for more),
|
|
159
|
+
`--id` (the id a create is made with) as `value`; `--calendar` and `--series` as `target`; `--no-notify` as `mode`.
|
|
160
|
+
`--notify` now means telling the people a change concerns — a chat's members or an event's attendees. Verb
|
|
161
|
+
`respond` (answer an invitation). Without them `option-role` and `unknown-verb` reported every calendar CLI's
|
|
162
|
+
write commands.
|
|
163
|
+
- **The vocabulary has the words of free/busy and repeating events** (cli-core's `calendars busy` and
|
|
164
|
+
`events create | update --repeat`). View `busy` (when calendars or people are taken, without what takes them);
|
|
165
|
+
flags `--repeat <rule>` (an RFC 5545 rule) as `value` and `--hours <from-to>` (the working hours to look in) as
|
|
166
|
+
`target`. gcal-cli overrides the four lint reports they cause until it takes this release.
|
|
167
|
+
|
|
168
|
+
- **`requestSchema(operation, definitions)` in `@wirecat/cli-base/codegen` builds the JSON Schema of a generated
|
|
169
|
+
operation's request body**, every referenced definition under `$defs`, or returns `null` when the operation takes
|
|
170
|
+
no body. drive-cli and gcal-cli each kept an identical copy for `api show`. Pass a manifest operation and the
|
|
171
|
+
`definitions` that `definitionsGenerator` wrote.
|
|
172
|
+
|
|
173
|
+
### Changed — may break callers
|
|
174
|
+
|
|
175
|
+
- **A lint baseline entry or override for a word that is now in the vocabulary goes stale, and `cli-dev lint` fails
|
|
176
|
+
on it.** This release adds `unsync`, `review`, `resolve`, `calendars`, `events` and `people`. zoom-cli lists
|
|
177
|
+
`events` in `lint/baseline/unknown-resource.json`; gcal-cli lists `calendars`, `events`, `people`,
|
|
178
|
+
`calendars unsync`, `links review` and `links resolve` in its baseline; drive-cli overrides `unknown-verb` for
|
|
179
|
+
`comments resolve`, and cli-memo for `search people`, in `lint/overrides.json`. Remove those entries in the same
|
|
180
|
+
change that takes this version.
|
|
181
|
+
- **The calendar write words make gcal-cli's write baseline stale too.** Its `lint/baseline/option-role.json` (20
|
|
182
|
+
entries under `events create | update | delete | respond`) and `events respond` in `unknown-verb.json` go stale
|
|
183
|
+
with this release; remove them when gcal takes it. No other CLI's baseline or overrides on `main` name these words.
|
|
184
|
+
- **The free/busy and repeat words make four of gcal-cli's overrides stale.** `lint/overrides.json` names
|
|
185
|
+
`calendars busy` (`unknown-verb`), `calendars busy --hours` and `events create | update --repeat` (`option-role`);
|
|
186
|
+
remove them when gcal takes this release.
|
|
187
|
+
|
|
188
|
+
- **`describeAlone` is no longer exported from `@wirecat/cli-base/commands`.** It was made public by accident in
|
|
189
|
+
0.62.0; it is a helper of the shared-command check and only works with a map kept for one check. No known caller
|
|
190
|
+
imports it. Describe a whole tree with `describeProgram` instead.
|
|
191
|
+
|
|
192
|
+
### Fixed
|
|
193
|
+
|
|
194
|
+
- **Handbook corrections from gcal-cli's first-release audit.**
|
|
195
|
+
- The Toolchain, CI, Security, Testing and Store pages listed "the ten repositories" and "the six CLIs" without
|
|
196
|
+
gcal. They now say "the WireCat repositories": every WireCat CLI, a new one from its first commit, and the shared
|
|
197
|
+
repositories. `gcal-cli` is a known repository name for "Enforced by".
|
|
198
|
+
- WC-SECR-4 said the keyring service is the command's name. It is the CLI's app name (`max-cli`, `gcal-cli`,
|
|
199
|
+
`cli-memo`), as cli-core passes it.
|
|
200
|
+
- WC-REL-16 says what a CLI's package `files` holds: `dist`, `skills`, `README.md`, `LICENSE` and what the CLI
|
|
201
|
+
reads or runs after install (`scenarios`, `install`, notices); `CHANGELOG.md` may ship. Never `src/`, tests,
|
|
202
|
+
scripts, workflows, `bin/release`, `config/`, `lint/`, `contracts/` or `template.json`.
|
|
203
|
+
- WC-REL-11 names its one exception: a package's first version, published by the owner with `bin/release --local`,
|
|
204
|
+
since npm sets a trusted publisher only for a package that exists. Step 2 of
|
|
205
|
+
[New CLI](docs/standards/new-cli.md) says the same.
|
|
206
|
+
- [New CLI](docs/standards/new-cli.md) says which copied files a CLI rewrites (seeds) and which it leaves to
|
|
207
|
+
cli-template (template-owned), and that a template-owned page wrong for the CLI is fixed in cli-template.
|
|
208
|
+
- "Done when" told authors to add a new CLI's shared audit findings to `audit/baseline`, which has not accepted
|
|
209
|
+
them since cli-base 0.51.0. It now says to fix each one, or declare an exact difference in the parity group.
|
|
210
|
+
- WC-CI-8 says the fresh-agent audit is given the pinned cli-base workflows.
|
|
211
|
+
- WC-TEST-12 has one exception: commands generated from an API description share one reason that names an
|
|
212
|
+
options-against-the-snapshot test and a test that drives a generated command through `run()`.
|
|
213
|
+
|
|
214
|
+
- **`syncDiscovery` writes the same snapshot for the same revision of a Google API.** Google serves one revision with
|
|
215
|
+
its object keys in a different order on each download, so two syncs gave different files, hashes and generated
|
|
216
|
+
code. The snapshot is now the parsed document with its keys sorted and 2-space indentation; values and array order
|
|
217
|
+
are unchanged. `sha256` is stable; `sourceSha256` is still the hash of the bytes Google served, so it can change
|
|
218
|
+
between syncs. The first sync after upgrading rewrites each snapshot once, and `pnpm generate` then reorders the
|
|
219
|
+
generated types, schemas and manifest once.
|
|
220
|
+
- **`skill show` now names every agent `skill install` serves: Claude Code, Codex, Gemini CLI, OpenClaw, and Hermes
|
|
221
|
+
on request.** Its help named only the first three, so OpenClaw and Hermes users could not tell the skill was meant
|
|
222
|
+
for them.
|
|
223
|
+
- **The [CI](docs/standards/ci.md) page lists the monthly cron minutes WireCat repositories already use**, under
|
|
224
|
+
WC-CI-9, and [New CLI](docs/standards/new-cli.md) step 3 points to it. Finding a free minute meant reading
|
|
225
|
+
`monthly.yml` in every repository. A new CLI adds its minute to the list in the same pull request that joins the
|
|
226
|
+
parity groups.
|
|
227
|
+
- **The [Kit surface](docs/standards/kit-surface.md) page lists every cli-core and cli-base export cli-template
|
|
228
|
+
0.7.0 imports**, among them the ones for MCP over HTTP: `mcpServerCommand`, `serveOverHttp`, `httpLockFile` and
|
|
229
|
+
the rest. The page left them out, so a change to them would not have been seen as one that reaches every new CLI.
|
|
230
|
+
- **[New CLI](docs/standards/new-cli.md) lets the fresh audit agent read the cli-base workflow files a CLI's
|
|
231
|
+
workflows pin.** WC-CI-8 tells an audit to read them, but the audit was limited to the handbook and the
|
|
232
|
+
repository. A release audit prompt kept in a CLI repository needs the same change.
|
|
233
|
+
- **WC-TEST-5 on the [Testing](docs/standards/testing.md) page says that a test may wait for a local process or
|
|
234
|
+
server it started**, polling with a timeout shorter than the test's own; a fixed sleep is still not allowed. It
|
|
235
|
+
was unclear whether such a wait counts as waiting for real time.
|
|
236
|
+
- **WC-CMD-6 on the [Commands](docs/standards/commands.md) page names `mcp --revoke` as an exception.** The rule says
|
|
237
|
+
an option never turns a command into a different action, and `--revoke` does: it forgets every browser login
|
|
238
|
+
instead of starting a server. The owner kept it an option on `mcp` because it belongs with the HTTP server's login
|
|
239
|
+
state. No other option gets this exception.
|
|
240
|
+
- **The handbook's examples start `gcal-cli` with the command `gcal`, not `cal`**, the system calendar program on macOS
|
|
241
|
+
and many Linux systems. A CLI named after it would shadow it.
|
|
242
|
+
|
|
11
243
|
## 0.63.0 — 27.10.2026
|
|
12
244
|
|
|
13
245
|
### Added
|
|
@@ -33,7 +33,7 @@ export interface DiscoveryProvenance {
|
|
|
33
33
|
version: string;
|
|
34
34
|
/** Of the committed file; `readDiscovery` refuses a snapshot that no longer matches it. */
|
|
35
35
|
sha256: string;
|
|
36
|
-
/** Of the bytes Google served.
|
|
36
|
+
/** Of the bytes Google served. Google varies its key order, so this one can change while `sha256` does not. */
|
|
37
37
|
sourceSha256: string;
|
|
38
38
|
normalization: string;
|
|
39
39
|
}
|
|
@@ -43,8 +43,8 @@ export interface SyncDiscoveryOptions {
|
|
|
43
43
|
fetch?: typeof globalThis.fetch;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* Downloads each Discovery document
|
|
47
|
-
* the diff: the build never fetches. `provenance.json` keeps the order of `sources`, and that order is
|
|
46
|
+
* Downloads each Discovery document, sorts its object keys so the same revision always gives the same file, and
|
|
47
|
+
* records where it came from. Run by hand, then review the diff: the build never fetches. `provenance.json` keeps the order of `sources`, and that order is
|
|
48
48
|
* the order of the generated schemas.
|
|
49
49
|
*/
|
|
50
50
|
export declare const syncDiscovery: (sources: Readonly<Record<string, string>>, options: SyncDiscoveryOptions) => Promise<Record<string, DiscoveryProvenance>>;
|
|
@@ -240,9 +240,18 @@ export const adaptDiscovery = (documents, options = {}) => {
|
|
|
240
240
|
};
|
|
241
241
|
};
|
|
242
242
|
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
243
|
+
/** Google serves the same revision with its keys in a different order each time; arrays keep theirs. */
|
|
244
|
+
const sortKeys = (value) => Array.isArray(value)
|
|
245
|
+
? value.map(sortKeys)
|
|
246
|
+
: object(value)
|
|
247
|
+
? Object.fromEntries(Object.keys(value)
|
|
248
|
+
.sort()
|
|
249
|
+
.map((key) => [key, sortKeys(value[key])]))
|
|
250
|
+
: value;
|
|
251
|
+
const NORMALIZATION = "object keys sorted, 2-space JSON; values and array order unchanged";
|
|
243
252
|
/**
|
|
244
|
-
* Downloads each Discovery document
|
|
245
|
-
* the diff: the build never fetches. `provenance.json` keeps the order of `sources`, and that order is
|
|
253
|
+
* Downloads each Discovery document, sorts its object keys so the same revision always gives the same file, and
|
|
254
|
+
* records where it came from. Run by hand, then review the diff: the build never fetches. `provenance.json` keeps the order of `sources`, and that order is
|
|
246
255
|
* the order of the generated schemas.
|
|
247
256
|
*/
|
|
248
257
|
export const syncDiscovery = async (sources, options) => {
|
|
@@ -257,20 +266,20 @@ export const syncDiscovery = async (sources, options) => {
|
|
|
257
266
|
const document = JSON.parse(raw);
|
|
258
267
|
if (!object(document) || document.name !== service)
|
|
259
268
|
throw new Error(`${source} is not the Discovery document of ${service}`);
|
|
260
|
-
const
|
|
261
|
-
downloaded[service] =
|
|
269
|
+
const written = `${JSON.stringify(sortKeys(document), null, 2)}\n`;
|
|
270
|
+
downloaded[service] = written;
|
|
262
271
|
provenance[service] = {
|
|
263
272
|
source,
|
|
264
273
|
revision: String(document.revision),
|
|
265
274
|
version: String(document.version),
|
|
266
|
-
sha256:
|
|
267
|
-
sourceSha256:
|
|
268
|
-
normalization:
|
|
275
|
+
sha256: sha256(written),
|
|
276
|
+
sourceSha256: sha256(raw),
|
|
277
|
+
normalization: NORMALIZATION,
|
|
269
278
|
};
|
|
270
279
|
}
|
|
271
280
|
mkdirSync(options.dir, { recursive: true });
|
|
272
|
-
for (const [service,
|
|
273
|
-
writeFileSync(join(options.dir, `${service}.json`),
|
|
281
|
+
for (const [service, text] of Object.entries(downloaded))
|
|
282
|
+
writeFileSync(join(options.dir, `${service}.json`), text);
|
|
274
283
|
writeFileSync(join(options.dir, "provenance.json"), `${JSON.stringify(provenance, null, 2)}\n`);
|
|
275
284
|
return provenance;
|
|
276
285
|
};
|
package/dist/codegen/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Turns an official API description into committed code: types, Valibot schemas, an operation
|
|
3
|
-
* manifest and a coverage page. Build-time
|
|
3
|
+
* manifest and a coverage page. Build-time, apart from the small helpers a CLI reads the generated
|
|
4
|
+
* files with (`identifier`, `requestSchema`), and format-neutral: it parses no file format and
|
|
4
5
|
* adds no dependency. `adaptOpenApi` reads an OpenAPI document and `adaptDiscovery` Google Discovery
|
|
5
6
|
* documents the consumer has parsed; an adapter from Postman or anything else lives in the consumer.
|
|
6
7
|
*/
|
|
7
8
|
export { adaptDiscovery, type DiscoveryMetadata, type DiscoveryOptions, type DiscoveryProvenance, type DiscoveryResult, type DiscoveryService, readDiscovery, type SyncDiscoveryOptions, syncDiscovery, } from "./discovery.js";
|
|
9
|
+
export { requestSchema } from "./json-schema.js";
|
|
8
10
|
export { type CoverageOptions, coverageGenerator, definitionsGenerator, type ManifestOperation, manifestGenerator, } from "./manifest.js";
|
|
9
11
|
export type { ApiBody, ApiModel, ApiOperation, ApiParameter, ApiSchema, Binding, CodeGenerator, Confidence, Discriminator, Effect, GeneratedArtifact, HttpBinding, HttpMethod, Override, RpcBinding, SchemaNode, SourceInfo, SourceReference, } from "./model.js";
|
|
10
12
|
export { identifier, kebab } from "./names.js";
|
package/dist/codegen/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Turns an official API description into committed code: types, Valibot schemas, an operation
|
|
3
|
-
* manifest and a coverage page. Build-time
|
|
3
|
+
* manifest and a coverage page. Build-time, apart from the small helpers a CLI reads the generated
|
|
4
|
+
* files with (`identifier`, `requestSchema`), and format-neutral: it parses no file format and
|
|
4
5
|
* adds no dependency. `adaptOpenApi` reads an OpenAPI document and `adaptDiscovery` Google Discovery
|
|
5
6
|
* documents the consumer has parsed; an adapter from Postman or anything else lives in the consumer.
|
|
6
7
|
*/
|
|
7
8
|
export { adaptDiscovery, readDiscovery, syncDiscovery, } from "./discovery.js";
|
|
9
|
+
export { requestSchema } from "./json-schema.js";
|
|
8
10
|
export { coverageGenerator, definitionsGenerator, manifestGenerator, } from "./manifest.js";
|
|
9
11
|
export { identifier, kebab } from "./names.js";
|
|
10
12
|
export { adaptOpenApi, OpenApiError } from "./openapi.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ManifestOperation } from "./manifest.js";
|
|
2
|
+
import type { SchemaNode } from "./model.js";
|
|
3
|
+
/**
|
|
4
|
+
* The JSON Schema (draft 2020-12) of an operation's request body, built from the `definitions` that
|
|
5
|
+
* `definitionsGenerator` wrote, with every referenced definition under `$defs`; `null` when the operation takes no
|
|
6
|
+
* body. For a CLI's `api show`, so an agent sees what to send before it calls.
|
|
7
|
+
*/
|
|
8
|
+
export declare const requestSchema: (operation: Pick<ManifestOperation, "request">, definitions: Readonly<Record<string, SchemaNode>>) => Record<string, unknown> | null;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { identifier } from "./names.js";
|
|
2
|
+
/**
|
|
3
|
+
* The JSON Schema (draft 2020-12) of an operation's request body, built from the `definitions` that
|
|
4
|
+
* `definitionsGenerator` wrote, with every referenced definition under `$defs`; `null` when the operation takes no
|
|
5
|
+
* body. For a CLI's `api show`, so an agent sees what to send before it calls.
|
|
6
|
+
*/
|
|
7
|
+
export const requestSchema = (operation, definitions) => {
|
|
8
|
+
if (!operation.request?.schema)
|
|
9
|
+
return null;
|
|
10
|
+
const defs = {};
|
|
11
|
+
const visiting = new Set();
|
|
12
|
+
const node = (value) => {
|
|
13
|
+
const common = { ...(value.description ? { description: value.description } : {}) };
|
|
14
|
+
switch (value.type) {
|
|
15
|
+
case "ref": {
|
|
16
|
+
const name = identifier(value.ref);
|
|
17
|
+
add(name);
|
|
18
|
+
return { ...common, $ref: `#/$defs/${name}` };
|
|
19
|
+
}
|
|
20
|
+
case "unknown":
|
|
21
|
+
return common;
|
|
22
|
+
case "union":
|
|
23
|
+
return { ...common, anyOf: value.of.map(node) };
|
|
24
|
+
case "allOf":
|
|
25
|
+
return { ...common, allOf: value.of.map(node) };
|
|
26
|
+
case "object":
|
|
27
|
+
return {
|
|
28
|
+
...common,
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: Object.fromEntries(Object.entries(value.properties).map(([key, item]) => [key, node(item)])),
|
|
31
|
+
required: value.required,
|
|
32
|
+
additionalProperties: value.additionalProperties ? node(value.additionalProperties) : true,
|
|
33
|
+
};
|
|
34
|
+
case "array":
|
|
35
|
+
return {
|
|
36
|
+
...common,
|
|
37
|
+
type: "array",
|
|
38
|
+
items: node(value.items),
|
|
39
|
+
...(value.minItems === undefined ? {} : { minItems: value.minItems }),
|
|
40
|
+
...(value.maxItems === undefined ? {} : { maxItems: value.maxItems }),
|
|
41
|
+
};
|
|
42
|
+
case "string":
|
|
43
|
+
return {
|
|
44
|
+
...common,
|
|
45
|
+
type: "string",
|
|
46
|
+
...(value.enum ? { enum: value.enum } : {}),
|
|
47
|
+
...(value.pattern ? { pattern: value.pattern } : {}),
|
|
48
|
+
...(value.minLength === undefined ? {} : { minLength: value.minLength }),
|
|
49
|
+
...(value.maxLength === undefined ? {} : { maxLength: value.maxLength }),
|
|
50
|
+
};
|
|
51
|
+
case "boolean":
|
|
52
|
+
return { ...common, type: "boolean" };
|
|
53
|
+
case "integer":
|
|
54
|
+
case "number":
|
|
55
|
+
return {
|
|
56
|
+
...common,
|
|
57
|
+
type: value.type,
|
|
58
|
+
...(value.minimum === undefined ? {} : { minimum: value.minimum }),
|
|
59
|
+
...(value.maximum === undefined ? {} : { maximum: value.maximum }),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const add = (name) => {
|
|
64
|
+
if (visiting.has(name))
|
|
65
|
+
return;
|
|
66
|
+
visiting.add(name);
|
|
67
|
+
const value = definitions[name];
|
|
68
|
+
if (!value)
|
|
69
|
+
throw new Error(`generated schema reference is missing: ${name}`);
|
|
70
|
+
defs[name] = node(value);
|
|
71
|
+
};
|
|
72
|
+
add(operation.request.schema);
|
|
73
|
+
return {
|
|
74
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
75
|
+
$ref: `#/$defs/${operation.request.schema}`,
|
|
76
|
+
$defs: defs,
|
|
77
|
+
};
|
|
78
|
+
};
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import type { Command } from "commander";
|
|
13
13
|
export { type CommandsDocument, type CommandsDocumentAbout, commandsDocument, commandsDocumentJsonSchema, commandsDocumentSchema, parseCommandsDocument, } from "./document.js";
|
|
14
14
|
export { COMMANDS_PAGE_LABELS, type CommandsPage, type CommandsPageLabels, type CommandsPageText, commandsPage, } from "./page.js";
|
|
15
|
-
export
|
|
15
|
+
export { type ArgumentInfo, annotate, annotateOption, type CommandInfo, type CommandLifetime, type CommandMeta, type CommandOutput, type CommandReach, type CommandState, describeOptions, describeProgram, flatten, metaOf, type OptionInfo, type OptionMeta, type Origin, optionMetaOf, stepTargets, } from "./registry.js";
|
|
16
16
|
/**
|
|
17
17
|
* Refuses a command path that arrived as one argument — `"projects add" --help`, what a zsh loop over
|
|
18
18
|
* `$c` passes. Commander settles `--help` for an unknown word before any hook runs and prints the root
|
package/dist/commands/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CliError } from "../errors.js";
|
|
2
2
|
export { commandsDocument, commandsDocumentJsonSchema, commandsDocumentSchema, parseCommandsDocument, } from "./document.js";
|
|
3
3
|
export { COMMANDS_PAGE_LABELS, commandsPage, } from "./page.js";
|
|
4
|
-
export
|
|
4
|
+
export { annotate, annotateOption, describeOptions, describeProgram, flatten, metaOf, optionMetaOf, stepTargets, } from "./registry.js";
|
|
5
5
|
/**
|
|
6
6
|
* Refuses a command path that arrived as one argument — `"projects add" --help`, what a zsh loop over
|
|
7
7
|
* `$c` passes. Commander settles `--help` for an unknown word before any hook runs and prints the root
|
package/dist/credentials.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface StoredCredential {
|
|
|
9
9
|
export interface CredentialsOptions {
|
|
10
10
|
/** Where the fallback file lives when the keyring cannot be used. */
|
|
11
11
|
configDir: string;
|
|
12
|
-
/** The keyring service name — the
|
|
12
|
+
/** The keyring service name — the CLI's app name, e.g. `max-cli`, not its command word. */
|
|
13
13
|
service: string;
|
|
14
14
|
/**
|
|
15
15
|
* **True when the config directory came from the environment rather than the OS convention.**
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface BundleOptions {
|
|
2
|
+
/** The CLI's root: `dist/` and `package.json` are under it. */
|
|
3
|
+
root: string;
|
|
4
|
+
/** The compiled bin, relative to `root`, e.g. `dist/bin/tg.js`. It becomes the loader. */
|
|
5
|
+
bin: string;
|
|
6
|
+
/** Packages that stay outside the bundle, besides `DEFAULT_EXTERNAL`. `*` matches anything. */
|
|
7
|
+
external?: readonly string[];
|
|
8
|
+
/** Packages whose modules keep their installed place, besides `DEFAULT_ANCHORED`. */
|
|
9
|
+
anchored?: readonly string[];
|
|
10
|
+
/** Third-party files read and found harmless, besides `DEFAULT_HARMLESS` (a path suffix each). */
|
|
11
|
+
harmless?: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
export interface BundleResult {
|
|
14
|
+
problems: string[];
|
|
15
|
+
/** The chunks a server preloads, as the loader names them. */
|
|
16
|
+
chunks: string[];
|
|
17
|
+
}
|
|
18
|
+
/** Native modules, Bun's SQLite, and what cli-core loads only by name or starts as a worker from its own file. */
|
|
19
|
+
export declare const DEFAULT_EXTERNAL: string[];
|
|
20
|
+
export declare const DEFAULT_ANCHORED: string[];
|
|
21
|
+
export declare const DEFAULT_HARMLESS: string[];
|
|
22
|
+
export declare const LOADER_MARK = "// cli-dev bundle loader\n";
|
|
23
|
+
/**
|
|
24
|
+
* Whether the loader runs a server: `serve`, `watch` or `mcp serve`, or `mcp` alone as before cli-core 0.463. Flags
|
|
25
|
+
* are skipped, so `<cli> personal --read-only mcp serve` counts; four words leave room for one flag's value. It is
|
|
26
|
+
* written into the loader as source, so it uses nothing from outside.
|
|
27
|
+
*/
|
|
28
|
+
export declare const isServer: (words: readonly string[]) => boolean;
|
|
29
|
+
/** The bin that replaces the compiled one: `name` is the bundle's entry, `chunks` what a server preloads. */
|
|
30
|
+
export declare const loaderSource: (name: string, version: string, chunks: readonly string[]) => string;
|
|
31
|
+
export declare const bundle: (options: BundleOptions) => Promise<BundleResult>;
|