@wirecat/cli-base 0.45.0 → 0.46.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 +1155 -0
- package/README.md +17 -2
- package/dist/batch.d.ts +0 -1
- package/dist/batch.js +0 -1
- package/dist/codegen/index.d.ts +0 -1
- package/dist/codegen/index.js +0 -1
- package/dist/codegen/manifest.d.ts +0 -1
- package/dist/codegen/manifest.js +0 -1
- package/dist/codegen/model.d.ts +0 -1
- package/dist/codegen/model.js +0 -1
- package/dist/codegen/names.d.ts +0 -1
- package/dist/codegen/names.js +0 -1
- package/dist/codegen/pipeline.d.ts +0 -1
- package/dist/codegen/pipeline.js +0 -1
- package/dist/codegen/runtime.d.ts +0 -1
- package/dist/codegen/runtime.js +0 -1
- package/dist/codegen/tree.d.ts +0 -1
- package/dist/codegen/tree.js +0 -1
- package/dist/codegen/typescript.d.ts +0 -1
- package/dist/codegen/typescript.js +0 -1
- package/dist/codegen/valibot.d.ts +0 -1
- package/dist/codegen/valibot.js +0 -1
- package/dist/commands/document.d.ts +0 -1
- package/dist/commands/document.js +0 -1
- package/dist/commands/index.d.ts +0 -1
- package/dist/commands/index.js +0 -1
- package/dist/commands/page.d.ts +3 -2
- package/dist/commands/page.js +3 -2
- package/dist/commands/registry.d.ts +0 -1
- package/dist/commands/registry.js +0 -1
- package/dist/completion/index.d.ts +0 -1
- package/dist/completion/index.js +0 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/credentials.d.ts +0 -1
- package/dist/credentials.js +0 -1
- package/dist/deadline.d.ts +0 -1
- package/dist/deadline.js +0 -1
- package/dist/dev/audit.d.ts +0 -1
- package/dist/dev/audit.js +0 -1
- package/dist/dev/bin.d.ts +0 -1
- package/dist/dev/bin.js +0 -1
- package/dist/dev/land.d.ts +0 -1
- package/dist/dev/land.js +0 -1
- package/dist/dev/lint.d.ts +0 -1
- package/dist/dev/lint.js +0 -1
- package/dist/dev/main.d.ts +0 -1
- package/dist/dev/main.js +0 -1
- package/dist/dev/next-version.d.ts +0 -1
- package/dist/dev/next-version.js +0 -1
- package/dist/dev/slow-tests.d.ts +0 -1
- package/dist/dev/slow-tests.js +0 -1
- package/dist/dev/test-matrix.d.ts +0 -1
- package/dist/dev/test-matrix.js +0 -1
- package/dist/drain.d.ts +0 -1
- package/dist/drain.js +0 -1
- package/dist/errors.d.ts +0 -1
- package/dist/errors.js +0 -1
- package/dist/executable.d.ts +0 -1
- package/dist/executable.js +0 -1
- package/dist/exit-codes.d.ts +0 -1
- package/dist/exit-codes.js +0 -1
- package/dist/failure.d.ts +0 -1
- package/dist/failure.js +0 -1
- package/dist/http/body.d.ts +0 -1
- package/dist/http/body.js +0 -1
- package/dist/http/index.d.ts +0 -1
- package/dist/http/index.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/keyring.d.ts +0 -1
- package/dist/keyring.js +0 -1
- package/dist/logger.d.ts +0 -1
- package/dist/logger.js +0 -1
- package/dist/logging.d.ts +0 -1
- package/dist/logging.js +0 -1
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/index.js +0 -1
- package/dist/output-buffer.d.ts +0 -1
- package/dist/output-buffer.js +0 -1
- package/dist/paths.d.ts +0 -1
- package/dist/paths.js +0 -1
- package/dist/pretty.d.ts +0 -1
- package/dist/pretty.js +0 -1
- package/dist/query/dates.d.ts +0 -1
- package/dist/query/dates.js +0 -1
- package/dist/query/evaluate.d.ts +0 -1
- package/dist/query/evaluate.js +0 -1
- package/dist/query/fields.d.ts +0 -1
- package/dist/query/fields.js +0 -1
- package/dist/query/help.d.ts +0 -1
- package/dist/query/help.js +0 -1
- package/dist/query/index.d.ts +0 -1
- package/dist/query/index.js +0 -1
- package/dist/query/parser.d.ts +0 -1
- package/dist/query/parser.js +0 -1
- package/dist/query/registry.d.ts +0 -1
- package/dist/query/registry.js +0 -1
- package/dist/query/types.d.ts +0 -1
- package/dist/query/types.js +0 -1
- package/dist/query/validate.d.ts +0 -1
- package/dist/query/validate.js +0 -1
- package/dist/release/fold.d.ts +0 -1
- package/dist/release/fold.js +0 -1
- package/dist/release/index.d.ts +0 -1
- package/dist/release/index.js +0 -1
- package/dist/release/markdown.d.ts +0 -1
- package/dist/release/markdown.js +0 -1
- package/dist/release/structure.d.ts +0 -1
- package/dist/release/structure.js +0 -1
- package/dist/renderer.d.ts +0 -1
- package/dist/renderer.js +0 -1
- package/dist/result-fields.d.ts +0 -1
- package/dist/result-fields.js +0 -1
- package/dist/retry.d.ts +0 -1
- package/dist/retry.js +0 -1
- package/dist/sanitize.d.ts +0 -1
- package/dist/sanitize.js +0 -1
- package/dist/skill/index.d.ts +0 -1
- package/dist/skill/index.js +0 -1
- package/dist/standards/audit.d.ts +0 -1
- package/dist/standards/audit.js +0 -1
- package/dist/standards/effects.d.ts +0 -1
- package/dist/standards/effects.js +0 -1
- package/dist/standards/errors.d.ts +0 -1
- package/dist/standards/errors.js +0 -1
- package/dist/standards/fields.d.ts +0 -1
- package/dist/standards/fields.js +0 -1
- package/dist/standards/flags-how.d.ts +0 -1
- package/dist/standards/flags-how.js +0 -1
- package/dist/standards/flags-what.d.ts +0 -1
- package/dist/standards/flags-what.js +0 -1
- package/dist/standards/identifiers.d.ts +0 -1
- package/dist/standards/identifiers.js +0 -1
- package/dist/standards/index.d.ts +0 -1
- package/dist/standards/index.js +0 -1
- package/dist/standards/lint.d.ts +0 -1
- package/dist/standards/lint.js +0 -1
- package/dist/standards/log.d.ts +0 -1
- package/dist/standards/log.js +0 -1
- package/dist/standards/output.d.ts +0 -1
- package/dist/standards/output.js +0 -1
- package/dist/standards/registry.d.ts +0 -1
- package/dist/standards/registry.js +0 -1
- package/dist/standards/steps.d.ts +0 -1
- package/dist/standards/steps.js +0 -1
- package/dist/standards/tables.d.ts +0 -1
- package/dist/standards/tables.js +0 -1
- package/dist/standards/vocabulary.d.ts +0 -1
- package/dist/standards/vocabulary.js +1 -1
- package/dist/streams.d.ts +0 -1
- package/dist/streams.js +0 -1
- package/dist/testing/index.d.ts +0 -1
- package/dist/testing/index.js +0 -1
- package/dist/testing/network.d.ts +0 -1
- package/dist/testing/network.js +0 -1
- package/dist/testing/sandbox.d.ts +0 -1
- package/dist/testing/sandbox.js +0 -1
- package/dist/testing/setup.d.ts +0 -1
- package/dist/testing/setup.js +0 -1
- package/dist/time.d.ts +0 -1
- package/dist/time.js +0 -1
- package/dist/update/index.d.ts +0 -1
- package/dist/update/index.js +0 -1
- package/docs/standards/ci.md +10 -4
- package/docs/standards/layout.md +2 -1
- package/docs/standards/permissions.md +10 -7
- package/package.json +6 -1
- package/dist/batch.d.ts.map +0 -1
- package/dist/batch.js.map +0 -1
- package/dist/codegen/index.d.ts.map +0 -1
- package/dist/codegen/index.js.map +0 -1
- package/dist/codegen/manifest.d.ts.map +0 -1
- package/dist/codegen/manifest.js.map +0 -1
- package/dist/codegen/model.d.ts.map +0 -1
- package/dist/codegen/model.js.map +0 -1
- package/dist/codegen/names.d.ts.map +0 -1
- package/dist/codegen/names.js.map +0 -1
- package/dist/codegen/pipeline.d.ts.map +0 -1
- package/dist/codegen/pipeline.js.map +0 -1
- package/dist/codegen/runtime.d.ts.map +0 -1
- package/dist/codegen/runtime.js.map +0 -1
- package/dist/codegen/tree.d.ts.map +0 -1
- package/dist/codegen/tree.js.map +0 -1
- package/dist/codegen/typescript.d.ts.map +0 -1
- package/dist/codegen/typescript.js.map +0 -1
- package/dist/codegen/valibot.d.ts.map +0 -1
- package/dist/codegen/valibot.js.map +0 -1
- package/dist/commands/document.d.ts.map +0 -1
- package/dist/commands/document.js.map +0 -1
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/page.d.ts.map +0 -1
- package/dist/commands/page.js.map +0 -1
- package/dist/commands/registry.d.ts.map +0 -1
- package/dist/commands/registry.js.map +0 -1
- package/dist/completion/index.d.ts.map +0 -1
- package/dist/completion/index.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/credentials.d.ts.map +0 -1
- package/dist/credentials.js.map +0 -1
- package/dist/deadline.d.ts.map +0 -1
- package/dist/deadline.js.map +0 -1
- package/dist/dev/audit.d.ts.map +0 -1
- package/dist/dev/audit.js.map +0 -1
- package/dist/dev/bin.d.ts.map +0 -1
- package/dist/dev/bin.js.map +0 -1
- package/dist/dev/land.d.ts.map +0 -1
- package/dist/dev/land.js.map +0 -1
- package/dist/dev/lint.d.ts.map +0 -1
- package/dist/dev/lint.js.map +0 -1
- package/dist/dev/main.d.ts.map +0 -1
- package/dist/dev/main.js.map +0 -1
- package/dist/dev/next-version.d.ts.map +0 -1
- package/dist/dev/next-version.js.map +0 -1
- package/dist/dev/slow-tests.d.ts.map +0 -1
- package/dist/dev/slow-tests.js.map +0 -1
- package/dist/dev/test-matrix.d.ts.map +0 -1
- package/dist/dev/test-matrix.js.map +0 -1
- package/dist/drain.d.ts.map +0 -1
- package/dist/drain.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/executable.d.ts.map +0 -1
- package/dist/executable.js.map +0 -1
- package/dist/exit-codes.d.ts.map +0 -1
- package/dist/exit-codes.js.map +0 -1
- package/dist/failure.d.ts.map +0 -1
- package/dist/failure.js.map +0 -1
- package/dist/http/body.d.ts.map +0 -1
- package/dist/http/body.js.map +0 -1
- package/dist/http/index.d.ts.map +0 -1
- package/dist/http/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/keyring.d.ts.map +0 -1
- package/dist/keyring.js.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/logging.d.ts.map +0 -1
- package/dist/logging.js.map +0 -1
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/output-buffer.d.ts.map +0 -1
- package/dist/output-buffer.js.map +0 -1
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js.map +0 -1
- package/dist/pretty.d.ts.map +0 -1
- package/dist/pretty.js.map +0 -1
- package/dist/query/dates.d.ts.map +0 -1
- package/dist/query/dates.js.map +0 -1
- package/dist/query/evaluate.d.ts.map +0 -1
- package/dist/query/evaluate.js.map +0 -1
- package/dist/query/fields.d.ts.map +0 -1
- package/dist/query/fields.js.map +0 -1
- package/dist/query/help.d.ts.map +0 -1
- package/dist/query/help.js.map +0 -1
- package/dist/query/index.d.ts.map +0 -1
- package/dist/query/index.js.map +0 -1
- package/dist/query/parser.d.ts.map +0 -1
- package/dist/query/parser.js.map +0 -1
- package/dist/query/registry.d.ts.map +0 -1
- package/dist/query/registry.js.map +0 -1
- package/dist/query/types.d.ts.map +0 -1
- package/dist/query/types.js.map +0 -1
- package/dist/query/validate.d.ts.map +0 -1
- package/dist/query/validate.js.map +0 -1
- package/dist/release/fold.d.ts.map +0 -1
- package/dist/release/fold.js.map +0 -1
- package/dist/release/index.d.ts.map +0 -1
- package/dist/release/index.js.map +0 -1
- package/dist/release/markdown.d.ts.map +0 -1
- package/dist/release/markdown.js.map +0 -1
- package/dist/release/structure.d.ts.map +0 -1
- package/dist/release/structure.js.map +0 -1
- package/dist/renderer.d.ts.map +0 -1
- package/dist/renderer.js.map +0 -1
- package/dist/result-fields.d.ts.map +0 -1
- package/dist/result-fields.js.map +0 -1
- package/dist/retry.d.ts.map +0 -1
- package/dist/retry.js.map +0 -1
- package/dist/sanitize.d.ts.map +0 -1
- package/dist/sanitize.js.map +0 -1
- package/dist/skill/index.d.ts.map +0 -1
- package/dist/skill/index.js.map +0 -1
- package/dist/standards/audit.d.ts.map +0 -1
- package/dist/standards/audit.js.map +0 -1
- package/dist/standards/effects.d.ts.map +0 -1
- package/dist/standards/effects.js.map +0 -1
- package/dist/standards/errors.d.ts.map +0 -1
- package/dist/standards/errors.js.map +0 -1
- package/dist/standards/fields.d.ts.map +0 -1
- package/dist/standards/fields.js.map +0 -1
- package/dist/standards/flags-how.d.ts.map +0 -1
- package/dist/standards/flags-how.js.map +0 -1
- package/dist/standards/flags-what.d.ts.map +0 -1
- package/dist/standards/flags-what.js.map +0 -1
- package/dist/standards/identifiers.d.ts.map +0 -1
- package/dist/standards/identifiers.js.map +0 -1
- package/dist/standards/index.d.ts.map +0 -1
- package/dist/standards/index.js.map +0 -1
- package/dist/standards/lint.d.ts.map +0 -1
- package/dist/standards/lint.js.map +0 -1
- package/dist/standards/log.d.ts.map +0 -1
- package/dist/standards/log.js.map +0 -1
- package/dist/standards/output.d.ts.map +0 -1
- package/dist/standards/output.js.map +0 -1
- package/dist/standards/registry.d.ts.map +0 -1
- package/dist/standards/registry.js.map +0 -1
- package/dist/standards/steps.d.ts.map +0 -1
- package/dist/standards/steps.js.map +0 -1
- package/dist/standards/tables.d.ts.map +0 -1
- package/dist/standards/tables.js.map +0 -1
- package/dist/standards/vocabulary.d.ts.map +0 -1
- package/dist/standards/vocabulary.js.map +0 -1
- package/dist/streams.d.ts.map +0 -1
- package/dist/streams.js.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js.map +0 -1
- package/dist/testing/network.d.ts.map +0 -1
- package/dist/testing/network.js.map +0 -1
- package/dist/testing/sandbox.d.ts.map +0 -1
- package/dist/testing/sandbox.js.map +0 -1
- package/dist/testing/setup.d.ts.map +0 -1
- package/dist/testing/setup.js.map +0 -1
- package/dist/time.d.ts.map +0 -1
- package/dist/time.js.map +0 -1
- package/dist/update/index.d.ts.map +0 -1
- package/dist/update/index.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,1155 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to `@wirecat/cli-base` (published as `@wirecat/cli-core` up to 0.20.0), one section per version, newest
|
|
4
|
+
first. Versions follow [semantic versioning](https://semver.org/); before `1.0.0` a minor release may change
|
|
5
|
+
the API.
|
|
6
|
+
Versions before 0.8.0 are in the [git tags](https://github.com/WireCatLabs/cli-base/tags).
|
|
7
|
+
|
|
8
|
+
Every entry says what changed as a caller sees it, why, and what to watch for — the rules are
|
|
9
|
+
[`docs/dev/CONVENTIONS.md`](docs/dev/CONVENTIONS.md#the-changelog).
|
|
10
|
+
|
|
11
|
+
## 0.46.0 — 18.10.2026
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`commandsPage({ …, details })`** closes each command's section with the Markdown paragraphs `details(command)`
|
|
16
|
+
returns. cli-core's `commandHelpMarkdown` gives the Returns, Next usually and Example lines that `--help` shows,
|
|
17
|
+
so `docs/commands.md` says the same as the terminal. Without `details` the page is unchanged.
|
|
18
|
+
- **`guide` is a root word in the vocabulary**: a top-level `<tool> guide [name]` (cli-core's scenarios command)
|
|
19
|
+
passes `cli-dev lint` without a baseline entry.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **The README says which platforms CI covers here:** Linux, plus a non-blocking macOS run of the path tests; no
|
|
24
|
+
Windows job. It read as if the keyring were tested on every platform it lists. `CLEANUP.md` is no longer tracked.
|
|
25
|
+
- **Commander is needed at run time by `/skill`,** not only as a type, and the README says so. Full validation
|
|
26
|
+
takes a `platforms` input to run the suite on Windows and macOS by hand; Windows fails 14 tests today.
|
|
27
|
+
- **The package no longer ships source maps.** They pointed at `src/`, which is not published, so vitest in every
|
|
28
|
+
consumer printed "Sourcemap … points to missing source files" for each file it loaded from here. Stack traces now
|
|
29
|
+
show the `dist/` JavaScript, which is close to the source.
|
|
30
|
+
- **The package now holds `CHANGELOG.md`,** and its npm page links the repository's issues and README.
|
|
31
|
+
- **The README gives the install command** and says the package is ESM only (`require()` works from Node 22.12).
|
|
32
|
+
- **WC-PERM-12 says that any command saves incoming history under the read-only lock**, not only `serve` and
|
|
33
|
+
`watch`: on a messenger whose history lives in the store and whose adapter has the optional `listen`, cli-core
|
|
34
|
+
0.343.0 saves what arrives during a one-shot command or an MCP session. The lock does not stop it. No messenger
|
|
35
|
+
has `listen` yet.
|
|
36
|
+
- **WC-CI-12 now names the required checks in every repository.** The `main` rulesets of whatsapp-cli, cli-core,
|
|
37
|
+
tg-cli, max-cli, cli-base and cli-memo require the pull request validation jobs besides `standards`, so a red pull
|
|
38
|
+
request cannot merge there. drive-cli, zoom-cli, cli-testing and cli-docs have no `pr.yml` and require only
|
|
39
|
+
`standards`. WC-CI-5 lists cli-memo among the repositories with `pr.yml`.
|
|
40
|
+
|
|
41
|
+
## 0.45.1 — 18.10.2026
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **WC-CI-5 now lists who runs pull request validation and what it costs, as measured.** whatsapp-cli, tg-cli,
|
|
46
|
+
max-cli and cli-core have `pr.yml` beside cli-base; cli-memo, drive-cli, zoom-cli and cli-testing still lack it. A
|
|
47
|
+
run takes 2–3 minutes in the CLIs and about 8 in cli-core, not the two and a half minutes the rule guessed.
|
|
48
|
+
- **WC-CI-12 now names what enforces it.** The `main` rulesets of whatsapp-cli and cli-core require the pull request
|
|
49
|
+
validation jobs besides `standards`, so a red pull request cannot merge there; tg-cli, max-cli and cli-base require
|
|
50
|
+
only `standards` and still rely on review.
|
|
51
|
+
|
|
52
|
+
## 0.45.0 — 18.10.2026
|
|
53
|
+
|
|
54
|
+
### Changed — may break callers
|
|
55
|
+
|
|
56
|
+
- **The lint, audit and vocabulary tables moved to `@wirecat/cli-base/standards/tables`.** `VOCABULARY`, `LINT_RULES`,
|
|
57
|
+
`AUDIT_RULES`, `PARITY_GROUPS`, `REQUIRED_ROOTS`, `IDENTIFIERS`, `FIELD_RULES` and their `define…` helpers and types
|
|
58
|
+
are no longer exported from `/standards`, which keeps the run-time contract only: effects, errors, output envelopes,
|
|
59
|
+
the log record and next steps. Every CLI loads `/standards` on start and parsed six dev-only tables it never read
|
|
60
|
+
(82 KB, about 7–12 ms; [measurement](https://github.com/WireCatLabs/cli-testing/tree/main/performance/startup/standards-split-before/README.md)).
|
|
61
|
+
Import the tables from `/standards/tables`; run-time names need no change.
|
|
62
|
+
- **Every pull request now runs the full Linux validation, coverage floor included (WC-CI-5).** A `pr.yml` calls the
|
|
63
|
+
repository's own `ci.yml` on `pull_request`, with platform suites skipped and superseded runs cancelled; before,
|
|
64
|
+
tests, coverage, contracts and parity ran only after the merge, so a pull request that lowered coverage passed and
|
|
65
|
+
then broke `main`. WC-CI-4, WC-CI-7, WC-CI-10, WC-TEST-11 and WC-TEST-13 say the same, and cli-base has its own
|
|
66
|
+
`pr.yml`. A CLI adds the workflow shown in WC-CI-5; it costs about two and a half minutes per pull request. Windows,
|
|
67
|
+
macOS and install checks still run only at release, monthly or on request.
|
|
68
|
+
|
|
69
|
+
## 0.44.5 — 18.10.2026
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **`node-ci.yml` runs a CLI's whole contract by name**: `cli: true` runs `contracts:check`, `contracts:upgrade`,
|
|
74
|
+
`security:no-leak`, `version:check`, `generate:check`, `test:matrix:check`, `docs:check`, `package:check` and
|
|
75
|
+
`lint:commands` as separate steps after the build (`parity: true` adds `parity:check`); a missing script fails its
|
|
76
|
+
step, and `skip` lists the ones a CLI cannot have yet. `platforms: true` runs the unit suite and the built `bin`
|
|
77
|
+
on Windows and macOS, with `platform-run` for extra commands. All are off by default, so today's callers see no
|
|
78
|
+
change.
|
|
79
|
+
|
|
80
|
+
## 0.44.4 — 18.10.2026
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
|
|
84
|
+
- **The handbook catches up with wa**: WC-LIFE-8 lets a one-shot command end a wait it entered with cli-core's
|
|
85
|
+
`untilStopped()` with exit 0, not 130, since stopping is how that wait ends. WC-REL-10 counts whatsapp-cli's
|
|
86
|
+
`bin/release` among the ones that check a signed release report. WC-PERM-18 is stricter: a standing hold (frozen,
|
|
87
|
+
limited, banned) holds every remote write, reactions and read receipts too, and a ban with no end date holds until
|
|
88
|
+
it is lifted.
|
|
89
|
+
- **`archive`, `unarchive` and `mark-unread` are vocabulary verbs.** They name the messenger CLIs' commands that
|
|
90
|
+
move a chat into the messenger's own archive and back, and mark a chat unread for the owner alone
|
|
91
|
+
(`chats archive`, `chats unarchive`, `chats mark-unread`). `cli-dev lint` no longer reports them as
|
|
92
|
+
`unknown-verb`. `--backend archive`, the local archive of messages, keeps its meaning. Watch for: once a CLI takes
|
|
93
|
+
this release, `cli-dev lint` fails on its `unknown-verb` baseline entries for these commands as stale until they
|
|
94
|
+
are deleted.
|
|
95
|
+
- **`star` and `unstar` are vocabulary verbs.** They name the messenger CLIs' `messages star` and `messages unstar`:
|
|
96
|
+
WhatsApp's starred messages, a mark only the owner sees. Watch for: once a CLI takes this release, `cli-dev lint`
|
|
97
|
+
fails on its `unknown-verb` baseline entries for them as stale until they are deleted.
|
|
98
|
+
- **The vocabulary has the words for privacy settings and muted chats.** `privacy` is a resource (an account has one),
|
|
99
|
+
`mute` and `unmute` are verbs, and `account privacy set`'s options (`--find-by-phone`, `--phone-number`, `--calls`,
|
|
100
|
+
`--chat-invites`, `--hide-online`, `--read-receipts`, `--profile-photo`, `--about-text`, `--last-seen`) and
|
|
101
|
+
`chats mute --until` have the role `value`. Why: every messenger CLI that turned these commands on carried up to 13
|
|
102
|
+
command-lint findings in its baseline (`unknown-resource`, `unknown-verb`, `option-role`). Watch for: once a CLI
|
|
103
|
+
takes this release, `cli-dev lint` fails on those baseline entries as stale until they are deleted.
|
|
104
|
+
|
|
105
|
+
### Changed — may break callers
|
|
106
|
+
|
|
107
|
+
- **WC-PERM-12 now says what the read-only lock refuses in cli-core 0.337.0**: every write, and every local change
|
|
108
|
+
not marked `destroysNothing`, so a new local write fails closed. Syncs, `serve` and `watch` keep receiving; rebuilt
|
|
109
|
+
indexes, backups, exports, charts and the timed task writes still run; local embedding still runs while text for an
|
|
110
|
+
outside service is refused. A CLI's own local write must be marked, or the lock refuses it.
|
|
111
|
+
|
|
112
|
+
## 0.44.3 — 18.10.2026
|
|
113
|
+
|
|
114
|
+
### Added
|
|
115
|
+
|
|
116
|
+
- **The commands page says when a command reaches another service, not the CLI's own.**
|
|
117
|
+
`annotate(command, { reaches: "other_service" })` marks a command whose remote side is a service other than the
|
|
118
|
+
CLI's own, such as an embedding provider or a model host. The command description and `commands --json` carry
|
|
119
|
+
`reaches: "other_service"`, and `commandsPage` labels it "Sends text to an outside service" (remote write) or "Reads
|
|
120
|
+
from an outside service" (remote read) instead of the CLI's `mutates` line, which said such a command changed
|
|
121
|
+
something in the messenger. The labels come with `COMMANDS_PAGE_LABELS.en` and `.ru`; a CLI's own labels object
|
|
122
|
+
may leave them out, and then the command gets no line. Commands without the field are described as before;
|
|
123
|
+
regenerate `docs/commands.md` once a command sets it.
|
|
124
|
+
- **WC-STORE-13 says why keys stay out of the shared store, and allows a per-file media key or reference**: the
|
|
125
|
+
store is what gets backed up, exported, copied and read by agents, so a key there would open an account or a device
|
|
126
|
+
from any copy. A per-file media key (WhatsApp's `mediaKey`) or a per-file reference (a MAX bot's attachment
|
|
127
|
+
`token`) may now be kept in the attachment's `providerRef`: each opens only that one file. Device, session and
|
|
128
|
+
identity keys, account tokens and passwords still stay out.
|
|
129
|
+
|
|
130
|
+
## 0.44.2 — 18.10.2026
|
|
131
|
+
|
|
132
|
+
### Added
|
|
133
|
+
|
|
134
|
+
- `--meeting-inventory` is a registered MCP mode switch for hosts that explicitly bind the shared read-only series inventory tool. Candidate dates stay unverified; the flag does not add a provider connection or widen a default server on its own.
|
|
135
|
+
|
|
136
|
+
## 0.44.1 — 18.10.2026
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
|
|
140
|
+
- **Meeting project suggestions have a distinct MCP opt-in.** `--meeting-project-candidates` is registered as a mode switch for hosts that bind the shared read-only candidate SDK. It selects that capability explicitly rather than widening an existing MCP server; consumer hosts still supply the implementation.
|
|
141
|
+
|
|
142
|
+
## 0.44.0 — 18.10.2026
|
|
143
|
+
|
|
144
|
+
### Added
|
|
145
|
+
|
|
146
|
+
- **`cli-dev lint` fails a command with no `effects`** (`missing-command-effects`, WC-CMD-17): every leaf, generated
|
|
147
|
+
ones included, and every group that runs on its own must declare them; a command without them counts as a write,
|
|
148
|
+
so its failures are never retried and no next step runs it unasked. The commands document now says
|
|
149
|
+
`runnable: true` on a group with an action of its own, so the rule can tell it from a group that only prints its
|
|
150
|
+
help — a CLI's groups are checked from the release that picks up this version. tg, max, wa, memo, drive and zoom
|
|
151
|
+
pass it at their current `main`. A reader of `commands --json` that rejects unknown keys must accept `runnable`,
|
|
152
|
+
and an exact comparison of `describeProgram` output gains it on groups such as `doctor`, `mcp` and `commands`.
|
|
153
|
+
- **`offline: false` marks a command that cannot answer offline**: `annotate(command, { offline: false })` on a
|
|
154
|
+
command or a group, and `describeProgram` and `commands --json` say `offline: false` on it and on every command
|
|
155
|
+
below it, like `mcp: false`. cli-core's agent catalogue offers an `offline` input on every command that reads the
|
|
156
|
+
service, and a sync or an `inbox` that refuses `--offline` had no way to say so. Nothing changes until a command
|
|
157
|
+
sets it; a reader of `commands --json` that rejects unknown keys must accept the new one.
|
|
158
|
+
- **`writeSecurely` writes bytes as well as text**: `contents` takes a `string` or a `Uint8Array` (a `Buffer` is one).
|
|
159
|
+
A login QR image can now be written atomically with mode `0600`, like the credentials file, instead of with
|
|
160
|
+
`writeFileSync` and a `chmod` after it. Callers that pass a string see no change.
|
|
161
|
+
- **The vocabulary knows `setup` and `--agent`**: `setup`, the guided first run that logs in and then installs the
|
|
162
|
+
agent skill, is a registered root word, and `setup --agent <agent>` has the `action` role. `cli-dev lint` no
|
|
163
|
+
longer reports them in tg and wa; their `lint/baseline` entries for them turn stale and can be removed.
|
|
164
|
+
- **The audit baseline holds wa's shared findings**: `cli-dev audit --for wa --lint wa=lint`, run with the other
|
|
165
|
+
CLIs' command trees, starts with no new finding. What wa shares with the other CLIs was already in the baseline
|
|
166
|
+
under the other CLIs' names.
|
|
167
|
+
- **The handbook covers a CLI with a Go part and a messenger with no test accounts**: a new toolchain rule pins Go
|
|
168
|
+
from `go.mod` and runs gofmt, vet and the Go tests; Go keeps its own file names, and the 1,000-line cap is
|
|
169
|
+
TypeScript only. Live checks may use the owner's own chat where no test account exists, no test may open a real
|
|
170
|
+
credential store of any kind, and a release checks every package it publishes. Logging in and out answer without
|
|
171
|
+
an operation id, a flag counts as naming a command in a lower layer, `SECURITY.md` is a user page, and the
|
|
172
|
+
`replies` rules apply only where the messenger has replies. Read the toolchain, layout, style, testing, releases,
|
|
173
|
+
output, architecture, lifecycle, security, permissions and documents pages before the next audit.
|
|
174
|
+
|
|
175
|
+
### Fixed
|
|
176
|
+
|
|
177
|
+
- **A query whose `/` opens a regular expression that never closes now says to quote the value.** `/` starts a
|
|
178
|
+
regular expression in the query language, so `text/plain` or `mime:(text/plain)` failed with
|
|
179
|
+
`query.unclosed-literal` and no hint; the message and `details.alternative` now read
|
|
180
|
+
`/ starts a regular expression; put the value in quotes: "text/plain"`. `mime:text/plain` keeps its existing hint,
|
|
181
|
+
`mime:"text/plain"`. The error code and reason are unchanged.
|
|
182
|
+
- **`--json=item.<field>` keeps that field**: `projectFields` read `items.` as each listed thing but not `item.` as
|
|
183
|
+
the one answered thing, so `--json=item.profile` printed `item: {}`. It now prints `item: { profile: … }`, as
|
|
184
|
+
`--json=profile` already did.
|
|
185
|
+
- **`cli-dev audit` leaves a baseline entry alone when the run lacks one of the CLIs it names**: such an entry was
|
|
186
|
+
counted as fixed, and `--write-baseline` dropped it, so a run over fewer CLIs wiped what a wider run had recorded.
|
|
187
|
+
It now stays in the baseline and is not counted.
|
|
188
|
+
|
|
189
|
+
## 0.43.5 — 18.10.2026
|
|
190
|
+
|
|
191
|
+
### Fixed
|
|
192
|
+
|
|
193
|
+
- **The shared test sandbox no longer fails a test file on Windows when a test left a file open**: the folder is
|
|
194
|
+
retried at exit and otherwise left for the system's temporary-file cleanup, with one line on stderr.
|
|
195
|
+
|
|
196
|
+
## 0.43.4 — 18.10.2026
|
|
197
|
+
|
|
198
|
+
### Fixed
|
|
199
|
+
|
|
200
|
+
- **A test that imitates SIGTERM keeps its sandbox and its worker.** Since 0.43.2 the shared test setup removed every
|
|
201
|
+
sandbox folder and ended the worker on any `SIGTERM` event, so a test calling `process.emit("SIGTERM")` lost its
|
|
202
|
+
files and killed its vitest worker. The setup now acts only on a signal from the operating system, which is still
|
|
203
|
+
how vitest ends a worker after a file fails; a CLI that set other `SIGTERM` listeners aside around such a test can
|
|
204
|
+
drop that.
|
|
205
|
+
|
|
206
|
+
## 0.43.3 — 17.10.2026
|
|
207
|
+
|
|
208
|
+
### Added
|
|
209
|
+
|
|
210
|
+
- **`--plain-order` in the vocabulary**, a sort switch: search results best first by the words alone, without
|
|
211
|
+
moving mail from senders with signs of fraud down. memo ranks such mail lower by default; this finds it.
|
|
212
|
+
|
|
213
|
+
## 0.43.2 — 17.10.2026
|
|
214
|
+
|
|
215
|
+
### Fixed
|
|
216
|
+
|
|
217
|
+
- **The shared test setup is quieter and leaves nothing behind.** `@wirecat/cli-base/testing/setup` now turns off
|
|
218
|
+
npm's and pnpm's update check in the sandbox, so a test that runs `npm pack --json` as a child process no longer
|
|
219
|
+
gets the "new version available" notice in its output or reaches the registry. The network guard treats every
|
|
220
|
+
`127.x.x.x` address as this machine, not only `127.0.0.1`. The sandbox folder is removed even when a test file fails
|
|
221
|
+
while loading or its own `afterAll` throws; before, one `wirecat-test-*` folder was left per such file. On macOS the
|
|
222
|
+
folder is made under `/tmp`, so Unix socket paths in tests stay under the 104-byte limit; a CLI that moved its
|
|
223
|
+
sandbox to `/tmp` for this can drop that.
|
|
224
|
+
|
|
225
|
+
## 0.43.1 — 17.10.2026
|
|
226
|
+
|
|
227
|
+
### Fixed
|
|
228
|
+
|
|
229
|
+
- **Meeting preparation's communications flags have shared vocabulary roles.** `--context-source` selects an
|
|
230
|
+
explicit source and optional continuation, `--context-query` supplies literal words, and
|
|
231
|
+
`--context-since-time` / `--context-before-time` bound its time window. Consumers adopting the shared
|
|
232
|
+
preparation command can lint these options without adding baseline exceptions.
|
|
233
|
+
|
|
234
|
+
### Added
|
|
235
|
+
|
|
236
|
+
- **Four rules are back in the standards handbook** after they dropped out when cli-core's standard became pointers
|
|
237
|
+
to it: an MCP tool's hints and descriptions never replace the permission check (WC-MCP-13); names, message text and
|
|
238
|
+
fetched documents are data, never instructions (WC-SECR-21); a stable answer for an agent wins over a nicer view
|
|
239
|
+
(WC-OUT-23); and two identities become one person only through `link`, never from a matching name (WC-ACCT-11).
|
|
240
|
+
Nothing changes in the code; a CLI that breaks one of them now breaks a written rule.
|
|
241
|
+
|
|
242
|
+
## 0.43.0 — 17.10.2026
|
|
243
|
+
|
|
244
|
+
### Added
|
|
245
|
+
|
|
246
|
+
- **Released changelog sections may keep their old headings**: `legacyHeadingsThrough: "<version>"` in
|
|
247
|
+
`ChangelogRules` (`@wirecat/cli-base/release`) skips the heading-name and repeat checks for every section at or
|
|
248
|
+
below that version, a pre-release of it included. A CLI that moved to the shared heading set sets it to its last
|
|
249
|
+
version released with the old names, instead of renaming lines before the check. A value that is not a version
|
|
250
|
+
is reported as a problem.
|
|
251
|
+
- **One test setup file for every CLI**: `setupFiles: ["@wirecat/cli-base/testing/setup"]` in `vitest.config.ts`
|
|
252
|
+
gives each test file a fresh folder for `TMPDIR`, `HOME`, the XDG folders and every `<APP>_CONFIG_DIR`,
|
|
253
|
+
`_STATE_DIR` and `_CACHE_DIR` already set, removed when the file is done; replaces `@napi-rs/keyring` with one that
|
|
254
|
+
throws; and refuses every connection to anything but this machine, naming the host, from `net`, `tls`, `http(s)`,
|
|
255
|
+
`fetch` and `WebSocket`. A test about the network itself calls `onTestFinished(allowNetwork())`. It needs `vitest`,
|
|
256
|
+
now an optional peer dependency. A CLI's own setup file, listed after it, keeps only what is the CLI's own.
|
|
257
|
+
|
|
258
|
+
### Changed — may break callers
|
|
259
|
+
|
|
260
|
+
- **`cli-dev audit` compares wa with the other CLIs** on the shared roots of the `all` parity group (`commands`,
|
|
261
|
+
`doctor`, `skill`, `mcp`, `upgrade`, `search`, `notes`, `meetings`). An audit run that passes `--cli` for wa may
|
|
262
|
+
find differences it did not report before; the weekly scorecard adds wa once wa is published.
|
|
263
|
+
|
|
264
|
+
## 0.42.0 — 17.10.2026
|
|
265
|
+
|
|
266
|
+
### Added
|
|
267
|
+
|
|
268
|
+
- **`mcp: false` works on a single option**: `annotateOption(option, { mcp: false })` from
|
|
269
|
+
`@wirecat/cli-base/commands` marks it, and `commands --json` carries `mcp: false` on that option and nothing on the
|
|
270
|
+
rest, so an MCP tool can leave it out of its input while the command stays offered. The first use is
|
|
271
|
+
`messages delete --for-everyone`: agents never delete for everyone. No MCP server reads it yet.
|
|
272
|
+
|
|
273
|
+
## 0.41.0 — 17.10.2026
|
|
274
|
+
|
|
275
|
+
### Added
|
|
276
|
+
|
|
277
|
+
- **The WireCat CLI standards handbook ships in the package**, at `docs/standards/README.md`: an index, 16 area
|
|
278
|
+
pages with 254 rules, from the toolchain to releases, and a checklist for a new CLI. Each rule has an id, a reason,
|
|
279
|
+
the check that enforces it or "review only", an example, its exceptions and the CLIs it applies to. A rule lives
|
|
280
|
+
on one page; a rule that moved or merged keeps its old id as a pointer, so a citation still resolves.
|
|
281
|
+
`pnpm docs:check` checks the ids, the rule counts in the index, and that every "Enforced by" entry names a real
|
|
282
|
+
check: one in this repository, or one in another WireCat repository written as `<repo>: <check>`.
|
|
283
|
+
|
|
284
|
+
## 0.40.4 — 17.10.2026
|
|
285
|
+
|
|
286
|
+
### Added
|
|
287
|
+
|
|
288
|
+
- **`scan` is a known verb**: read stored messages for what a rule finds, such as tasks, and list it; record
|
|
289
|
+
it only with `--yes`. For `tasks scan <chat>` in cli-core, the name the owner chose over `tasks apply`.
|
|
290
|
+
- **`mcp: false` keeps a command off MCP servers**: set on a command or a whole group with `annotate`, it covers every
|
|
291
|
+
command below it. `commands --json` carries `mcp: false` on each command it reaches and nothing on the rest, so MCP
|
|
292
|
+
tool lists can be built from the command tree. Agents running the CLI itself are not affected.
|
|
293
|
+
|
|
294
|
+
## 0.40.3 — 17.10.2026
|
|
295
|
+
|
|
296
|
+
### Added
|
|
297
|
+
|
|
298
|
+
- Release source checks support Go through its pinned toolchain and CodeQL autobuild. Callers
|
|
299
|
+
opt in with `go` in `languages` and set `go-version-file` for a nested module; interpreted
|
|
300
|
+
language checks retain their existing build mode and critical severity policy.
|
|
301
|
+
|
|
302
|
+
- **Spreadsheet structure uses shared `insert` and `format` verbs.** `insert` adds bounded rows,
|
|
303
|
+
columns or cells before an explicit position; `format` changes selected cell presentation
|
|
304
|
+
without replacing values. Consumers can remove these dated vocabulary exceptions after adoption.
|
|
305
|
+
|
|
306
|
+
## 0.40.2 — 17.10.2026
|
|
307
|
+
|
|
308
|
+
### Fixed
|
|
309
|
+
|
|
310
|
+
- **An upgrade through pnpm installs the newest version.** pnpm 11 installs only versions at least a day old
|
|
311
|
+
(`minimumReleaseAge` 1440), so `pnpm add -g <package>@latest` could install a day-old release — on 2026-10-17 an
|
|
312
|
+
older `tg` than the one installed — while the update notice named the newest. `updateCommand("pnpm", …)` now adds
|
|
313
|
+
`--config.minimumReleaseAgeExclude=<scope>/*` for the package's own scope; every other dependency keeps pnpm's wait.
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
## 0.40.1 — 17.10.2026
|
|
317
|
+
|
|
318
|
+
### Added
|
|
319
|
+
|
|
320
|
+
- **Spreadsheet commands have shared vocabulary.** `sheets` names remote spreadsheets;
|
|
321
|
+
`--values <json>` supplies cell rows, `--input <mode>` selects input parsing and
|
|
322
|
+
`--render <mode>` selects returned value representation. Drive uses the existing `info`,
|
|
323
|
+
`show`, `update`, `add` and `clear` verbs. Consumers can remove corresponding dated lint
|
|
324
|
+
exceptions after adopting this version; existing baselines need no additions.
|
|
325
|
+
- **`places` is a view noun**: the street addresses confirmed as places, most mentioned first, as in
|
|
326
|
+
`tg <profile> mentions places` (cli-core 0.308.0). The `unknown-verb` lint no longer reports it; tg and max can
|
|
327
|
+
drop that baseline line after adopting this version.
|
|
328
|
+
|
|
329
|
+
- **`--certainty <n>` is a known flag** (role `value`): how sure an agent is, 0 to 1, kept with what it wrote, as
|
|
330
|
+
`tasks close --certainty` in cli-core takes it. tg and max listed it in their `option-role` lint baselines; after
|
|
331
|
+
they update cli-base those lines are stale and go.
|
|
332
|
+
|
|
333
|
+
### Fixed
|
|
334
|
+
|
|
335
|
+
- **The shared changelog guard can restore a historical section to its exact immutable tag.** This repairs notes that raced publication without permitting arbitrary historical edits; missing tag content still fails closed.
|
|
336
|
+
|
|
337
|
+
- **The changelog guard refuses a pull request that repeats a `###` heading in a section not yet released**
|
|
338
|
+
(`### Fixed` twice under `## Unreleased`). Each app's shape check refuses it too, but only in full validation,
|
|
339
|
+
so it reached main and stopped cli-core's 0.307.0 release. A repeat already on the base does not fail the guard.
|
|
340
|
+
Each app moves its guard pin to take it.
|
|
341
|
+
|
|
342
|
+
- **`bin/release` restarts itself once when the release brings a newer `bin/release`**: folding the changelog and
|
|
343
|
+
raising the version both fast-forward `main`, and the shell went on reading the old script from the byte it had
|
|
344
|
+
reached, so the rest of the run was a mix of old and new text. It now starts the new script over with the same
|
|
345
|
+
arguments; a second change during that run stops it with `run it again`. Only the repository's own release is
|
|
346
|
+
affected; the published package does not change.
|
|
347
|
+
- **`bin/release` restarts by its path in the repository after updating `main`**: it restarted as `$0` after
|
|
348
|
+
changing to the repository root, which pointed nowhere when the script was started from another folder by a relative
|
|
349
|
+
path. Only the repository's own release is affected.
|
|
350
|
+
|
|
351
|
+
## 0.40.0 — 16.10.2026
|
|
352
|
+
|
|
353
|
+
### Fixed
|
|
354
|
+
|
|
355
|
+
- **An email address reads as one term, unquoted**: `from:alice@example.com` used to fail with
|
|
356
|
+
`query.unsupported-operator — boost and minimum-should-match are not supported`, because `@` is Lucene's
|
|
357
|
+
minimum-should-match operator. Inside a word, `@` followed by a name with a dot (`user@host.tld`) now stays part of
|
|
358
|
+
the word. `(a OR b)@2` and `word@2` still fail as before.
|
|
359
|
+
|
|
360
|
+
## 0.39.0 — 16.10.2026
|
|
361
|
+
|
|
362
|
+
### Added
|
|
363
|
+
|
|
364
|
+
- **A query that fails on an unquoted value with an operator in it says to quote it.** `url:a.com/x?y=1` used to
|
|
365
|
+
fail with only `query.invalid-syntax at position 14`: `/`, `?`, `=` and `:` are query syntax. The error now ends
|
|
366
|
+
with `put the value in quotes: url:"a.com/x?y=1"`, also in `details.alternative`. A failure that already carries
|
|
367
|
+
an alternative keeps its own.
|
|
368
|
+
|
|
369
|
+
## 0.38.0 — 16.10.2026
|
|
370
|
+
|
|
371
|
+
### Added
|
|
372
|
+
|
|
373
|
+
- **A command says how long it runs**: `CommandMeta.lifetime` (`persistent` until stopped, `interactive` until a person
|
|
374
|
+
answers; unset is bounded by the default timeout) and `cooperative` (stops at its own pace when aborted from outside),
|
|
375
|
+
set with `annotate` and printed in `commands --json`. A runner reads them with `metaOf` instead of matching command
|
|
376
|
+
names.
|
|
377
|
+
|
|
378
|
+
### Fixed
|
|
379
|
+
|
|
380
|
+
- **Release scripts report observed lock holders separately from stale release labels.** Shared
|
|
381
|
+
diagnostics no longer attribute a live lock to a previous run; wait for the holders to finish, then
|
|
382
|
+
retry.
|
|
383
|
+
|
|
384
|
+
## 0.37.0 — 16.10.2026
|
|
385
|
+
|
|
386
|
+
### Added
|
|
387
|
+
|
|
388
|
+
- **The vocabulary registers `apply`, and `inspect` covers a mailbox.** `apply` runs the owner's saved rules over
|
|
389
|
+
what is already stored and changes what they match, saying only what would change unless `--yes` (memo's
|
|
390
|
+
`mail rules apply`); `test` stays the read-only twin that never changes anything. `inspect` now means looking at
|
|
391
|
+
a source before taking anything from it — a chat link without joining, a mailbox without importing (memo's
|
|
392
|
+
`mail probe` becomes `mail inspect`). Both were `unknown-verb` findings in memo's command lint baseline.
|
|
393
|
+
|
|
394
|
+
## 0.36.0 — 16.10.2026
|
|
395
|
+
|
|
396
|
+
### Added
|
|
397
|
+
|
|
398
|
+
- **`cli-dev changelog fold --land` lands the fold through a pull request and redoes it once when main moves.**
|
|
399
|
+
bin/release used to fold, open the pull request and wait on its checks; a session that merged a change to
|
|
400
|
+
CHANGELOG.md meanwhile left the pull request unmergeable and the release stopped (cli-core#1335). With
|
|
401
|
+
`--land` the fold is made on a fresh `origin/main`; a pull request that conflicts — found before waiting on checks,
|
|
402
|
+
since a conflicting one gets none, or when the merge is refused — is closed and the fold made again on the new
|
|
403
|
+
main, once. It prints the line and the pull request when it landed, nothing when there was nothing to fold (another
|
|
404
|
+
session already did), and fails after a second conflict or on failed checks. It needs `gh` and a clean `main`.
|
|
405
|
+
- **`mergeRepeatedHeadings` (`@wirecat/cli-base/release`) and `cli-dev changelog fold` merge a `###` heading the
|
|
406
|
+
dated section repeats.** A pull request branched before a fold adds under the unreleased heading; git applies the
|
|
407
|
+
hunk under the dated heading beside the section's own copy, and docs:check refuses "Added twice" (cli-core 0.294.0
|
|
408
|
+
after #1327). With no unreleased section on top, the fold now merges the dated section's repeats and prints
|
|
409
|
+
`merged repeated headings in <version>`.
|
|
410
|
+
|
|
411
|
+
### Fixed
|
|
412
|
+
|
|
413
|
+
- **The fold no longer leaves a blank line inside a merged list.** When a section already repeated a heading, the
|
|
414
|
+
blank line before its second copy ended up between the merged entries. Headings that differ only by trailing
|
|
415
|
+
spaces now merge too.
|
|
416
|
+
|
|
417
|
+
## 0.35.0 — 15.10.2026
|
|
418
|
+
|
|
419
|
+
### Added
|
|
420
|
+
|
|
421
|
+
- **Bounded batches share parsing, correlation and sequential execution.** `prepareBatch`, `readBatchInput` and
|
|
422
|
+
`runBatch` accept explicit registered handlers, cap input/count/read reservations and retained output, and keep
|
|
423
|
+
a result for every input on budget refusal. Failed reads never refund their reserved ceiling; it is not a byte
|
|
424
|
+
consumption measurement. Hosts retain account authorization, cancellation, final rendering and resource cleanup.
|
|
425
|
+
`projectBatchAnswers` selects nested answer fields while retaining ids, errors and completeness.
|
|
426
|
+
|
|
427
|
+
## 0.34.0 — 15.10.2026
|
|
428
|
+
|
|
429
|
+
### Added
|
|
430
|
+
|
|
431
|
+
- **`cli-dev changelog fold` folds `## Unreleased` into the dated section below it.** One session dates the version
|
|
432
|
+
and sets package.json; before anyone publishes, another merges a new `## Unreleased` above it, and the release
|
|
433
|
+
refuses until someone folds by hand (cli-core#1300 fixed it for cli-core alone). The command rewrites CHANGELOG.md
|
|
434
|
+
when the section below the unreleased one is `## <version> — ` (`--version`, package.json's by default): same-named
|
|
435
|
+
`###` headings merge, the unreleased entries first, the date stays. It prints `folded Unreleased into <version>`
|
|
436
|
+
when it folded and nothing otherwise, and fails on text under the unreleased section before its first `###`
|
|
437
|
+
rather than lose it. `--unreleased «Не выпущено»` names another title. It does not ask npm: run it in
|
|
438
|
+
bin/release only while the version is not published, or it adds entries to released notes. `foldUnreleased` is
|
|
439
|
+
exported from `@wirecat/cli-base/release` for the same job in code.
|
|
440
|
+
|
|
441
|
+
## 0.33.0 — 15.10.2026
|
|
442
|
+
|
|
443
|
+
### Changed — may break callers
|
|
444
|
+
|
|
445
|
+
- **The shared vocabulary registers the words of cli-core's task, mention and picture commands.** Verbs `claim`,
|
|
446
|
+
`release`, `merge`, `unmerge`, `defer` and `embed`; views `agenda`, `categories` and `domains`; resources `images`
|
|
447
|
+
and `duplicates`; flags `--into <id>`, `--all-in-chat`, `--due-within <duration>`, `--unanswered <duration>`,
|
|
448
|
+
`--waiting <duration>`, `--category <name>`, `--holder <name>` and `--lease <duration>`. `tasks plan` stays
|
|
449
|
+
unregistered: `plan` is a synonym of `update`. A filter is still not registered, so `tasks agenda --tag`,
|
|
450
|
+
`--claimed` and `tasks duplicates --unsure` keep their `option-role` finding. A CLI that moves to this version
|
|
451
|
+
must remove the baseline entries these clear, because a stale entry fails: on tg, for example, `unknown-verb`
|
|
452
|
+
`tasks claim`, `option-role` `tasks agenda --holder` and `unknown-resource` `images`.
|
|
453
|
+
|
|
454
|
+
## 0.32.0 — 15.10.2026
|
|
455
|
+
|
|
456
|
+
### Added
|
|
457
|
+
|
|
458
|
+
- **The shared vocabulary registers 13 more flags that apps carried without a role.** Rule fields `--sender`,
|
|
459
|
+
`--domain`, `--list-id` and `--do <actions>` (what a rule does, the same list tg and max's reply rules take);
|
|
460
|
+
`--clear`, `--ignore`, `--subfolder`, `--occurred-time`, `--grant <scopes>`, `--min-similarity`, `--domain-age`,
|
|
461
|
+
`--retry-attachments` and `--all-versions`. `--occurred` is now a synonym of `--occurred-time`, and
|
|
462
|
+
`--target-accounts` of `--source`. A CLI that moves to this version must drop the `option-role` baseline entries
|
|
463
|
+
these clear, because a stale entry fails, and rename the flags `flag-synonym` now names.
|
|
464
|
+
|
|
465
|
+
### Fixed
|
|
466
|
+
|
|
467
|
+
- **Changelog checks reject duplicate release and pending headings.** Repeated versions could hide
|
|
468
|
+
changed notes behind an unchanged copy. Keep one section per version and one pending section.
|
|
469
|
+
|
|
470
|
+
## 0.31.1 — 15.10.2026
|
|
471
|
+
|
|
472
|
+
### Fixed
|
|
473
|
+
|
|
474
|
+
- **Nested field selection traverses arrays and retains report coverage.** Item/list envelopes, continuation, missing data and operation identifiers are handled by one shared projector; consumers no longer need to unwrap item answers.
|
|
475
|
+
|
|
476
|
+
## 0.31.0 — 15.10.2026
|
|
477
|
+
|
|
478
|
+
### Changed — may break callers
|
|
479
|
+
|
|
480
|
+
- **The shared vocabulary registers 158 more flags with a role, and names 20 more flags as synonyms.** These are the
|
|
481
|
+
options tg, max, memo, drive and zm already use, such as `--chat`, `--model`, `--title`, `--sync-time` and
|
|
482
|
+
`--max-bytes`. A filter is still not registered: it belongs in the list's query. On 2026-10-14 this clears 226 of
|
|
483
|
+
tg's 287 `option-role` baseline entries, 216 of max's 281, 114 of memo's 146, 39 of drive's 53 and 74 of zm's 88.
|
|
484
|
+
A CLI that moves to this version must remove those entries from its baseline, because a stale entry fails. It
|
|
485
|
+
also gets new findings to fix:
|
|
486
|
+
- `flag-synonym`: for example `--refresh` is `--sync-first`, `--budget` is `--max-pages`, `--estimate` is
|
|
487
|
+
`--dry-run`, `--offset` is `--cursor` and `--destination` is `--output-dir`.
|
|
488
|
+
- `flag-two-meanings`: a use whose value name differs from the registered one, such as zm's
|
|
489
|
+
`--title <text>`, which is `--title <title>` in the vocabulary.
|
|
490
|
+
- **A flag's value name may contain `=` or `:`, and may end in `...`.** So `<key=level>`, `<hh:mm>` and `<ref...>`,
|
|
491
|
+
which commands already show, can be registered.
|
|
492
|
+
|
|
493
|
+
- **`node-ci.yml` no longer leaves the job token in the checkout.** Its `check`, `bun` and `secrets` jobs check out
|
|
494
|
+
with `persist-credentials: false`, so nothing a dependency runs in those jobs can read the token from `.git/config`.
|
|
495
|
+
A caller whose `checks` lines push or call `git` against the remote with that token needs its own job for it.
|
|
496
|
+
- **`release-checks.yml` asks for less.** Only the `source` job requests `actions: read` and
|
|
497
|
+
`security-events: write`; the dependency audit reads the lockfile without `pnpm install`, so no
|
|
498
|
+
lifecycle script runs; the secret scan no longer keeps the checkout token. Callers granting
|
|
499
|
+
`contents: read`, `actions: read` and `security-events: write` need no change.
|
|
500
|
+
|
|
501
|
+
### Fixed
|
|
502
|
+
|
|
503
|
+
- **The shared `release-checks.yml` gate now blocks critical CodeQL findings.** CodeQL 2.27 lists its
|
|
504
|
+
rules under `tool.extensions`, not `tool.driver`, so every finding scored 0 and the gate always
|
|
505
|
+
passed. Rules are now resolved through each result's `rule.toolComponent`, and a finding whose rule
|
|
506
|
+
is not in the report fails the gate instead of passing it. Callers get this when they bump their pin.
|
|
507
|
+
|
|
508
|
+
## 0.30.0 — 14.10.2026
|
|
509
|
+
|
|
510
|
+
### Fixed
|
|
511
|
+
|
|
512
|
+
- **`cli-dev audit` no longer reports a command as missing from a whole-tree pair when neither member has it.** A
|
|
513
|
+
path only another CLI has (memo's `catalog`, `mail`, `meetings projects`) came out as `max+tg catalog: presence:
|
|
514
|
+
only in ` with nobody named, 21 false findings on 2026-10-14. A path counts as missing only when at least one
|
|
515
|
+
member of the group has it.
|
|
516
|
+
|
|
517
|
+
### Added
|
|
518
|
+
|
|
519
|
+
- The shared command vocabulary defines `prepare` as bounded cited context assembly and classifies
|
|
520
|
+
`--meetings`, `--cues` and `--context-limit` as work budgets, `--history-since-time` as a target
|
|
521
|
+
history window and `--meeting-preparation` as opt-in tool exposure. Preparation commands reuse
|
|
522
|
+
`--since-time` and `--before-time` for an inclusive start and exclusive end. Command lint can
|
|
523
|
+
check these workflows without new baseline entries or per-tool overrides.
|
|
524
|
+
|
|
525
|
+
## 0.29.0 — 14.10.2026
|
|
526
|
+
|
|
527
|
+
### Changed — may break callers
|
|
528
|
+
|
|
529
|
+
- **`updateNotice` names `upgrade`, and stays silent only when the upgrade is the command being run.** The line said
|
|
530
|
+
`` `<cli> update` installs it `` while every CLI's command is `upgrade`, the standard's required root, and it went
|
|
531
|
+
silent whenever the word `update` appeared anywhere, so `tasks update` never saw a notice. The word is now
|
|
532
|
+
`upgradeCommand`, default `"upgrade"`, and the notice skips only when it or `complete` is one of the first two words
|
|
533
|
+
that are not options (a profile may come first). A CLI that patched the line with `.replace(...)` or skipped on
|
|
534
|
+
`argv.includes("upgrade")` itself can drop both.
|
|
535
|
+
- **`skill show` and `skill install` carry their effects.** `show` reads this machine, `install` writes to it, and
|
|
536
|
+
neither touches the service; before, they had none and counted as writes. A host that annotated them itself can stop.
|
|
537
|
+
|
|
538
|
+
### Removed
|
|
539
|
+
|
|
540
|
+
- **`legacyMacPaths` and `migrateLegacyMacPaths` are gone, with the `LegacyMove` and `MigrateLegacyPathsOptions`
|
|
541
|
+
types.** Every machine that ran a release with `~/Library` folders has moved them. A CLI that calls the migration at
|
|
542
|
+
start drops the call.
|
|
543
|
+
- **`noopLogger` and `isTransportFailure` are gone.** Nothing used them.
|
|
544
|
+
|
|
545
|
+
## 0.28.2 — 14.10.2026
|
|
546
|
+
|
|
547
|
+
### Added
|
|
548
|
+
|
|
549
|
+
- **`readJsonResponse` reads UTF-8 JSON within an explicit byte budget.** HTTP adapters can reject
|
|
550
|
+
oversized or malformed bodies before parsing, even without a trustworthy Content-Length. The
|
|
551
|
+
`/http` helper supports cancellation and releases its reader; callers still own status handling
|
|
552
|
+
and provider validation. It adds no HTTP dependency to the root export.
|
|
553
|
+
|
|
554
|
+
## 0.28.1 — 14.10.2026
|
|
555
|
+
|
|
556
|
+
### Changed — may break callers
|
|
557
|
+
|
|
558
|
+
- **`--operation-id` replaces `--send-id`, and `operation_id` replaces `send_id`.** One id per meaning: the flag
|
|
559
|
+
that repeats a write after an unknown outcome names the same attempt as the answer's `operation_id`. The flag row
|
|
560
|
+
lists `--send-id` in `replaces`, so `flag-synonym` reports a CLI that still takes it, and `identifier-name` reports
|
|
561
|
+
a `send_id` key. `projectFields` keeps only `operation_id` beside the projected fields.
|
|
562
|
+
|
|
563
|
+
### Added
|
|
564
|
+
|
|
565
|
+
- **Vocabulary rows for `--all`, `--as-owner` and `--problems`.** `--all` (paging): every item at once, instead of one
|
|
566
|
+
page or one target. `--as-owner` (mode): record an action as the owner's when an agent's terminal runs the tool.
|
|
567
|
+
`--problems` (output): only failures, warnings and crashes (`runs show`). cli-core already ships all three, so apps'
|
|
568
|
+
`cli-dev lint` stopped reporting them as unknown flags.
|
|
569
|
+
|
|
570
|
+
## 0.28.0 — 14.10.2026
|
|
571
|
+
|
|
572
|
+
### Changed — may break callers
|
|
573
|
+
|
|
574
|
+
- **`effects` replaces `mutates` and `local` on commands.** `annotate(command, { effects: { remote, local } })`, each
|
|
575
|
+
`none | read | write`; `commands --json` prints `effects`. `mutates: true` is `remote: "write"`, `mutates + local` is
|
|
576
|
+
`local: "write"`. A command without `effects` counts as a write, so annotate every read command, or its failures are
|
|
577
|
+
never safe to retry and steps to it are never safe to run unasked. MCP's `readOnlyHint` is `!writes(effects)`.
|
|
578
|
+
- **The error object carries `retry: { safe, after_ms? }`, always.** `errorObjectOf` derives it from the code, the
|
|
579
|
+
failed command's `effects` (new `FailureContext.effects`) and the new `sent` detail: a transient failure (`timeout`,
|
|
580
|
+
`rate_limited`, `network_error`, `provider_unavailable`, `provider_error` with `retryable: true`) of a command that
|
|
581
|
+
writes nothing, or of a write with `sent: false`, is safe; `outcome_unknown` never is. `retryable` and
|
|
582
|
+
`retry_after_ms` are read into `retry` and no longer copied into `details`. `operation_id`, one write attempt, is a
|
|
583
|
+
common detail now, so an unknown outcome names the attempt to look up before trying again.
|
|
584
|
+
- **A next step has `kind` and `safe_to_auto_execute`.** `kind: "command"` keeps `command` and `args`;
|
|
585
|
+
`kind: "user_action"` (defined with `{ id, kind: "user_action", why }`) has neither and is never safe. A command
|
|
586
|
+
step is safe only when its target is known to write nothing. At most two steps per answer (`MAX_NEXT_STEPS`, was
|
|
587
|
+
three): the one to take, then one alternative.
|
|
588
|
+
- **`stepOf` checks that a step binds.** Argument values must be scalars, or lists of them, on one line — a paragraph
|
|
589
|
+
read out of a message never becomes a step. With `targets` (`stepTargets(program)` from `/commands`, or
|
|
590
|
+
`FailureContext.targets`), the command must exist and take every argument named, the `*` step included; a
|
|
591
|
+
command takes its own options, its groups' and the root's, each named by its long flag (`--no-input` is
|
|
592
|
+
`no_input`).
|
|
593
|
+
- **`meta.complete` and `meta.issues` replace `meta.skipped`.** `complete` is required on every envelope: `false` when
|
|
594
|
+
a source failed or was skipped, with `issues: [{ code, reason?, source }]` (`code` is an error code, so a skipped
|
|
595
|
+
account is `authentication_error`, not free text). `truncated` (a size cap cut the answer) and `page.has_more`
|
|
596
|
+
(another page exists) keep their own meanings. A command that may answer partially declares
|
|
597
|
+
`annotate(command, { partial: true })`, shown in `commands --json`; `exitCodeOfAnswer(meta, partial)` exits 0
|
|
598
|
+
only then, else with the first issue's code.
|
|
599
|
+
- **`page` says how the source pages.** `{ mode: "page", limit, has_more, next_page? }` or
|
|
600
|
+
`{ mode: "cursor", limit, has_more, next_cursor? }`; `cursor` is gone. A cursor source never shows page numbers.
|
|
601
|
+
- **An override names its owner and a review date.** Each `lint/overrides.json` entry needs `owner` (a GitHub handle
|
|
602
|
+
or team, `@leemour`) and `review_after` (`YYYY-MM-DD`); `cli-dev lint` and `cli-dev audit` fail one past its date.
|
|
603
|
+
`overridesProblems(entries, today)` takes the date. `cli-dev audit` names a rule overridden more than three times
|
|
604
|
+
across the CLIs it reads (`rulesForReview`, `OVERRIDE_RULE_REVIEW`), without failing; the per-repo budget of 10
|
|
605
|
+
stays.
|
|
606
|
+
- **`api_operation` replaces `operation_id` on commands.** `annotate(generated, { api_operation })` and the commands
|
|
607
|
+
document key: the catalog operation a generated command was made from. `operation_id` now means one write attempt
|
|
608
|
+
only, as `IDENTIFIERS` says.
|
|
609
|
+
- **A log record's `body` is its event id, never a sentence.** `createRecordLog` and `logRecordOf` write the
|
|
610
|
+
`event` attribute as `body` and drop the message passed beside it (`log.error({ event }, "text")`), which could
|
|
611
|
+
quote content. `errorRecordOf` names its record `command.failed` and moves the message into `attributes.message`.
|
|
612
|
+
Give every record a registered dotted `event`, or its `body` is empty.
|
|
613
|
+
|
|
614
|
+
### Added
|
|
615
|
+
|
|
616
|
+
- **`Streams.drain(signal?)`.** A caller that wrote a lot of output can wait until stdout and stderr have flushed, or
|
|
617
|
+
give up when the signal aborts. Optional on `Streams`; `processStreams` implements it.
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
- **JSON lines with an end line:** `jsonlOf(envelope)` prints `{"type":"item","data":…}` per item, then
|
|
621
|
+
`{"type":"end","complete":…,"issues"?:…,"page":…}`, so a reader tells a finished stream from a cut one;
|
|
622
|
+
`jsonlItemSchema` and `jsonlEndSchema` describe them, and `key-casing` checks both.
|
|
623
|
+
- **`missing` entries may have no `step`**, for a field nothing can fill.
|
|
624
|
+
- **The `absent-null` field rule and the `nullable-list` lint rule** (medium): absent is not asked or not known,
|
|
625
|
+
`null` is known to have no value, `[]` is known empty, `0` is measured. The lint fails a list in a registered
|
|
626
|
+
JSON Schema that may be `null`. Run `cli-dev lint --write-baseline` once to record today's.
|
|
627
|
+
- **Flag synonyms.** A vocabulary flag lists its other names in `replaces` (`--limit`: `--max`, `--count`, `--take`,
|
|
628
|
+
`--max-results`); the `flag-synonym` lint rule (medium) reports them, and `option-role` leaves them to it.
|
|
629
|
+
- **The identifiers glossary**, `IDENTIFIERS` and `defineIdentifiers`: `run_id` (one invocation), `operation_id` (one
|
|
630
|
+
write attempt), `request_id` (the provider's reference), `trace_id` (tracing). The `identifier-name` lint rule
|
|
631
|
+
(high) reports `execution_id`, `invocation_id`, `log_id` and `diagnostic_id` in a registered schema or the commands
|
|
632
|
+
document.
|
|
633
|
+
- **Registered log events.** `defineLogEvents([{ id, meaning, keys }])` — a dotted id such as
|
|
634
|
+
`provider.request.failed` and the attribute keys each record carries; `LOG_EVENTS` holds cli-base's own
|
|
635
|
+
(`command.failed`). `logEventProblems(record, events)` names an unknown event or a missing key, and
|
|
636
|
+
`expectRegisteredEvents(lines, events)` from `/testing` throws on either, so a test fails on an event nobody
|
|
637
|
+
registered.
|
|
638
|
+
|
|
639
|
+
### Fixed
|
|
640
|
+
|
|
641
|
+
- **A config file that exists but cannot be read is an error, not an empty config.** Only a missing file falls back
|
|
642
|
+
to defaults; a directory, a file used as a parent folder, or an I/O failure reports the filesystem error, so a bad
|
|
643
|
+
path no longer silently resets every setting.
|
|
644
|
+
|
|
645
|
+
## 0.27.2 — 14.10.2026
|
|
646
|
+
|
|
647
|
+
### Added
|
|
648
|
+
|
|
649
|
+
- **`--scan-limit <n>` is a shared read-budget option.** Commands can bound candidate inspection separately from returned matches and byte reads. Adopting consumers remove any now-stale lint baseline entries for this option.
|
|
650
|
+
|
|
651
|
+
## 0.27.1 — 14.10.2026
|
|
652
|
+
|
|
653
|
+
### Added
|
|
654
|
+
|
|
655
|
+
- **`cli-dev audit`**: two or more CLIs, from their `commands --json`, against every lint rule and against each other
|
|
656
|
+
— required roots, the same contract on a shared path, the same meaning for a flag, one schema per output entity, one
|
|
657
|
+
name per failure. It prints a scorecard (a table, or the list envelope with `--json`) and fails on a finding the
|
|
658
|
+
baseline in `audit/baseline/` does not hold. `/standards` adds `AUDIT_RULES`, `PARITY_GROUPS`, `REQUIRED_ROOTS` and
|
|
659
|
+
`AUDIT_BLOCKS`, the switch that makes a new cross-CLI divergence fail a release (`"new"`, today) or only show
|
|
660
|
+
(`"never"`). A weekly workflow audits the five latest published CLIs and rewrites one pinned issue.
|
|
661
|
+
|
|
662
|
+
### Fixed
|
|
663
|
+
|
|
664
|
+
- The shared `--bytes` budget uses `<bytes>`, matching existing evidence commands and preventing a false two-meanings lint failure.
|
|
665
|
+
|
|
666
|
+
## 0.27.0 — 14.10.2026
|
|
667
|
+
|
|
668
|
+
### Changed — may break callers
|
|
669
|
+
|
|
670
|
+
- **A log record carries only allow-listed attribute keys.** `createRecordLog` writes a top-level attribute key that is
|
|
671
|
+
not in `LOG_ATTRIBUTE_KEYS` or the new `allow` option as `"[not allowed]"`, and redacts any key that names content
|
|
672
|
+
(`isContentKey`: `text`, `chatTitle`, `errorMessage`, `accessToken`, `phoneNumber`, …) at any depth. Pass every key
|
|
673
|
+
your writers log in `allow`, or `runs show` loses those fields. A writer that builds its own lines calls
|
|
674
|
+
`logRecordOf`, the same builder.
|
|
675
|
+
|
|
676
|
+
### Added
|
|
677
|
+
|
|
678
|
+
- **`log-attribute-key` lint rule** (high): no key of the CLI's log allow-list names message text, a token or a phone
|
|
679
|
+
number. Pass `logAttributesJsonSchema(allow)` as `log_attributes` in `cli-dev lint --schemas`; without it the rule
|
|
680
|
+
checks cli-base's own list. `key-casing` skips that entry, as log attribute keys are camelCase for now.
|
|
681
|
+
- **`traceIdOf(traceparent)`** in `/standards`: the trace id of a W3C `traceparent`, or undefined for one the spec
|
|
682
|
+
says to ignore — for an MCP caller's `_meta.traceparent` or a `TRACEPARENT` variable.
|
|
683
|
+
|
|
684
|
+
## 0.26.1 — 14.10.2026
|
|
685
|
+
|
|
686
|
+
### Added
|
|
687
|
+
|
|
688
|
+
- **The shared vocabulary names an offline source catalog.** `catalog` is a stored file/folder metadata resource, `tree` its hierarchy view, and `--depth <n>` a traversal budget. Consumers can expose offline browsing without provider-specific naming exceptions; list filters still use the shared query language.
|
|
689
|
+
|
|
690
|
+
- The `passage` view names a cited transcript anchor with bounded surrounding lines. Evidence budgets `--bytes` / `--max-read-bytes` and `--expected-fingerprint` are registered; the existing `--before-n` / `--after-n` counts also describe transcript lines.
|
|
691
|
+
|
|
692
|
+
- **The verb `rebuild`**: compute again, from what the store already holds, what the tool derives from it, keeping
|
|
693
|
+
the owner's decisions. cli-messaging's `mentions rebuild` (phones, e-mail and links found in stored text) is
|
|
694
|
+
the first command to use it.
|
|
695
|
+
- **The resource `mentions`**: phones, e-mail addresses, links and documents found in stored text, each where it was
|
|
696
|
+
written.
|
|
697
|
+
|
|
698
|
+
### Changed — may break callers
|
|
699
|
+
|
|
700
|
+
- **`identities` now means every way to reach a person or an organization** — an account in a messenger or mailbox,
|
|
701
|
+
an e-mail address, a phone — not only messenger and mailbox accounts. Only the description changes; no rule does.
|
|
702
|
+
|
|
703
|
+
## 0.26.0 — 13.10.2026
|
|
704
|
+
|
|
705
|
+
### Changed — may break callers
|
|
706
|
+
|
|
707
|
+
- **116 more vocabulary flags with a role**, from the flags tg, max, memo, drive, zoom and cli-messaging share:
|
|
708
|
+
output (`--json`, `--jsonl`, `--fields`, `--brief`, `--full`, `--quiet`, …), sort (`--measure`, `--score`,
|
|
709
|
+
`--newest`, `--order`, `--weights`), mode, action, budget (`--max-*` with their units), target and value rows.
|
|
710
|
+
`option-role` drops in every app: memo 244 → 141, drive 66 → 56, max 562 → 317, tg 576 → 329, zoom 157 → 106,
|
|
711
|
+
cli-messaging's chat app 366 → 151; no other rule rises. Filter flags get no row: they become query fields.
|
|
712
|
+
`cli-dev lint` fails on the now-stale `option-role` baseline entries until the app runs `--write-baseline` at its
|
|
713
|
+
bump; regenerate cli-messaging's STANDARD flag table too.
|
|
714
|
+
- **The parsed query tree is snake_case.** A range predicate carries `lower_inclusive` and `upper_inclusive`, and a
|
|
715
|
+
negated clause has `occur: "must_not"`; `DateRange` from `dateRange` has `lower_inclusive` and `upper_inclusive`.
|
|
716
|
+
The tree is JSON an agent sends back (an MCP `ast`, a saved search), so it follows the one casing for every key.
|
|
717
|
+
A tree stored in the old form fails the new `queryAstSchema`: rewrite stored trees before reading them.
|
|
718
|
+
|
|
719
|
+
### Added
|
|
720
|
+
|
|
721
|
+
- **`queryAstSchema` and `queryNodeSchema`** in `/query`: the tree's valibot schema, so a caller validates an `ast`
|
|
722
|
+
it receives instead of keeping its own. `key-casing` checks it as the base schema `query_ast`.
|
|
723
|
+
|
|
724
|
+
## 0.25.0 — 13.10.2026
|
|
725
|
+
|
|
726
|
+
### Changed — may break callers
|
|
727
|
+
|
|
728
|
+
- **Every JSON key the standard defines is snake_case.** The envelope: `page.has_more`, `meta.run_id`,
|
|
729
|
+
`meta.duration_ms`. The error object: `error.run_id`; error details `retry_after_ms`, `request_id`,
|
|
730
|
+
`timeout_ms`, `max_bytes`, `buffered_bytes`, `partial_output`. The log record: `run_id`, and `trace_id` as
|
|
731
|
+
OpenTelemetry spells it for JSON log lines; `thrown_message` in an error record's attributes.
|
|
732
|
+
`commands --json`: `global_options`, `inherited_options`, `exit_codes`, `takes_value`, `operation_id`, and
|
|
733
|
+
`implies` keyed by long flag (`--refresh`) instead of Commander's attribute name. One casing for every key, so
|
|
734
|
+
an agent never guesses. Reasons' `details`, step argument names and `{placeholders}` must now be snake_case,
|
|
735
|
+
or `defineReasons` and `defineSteps` throw at start-up; `annotate` takes `operation_id`; `projectFields` keeps
|
|
736
|
+
`operation_id` and `send_id`. Bump your `contract`.
|
|
737
|
+
- **The field rule `camel-case` is now `snake-case`**, and a duration key ends in `_ms`.
|
|
738
|
+
- **Every vocabulary flag has a `role`**, one of `FLAG_ROLES`, and `defineVocabulary` refuses a flag without one.
|
|
739
|
+
There is no filter role: a filter is a query field.
|
|
740
|
+
- **Query error messages start with the command that ran**, `chats list: query.unknown-field at position 8`, in
|
|
741
|
+
place of `search:`; the guide link is in `details.guide` only when the caller passes one. The `~` hints no
|
|
742
|
+
longer name `--language legacy`, a messages-search option.
|
|
743
|
+
|
|
744
|
+
### Added
|
|
745
|
+
|
|
746
|
+
- **`--account`, `--provider` and `--source` in the vocabulary** with role `scope`: they choose the accounts a
|
|
747
|
+
command reads, so `filter-flag` and `option-role` no longer report them.
|
|
748
|
+
- **One query language for every list: `@wirecat/cli-base/query`.** The Lucene 9.12.3 parser port moves here
|
|
749
|
+
from cli-messaging with its date handling. `queryFieldsOf` derives a list's fields from its entity schema,
|
|
750
|
+
`validateQuery` checks a query against them, `fieldsHelp` prints the Fields section, `defineQuery` refuses a
|
|
751
|
+
field whose example does not run, and `QUERY_REASONS` registers the shared `query.*` errors, with
|
|
752
|
+
`query.bare-word`, `query.invalid-number` and `query.unsupported-placement` new. `evaluate` judges one item
|
|
753
|
+
against a query, for tests: a list filters in its store or at the provider, never in memory.
|
|
754
|
+
- **`annotate` takes `output: { entity, view? }` and `query`, and `commands --json` carries both**, so an agent
|
|
755
|
+
sees what a list answers with and which fields it filters by.
|
|
756
|
+
- **`reference` joins `isoTime` in `/standards`**: the schema of a typed name such as `note:42`.
|
|
757
|
+
- **Four lint rules for lists.** `filter-flag` (an option of a read-only command named after a field of its
|
|
758
|
+
entity, scope flags exempt), `option-role` (an option with no role in the vocabulary), `list-without-query` and
|
|
759
|
+
`query-example`. Today's violations go to your baseline with `--write-baseline`.
|
|
760
|
+
- **`cli-dev lint` checks key casing.** The new rule `key-casing` fails on a key that is not snake_case in
|
|
761
|
+
cli-base's schemas, the commands document as the CLI printed it, and the schemas given with
|
|
762
|
+
`--schemas <file>`. A CLI with camelCase keys left baselines them with `--write-baseline`.
|
|
763
|
+
|
|
764
|
+
### Security
|
|
765
|
+
|
|
766
|
+
- **Log redaction also hides `refresh_token` and `verify_code`**, so snake_case events are covered.
|
|
767
|
+
|
|
768
|
+
## 0.24.0 — 13.10.2026
|
|
769
|
+
|
|
770
|
+
### Changed — may break callers
|
|
771
|
+
|
|
772
|
+
- **`commands --json` names exit code 1 `internal_error`**, the code a crash reports, in place of
|
|
773
|
+
`generic_failure`. A reader that looked the key up by its old name reads `internal_error`.
|
|
774
|
+
|
|
775
|
+
### Added
|
|
776
|
+
|
|
777
|
+
- **`--debug` in the vocabulary:** on failure, show the full error record, cause and stack.
|
|
778
|
+
|
|
779
|
+
## 0.23.0 — 13.10.2026
|
|
780
|
+
|
|
781
|
+
### Added
|
|
782
|
+
|
|
783
|
+
- **`createRecordLog` writes the standard log record.** Each call appends one `LogRecord` as a flat JSON line —
|
|
784
|
+
`time`, `severity`, `body`, `runId`, `traceId`, `command`, `attributes`, `resource` — to a file (mode 0600) or
|
|
785
|
+
hands it to a function, so a log written to stderr gets the same record. The event becomes `attributes`;
|
|
786
|
+
`body` is the message when given, else the event's `event` name. Lines are appended synchronously, so an exit
|
|
787
|
+
never drops the tail.
|
|
788
|
+
- **One failure handler: `errorObjectOf`, `renderError`, `errorRecordOf`, `mcpErrorResult`, `catchCrashes`.**
|
|
789
|
+
Any thrown value becomes the one error object `{ error: { code, reason, message, param?, details?, next?,
|
|
790
|
+
runId? } }`. The reason comes from `details.reason` when the package registered it, else from the code's
|
|
791
|
+
base reason (`BASE_REASONS`, one per code). Only the reason's detail keys and `COMMON_DETAILS` survive;
|
|
792
|
+
`cause` never does. The next step is chosen by the reason's `step`, never by the message text. A person sees
|
|
793
|
+
`✗ message`, one `→ next step` line and `details: <cli> runs show <runId>`; `--debug` callers pass the
|
|
794
|
+
record from `errorRecordOf` instead, the only place a cause or stack is shown. The CLI's machine output and
|
|
795
|
+
MCP's `structuredContent` are the same value. `catchCrashes` reports a throw before a CLI's own handler.
|
|
796
|
+
- **`CRASH_CODE` (`internal_error`) and `CRASH_REASON` (`command.crashed`)** for a failure that is not a
|
|
797
|
+
`CliError`: exit 1, a fixed message — the thrown text never reaches the user. It stays outside `errorCodes`,
|
|
798
|
+
so no command can raise it.
|
|
799
|
+
- `CliErrorDetails` names `reason` and `param`.
|
|
800
|
+
- `FailureContext.details`: detail keys a package allows on every reason until each is registered on its own.
|
|
801
|
+
- **Two `cli-dev lint` rules for help examples**, ported from the Azure CLI linter. `command-example-count`: every
|
|
802
|
+
handwritten leaf has one to three `examples`. `faulty-help-example-parameters`: each example starts with the
|
|
803
|
+
tool, may name a profile, runs the exact command path, gives the arguments that command takes and only its own,
|
|
804
|
+
its parents' and the global options. The check reads `commands --json`, so it needs no live Commander tree.
|
|
805
|
+
Generated commands are exempt: their examples would restate the API they mirror.
|
|
806
|
+
- **Vocabulary for drive, memo and zm.** Verb `run`; resources `files`, `comments`, `meetings`, `recordings`,
|
|
807
|
+
`jobs`, `actions`, `aliases` and the singulars `vocabulary` and `api`; views `transcript` and `evidence`; flag
|
|
808
|
+
`--until-time <time>`.
|
|
809
|
+
|
|
810
|
+
### Changed — may break callers
|
|
811
|
+
|
|
812
|
+
- **`errorObjectSchema.runId` is optional** until every CLI keeps a run for each failure.
|
|
813
|
+
- **Reasons cli-base raises are dotted and registered:** `command_timeout` → `command.timed-out`,
|
|
814
|
+
`output_limit` → `output.too-large`, `projection_unavailable` → `output.fields-unavailable`. A script that
|
|
815
|
+
matched the old strings has to switch.
|
|
816
|
+
- The handler also recognises a `CliError` from a cli-base copy older than 0.22.0 by name and code, since
|
|
817
|
+
those carry no brand.
|
|
818
|
+
- **`unknown-verb` accepts `search <resource>`.** A leaf under `search` (`search messages`, `bot search messages`)
|
|
819
|
+
passes when its name is a resource noun or `all`, as STANDARD's search hierarchy places it. A CLI that adopts
|
|
820
|
+
this must delete the now-stale baseline entries and overrides, and runs the two example rules for the first
|
|
821
|
+
time: `--write-baseline` records the examples it still lacks.
|
|
822
|
+
- **Redaction applies at every depth, arrays included.** It used to stop two levels down.
|
|
823
|
+
|
|
824
|
+
### Removed
|
|
825
|
+
|
|
826
|
+
- **`createFileLogger`, `FileLogger` and `FileLoggerOptions`, and the `pino` dependency.** Use `createRecordLog`
|
|
827
|
+
with a `runId`, `command` and `resource`; there is no `close()` to await any more.
|
|
828
|
+
|
|
829
|
+
## 0.22.0 — 13.10.2026
|
|
830
|
+
|
|
831
|
+
### Added
|
|
832
|
+
|
|
833
|
+
- **`/standards`: the registries one standard for every CLI is built from.** `VOCABULARY` (verbs, resource nouns,
|
|
834
|
+
view nouns, root words, flags with one meaning each), the answer envelope (`listEnvelopeSchema`,
|
|
835
|
+
`itemEnvelopeSchema`, `pageSchema`, `metaSchema`, `nextStepSchema`, `missingSchema`, `FIELD_RULES`), the error
|
|
836
|
+
object and reasons (`errorObjectSchema`, `defineReasons`), next steps (`STEPS`, `defineSteps`, `stepOf`), the
|
|
837
|
+
log record (`logRecordSchema`) and the lint rules (`LINT_RULES`). Each is a Valibot schema; `jsonSchemaOf`
|
|
838
|
+
emits JSON Schema 2020-12. A malformed entry throws a `RegistryError` naming every problem. Nothing uses them
|
|
839
|
+
yet: the output, error and log streams adopt them in later releases.
|
|
840
|
+
- **`commandsDocument` in `/commands`: one `commands --json` shape for every CLI**, with
|
|
841
|
+
`commandsDocumentSchema`, `commandsDocumentJsonSchema()` and `parseCommandsDocument`. memo, drive and zoom
|
|
842
|
+
print their own shapes today; `cli-dev lint` refuses them until they switch.
|
|
843
|
+
- **`cli-dev lint`** judges a CLI's command tree by the lint rules — verbs from the vocabulary, resources,
|
|
844
|
+
one meaning per flag, summaries present and at most 80 characters, every argument and option described —
|
|
845
|
+
against a shrink-only baseline in `lint/baseline/<rule-id>.json` and counted overrides in
|
|
846
|
+
`lint/overrides.json`.
|
|
847
|
+
|
|
848
|
+
- **`refuseJoinedPath` in `/commands` refuses a command path given as one argument.** `tool "projects add" --help` —
|
|
849
|
+
what a zsh loop over `$c` passes — made Commander print the root help, and an agent read it as a missing
|
|
850
|
+
command. Called on the words before `parseAsync`, it throws a `validation_error` naming the words to type. A
|
|
851
|
+
CLI adopts it at its next bump; memo has the same check of its own until then.
|
|
852
|
+
|
|
853
|
+
### Fixed
|
|
854
|
+
|
|
855
|
+
- **`isCliError` recognises an error made by another copy of the package.** It checked `instanceof`, which is
|
|
856
|
+
false when a CLI and one of its dependencies each load their own cli-base during a pin bump. It
|
|
857
|
+
now checks a brand set by the constructor; `deadline` and `createOutputBuffer` use it too. Both copies must be
|
|
858
|
+
this release or later: an error made by 0.21.0 carries no brand. Use `isCliError(error)` instead of
|
|
859
|
+
`error instanceof CliError`.
|
|
860
|
+
|
|
861
|
+
## 0.21.0 — 11.10.2026
|
|
862
|
+
|
|
863
|
+
### Changed — may break callers
|
|
864
|
+
|
|
865
|
+
- **The package is now `@wirecat/cli-base`, and the repository `WireCatLabs/cli-base`.** The code is the same as
|
|
866
|
+
0.20.0. Change every `@wirecat/cli-core` import, `extends` (`biome.json`, `tsconfig*.json`), lefthook,
|
|
867
|
+
cspell, rumdl and vale path, and every `uses: WireCatLabs/cli-core/.github/workflows/…` to `cli-base`. The
|
|
868
|
+
name `@wirecat/cli-core` is not deprecated: the messenger layer, now `@wirecat/cli-messaging`, takes it over
|
|
869
|
+
in a later release, with versions above 0.24x, so a pin such as `>=0.20.0 <0.21.0` never crosses over. The
|
|
870
|
+
code generator's default imports are now `@wirecat/cli-base/codegen` and `/codegen/runtime`; pass
|
|
871
|
+
`coreImport` and `runtimeImport` to keep the old ones.
|
|
872
|
+
|
|
873
|
+
## 0.20.0 — 11.10.2026
|
|
874
|
+
|
|
875
|
+
### Changed — may break callers
|
|
876
|
+
|
|
877
|
+
- **`resolvePaths` gives the XDG layout on macOS too** — `~/.config/<app>`, `~/.local/share/<app>` and
|
|
878
|
+
`~/.cache/<app>`, or the `XDG_*` variables when set — instead of `~/Library/Preferences`,
|
|
879
|
+
`~/Library/Application Support` and `~/Library/Caches`. One layout on every Unix is one set of
|
|
880
|
+
documentation and one place to look. Linux and Windows paths do not change, and the `*_DIR` overrides
|
|
881
|
+
still win. It now reads `HOME`, the `XDG_*` variables, `USERPROFILE`, `APPDATA` and `LOCALAPPDATA`
|
|
882
|
+
from the `env` it is given, not from the global `process.env`, and takes an optional `platform`.
|
|
883
|
+
**On macOS, a CLI that adopts this release finds none of its existing files** until it calls
|
|
884
|
+
`migrateLegacyMacPaths` at start. A keyring service name built from the config path changes with it.
|
|
885
|
+
|
|
886
|
+
### Added
|
|
887
|
+
|
|
888
|
+
- **`migrateLegacyMacPaths` moves an older release's `~/Library` folders to the new ones**, once.
|
|
889
|
+
On macOS, with no `*_DIR` override set, it moves each old folder whose new one is missing or empty,
|
|
890
|
+
all of them or none, and returns what moved. It never merges into a folder that has files, and
|
|
891
|
+
across file systems it copies, checks the copy and keeps the old folder. It throws a
|
|
892
|
+
`configuration_error` naming the processes when lsof shows a file open in a pending folder — stop a
|
|
893
|
+
running `serve` or MCP server and run again. lsof sees only files open at that moment, so a caller
|
|
894
|
+
that knows its own lock files should report their holders through `holders`. Call it at program start, before anything resolves a
|
|
895
|
+
path; with nothing to move it costs one `lstat` per folder. `legacyMacPaths` gives the old folders.
|
|
896
|
+
|
|
897
|
+
### Removed
|
|
898
|
+
|
|
899
|
+
- **The `env-paths` dependency.** The paths it gave on Windows are kept as they were.
|
|
900
|
+
|
|
901
|
+
## 0.19.4 — 11.10.2026
|
|
902
|
+
|
|
903
|
+
### Fixed
|
|
904
|
+
|
|
905
|
+
- Package references, documentation and fixtures use the WireCat namespace throughout.
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
- The owner-migration helper covers meetings, testing, Zoom and the shared organization repositories, so their links and package names migrate with the original CLIs.
|
|
909
|
+
|
|
910
|
+
## 0.19.3 — 10.10.2026
|
|
911
|
+
|
|
912
|
+
### Fixed
|
|
913
|
+
|
|
914
|
+
- **Zero command deadlines abort synchronously** before a body can execute, matching the documented
|
|
915
|
+
immediate deadline instead of scheduling a timer that could lose to a fast command. They create
|
|
916
|
+
no sleep or timer; an already aborted parent retains its cancellation reason.
|
|
917
|
+
|
|
918
|
+
## 0.19.2 — 10.10.2026
|
|
919
|
+
|
|
920
|
+
### Added
|
|
921
|
+
|
|
922
|
+
- **Portable command control helpers** expose `fieldsOf`, `projectFields`, `createOutputBuffer`
|
|
923
|
+
and `createDeadline` from the root export. Field projection retains list and operation metadata;
|
|
924
|
+
a bounded UTF-8 buffer delays data until hosts finish cleanup. Deadlines use injected sleep and
|
|
925
|
+
cancellation, waiting for the body to settle before callers close resources. Callers must propagate
|
|
926
|
+
the signal, dispose the deadline and discard buffered output on failure; no provider/store lifecycle
|
|
927
|
+
or automatic retries are imported.
|
|
928
|
+
|
|
929
|
+
### Fixed
|
|
930
|
+
|
|
931
|
+
- Windows maintenance commands support portable relative PATH entries and custom or sanitized command-processor environments while preserving separate arguments.
|
|
932
|
+
|
|
933
|
+
### Security
|
|
934
|
+
|
|
935
|
+
- Release checks include source and secret analysis; critical production advisories and critical source findings block publication. Workflow findings are reported for review. PR security remains the fast secret scan.
|
|
936
|
+
|
|
937
|
+
## 0.19.0 — 10.10.2026
|
|
938
|
+
|
|
939
|
+
### Fixed
|
|
940
|
+
|
|
941
|
+
- Windows updater and MCP setup commands resolve through absolute PATH entries and use an explicit command processor, avoiding accidental execution from the current folder. POSIX resolution is unchanged.
|
|
942
|
+
|
|
943
|
+
### Added
|
|
944
|
+
|
|
945
|
+
- `/update` exports `executableOnPath` and `executableEnvironment` for consumers using the same Windows command resolution.
|
|
946
|
+
|
|
947
|
+
## 0.18.2 — 10.10.2026
|
|
948
|
+
|
|
949
|
+
### Changed — may break callers
|
|
950
|
+
|
|
951
|
+
- **The project is now licensed under Apache License 2.0.** See `LICENSE` for the terms.
|
|
952
|
+
|
|
953
|
+
## 0.18.1 — 10.10.2026
|
|
954
|
+
|
|
955
|
+
### Fixed
|
|
956
|
+
|
|
957
|
+
- **The shared spelling list knows `wirecat`.** `cspell` no longer flags the new package scope in READMEs.
|
|
958
|
+
|
|
959
|
+
## 0.18.0 — 10.10.2026
|
|
960
|
+
|
|
961
|
+
### Changed — may break callers
|
|
962
|
+
|
|
963
|
+
- **The package is now `@wirecat/cli-core`, and the repository is `WireCatLabs/cli-core`.** Install
|
|
964
|
+
`@wirecat/cli-core` and change imports from `@wirecat/cli-core` (and its subpaths) to `@wirecat/cli-core`;
|
|
965
|
+
the code is the same as 0.17.3. `@wirecat/cli-core` gets no new versions. Call the reusable workflows
|
|
966
|
+
as `WireCatLabs/cli-core/.github/workflows/...`.
|
|
967
|
+
|
|
968
|
+
## 0.17.3 — 09.10.2026
|
|
969
|
+
|
|
970
|
+
### Changed — may break callers
|
|
971
|
+
|
|
972
|
+
- **Production dependency and workflow security checks run before releases.** Call the reusable
|
|
973
|
+
`release-checks.yml` workflow from each release workflow and require it before building. `node-ci.yml`
|
|
974
|
+
keeps lint, typecheck, coverage, build, Bun and secret scanning on changes.
|
|
975
|
+
|
|
976
|
+
### Fixed
|
|
977
|
+
|
|
978
|
+
- **Display sanitization makes Unicode tags and byte-order marks visible.** Subdivision flag emoji
|
|
979
|
+
stay intact. CLI machine output continues to preserve original strings.
|
|
980
|
+
|
|
981
|
+
## 0.17.2 — 07.10.2026
|
|
982
|
+
|
|
983
|
+
### Added
|
|
984
|
+
|
|
985
|
+
- **`indent(text, spaces)` shifts every line of a block right.** A step's body under its heading, or a
|
|
986
|
+
QR code, can sit indented in a setup screen. Empty lines stay empty, so no trailing spaces are printed.
|
|
987
|
+
|
|
988
|
+
## 0.17.1 — 04.10.2026
|
|
989
|
+
|
|
990
|
+
### Fixed
|
|
991
|
+
|
|
992
|
+
- **`cli-dev docs-check` and `markdownFiles` skip what is not a file or a folder.** A device or a
|
|
993
|
+
pipe named `*.md` used to be read, and the check crashed. Claude Code's Bash sandbox lays devices
|
|
994
|
+
over names in the working folder (`.claude/loop.md`, `.claude/skills`), so the check failed in
|
|
995
|
+
every agent session with the sandbox on. A symbolic link to a file is still listed; a link to a
|
|
996
|
+
folder is still not followed.
|
|
997
|
+
|
|
998
|
+
## 0.17.0 — 03.10.2026
|
|
999
|
+
|
|
1000
|
+
### Changed — may break callers
|
|
1001
|
+
|
|
1002
|
+
- Consumers switching exhaustively over `SchemaNode` or API parameter locations must handle explicit unions and RPC body parameters. Existing HTTP models generate the same artifacts.
|
|
1003
|
+
|
|
1004
|
+
### Added
|
|
1005
|
+
|
|
1006
|
+
- API generators preserve explicit unions and Boolean literals, validate nested references, and emit schema definitions for shared command input traversal. RPC parameters can belong to the JSON body; multipart references retain their format. Source adapters can mark secret fields so consumers keep them out of generated CLI arguments.
|
|
1007
|
+
|
|
1008
|
+
## 0.16.0 — 02.10.2026
|
|
1009
|
+
|
|
1010
|
+
### Added
|
|
1011
|
+
|
|
1012
|
+
- **`@wirecat/cli-core/mcp` installs and checks local stdio MCP entries.** A CLI can add its existing
|
|
1013
|
+
MCP server to Codex or Claude Code through those clients' own commands and probe the handshake and
|
|
1014
|
+
tool list without calling a tool. Existing entries are refused, so callers must remove one in the
|
|
1015
|
+
client before changing it.
|
|
1016
|
+
Client commands use `cross-spawn` so npm's Windows `.cmd` shims can be started.
|
|
1017
|
+
|
|
1018
|
+
## 0.15.0 — 01.10.2026
|
|
1019
|
+
|
|
1020
|
+
### Added
|
|
1021
|
+
|
|
1022
|
+
- **`annotate(command, { mutates: true, local: true })`** marks a write that changes only this
|
|
1023
|
+
machine — a file, the keyring — and never the service. `CommandInfo.local` carries it, and
|
|
1024
|
+
`mutates` stays true, so a caller that tells reads from writes still sees a write.
|
|
1025
|
+
- **`commandsPage` text takes `mutatesLocal`**, the line shown under such a command instead of
|
|
1026
|
+
`mutates`. Without it a local write gets no line. Before this, tg-cli labelled `config set` as
|
|
1027
|
+
changing Telegram.
|
|
1028
|
+
|
|
1029
|
+
## 0.14.0 — 01.10.2026
|
|
1030
|
+
|
|
1031
|
+
### Added
|
|
1032
|
+
|
|
1033
|
+
- **Shared settings for checking docs**: `@wirecat/cli-core/cspell` (spelling in English, British
|
|
1034
|
+
English and Russian, with the shared word list; code and links are not checked),
|
|
1035
|
+
`config/rumdl.toml` (Markdown form) and `config/vale/` (prose: filler words and long sentences in
|
|
1036
|
+
both languages, and tg's tone). A repository installs the tools itself — [README](docs/TOOLING.md).
|
|
1037
|
+
- **`cli-dev docs-check --pages`** also checks `docs/` against `docs/meta.json`, the docs portal's
|
|
1038
|
+
page structure.
|
|
1039
|
+
|
|
1040
|
+
## 0.13.0 — 01.10.2026
|
|
1041
|
+
|
|
1042
|
+
### Added
|
|
1043
|
+
|
|
1044
|
+
- **`skillCommand(app, skill, environment, more)`**: `more` names skills a library ships for every CLI
|
|
1045
|
+
built on it, and `skill show <name>` prints one, with `{{command}}` turned into the CLI's command.
|
|
1046
|
+
cli-messaging ships one for linking conversations. They are printed, never installed — two CLIs
|
|
1047
|
+
would install the same name. Without `more`, `skill show` takes no argument, as before.
|
|
1048
|
+
- **The shared pre-push hook runs `parity:check` after `typecheck`**, when the project has that
|
|
1049
|
+
script. tg-cli and max-cli check their commands and pages against cli-messaging's parity manifest
|
|
1050
|
+
before a push instead of a minute later in CI. A project without the script sees no change. Why in
|
|
1051
|
+
one command: the check builds into the same `dist/` that typecheck writes, and two `tsc` runs side
|
|
1052
|
+
by side race on its state file.
|
|
1053
|
+
|
|
1054
|
+
## 0.12.0 — 01.10.2026
|
|
1055
|
+
|
|
1056
|
+
### Changed — may break callers
|
|
1057
|
+
|
|
1058
|
+
- **`commandsPage` writes what tg-cli's own copy of it already did**: each description ends as a
|
|
1059
|
+
sentence, the allowed values follow it ("One of: `new`, `old`."), an argument shows its default
|
|
1060
|
+
as an option does, and a `~` is escaped — `~~struck~~` in a description struck out the rest of
|
|
1061
|
+
the row. `CommandsPageLabels` gains `oneOf` (`COMMANDS_PAGE_LABELS` has it in both languages).
|
|
1062
|
+
What to watch for: a regenerated `commands.md` changes on almost every row; a caller with its
|
|
1063
|
+
own labels adds `oneOf`.
|
|
1064
|
+
|
|
1065
|
+
## 0.11.0 — 01.10.2026
|
|
1066
|
+
|
|
1067
|
+
### Added
|
|
1068
|
+
|
|
1069
|
+
- **Shared configuration a CLI extends instead of copying.** `@wirecat/cli-core/tsconfig.base.json`
|
|
1070
|
+
(compiler options), `/tsconfig.test.json` and `/tsconfig.scripts.json` (the no-emit overlays for
|
|
1071
|
+
tests and `scripts/`), `/biome` (formatter, linter, the `scripts/` console rule) and
|
|
1072
|
+
`config/lefthook.yml` (the git hooks). Paths, file lists and import rules stay in each repository.
|
|
1073
|
+
What to watch for: in lefthook, the extended file overrides your own `lefthook.yml`, not the other
|
|
1074
|
+
way round. How to adopt each: [README](docs/TOOLING.md).
|
|
1075
|
+
- **`cli-dev`, a command for the development scripts every CLI carried a copy of:** `slow-tests`,
|
|
1076
|
+
`next-version`, `version`, `docs-check` and `test-matrix`. Each prints what the script it replaces
|
|
1077
|
+
printed; the test matrix page names `cli-dev` in its first line, so a repository regenerates and
|
|
1078
|
+
commits that page once when it switches.
|
|
1079
|
+
- **`.github/workflows/node-ci.yml`, a reusable workflow:** install, lint, typecheck, test with
|
|
1080
|
+
coverage, build, the extra checks a repository passes in, the Bun run and a gitleaks scan of the
|
|
1081
|
+
whole history.
|
|
1082
|
+
|
|
1083
|
+
## 0.10.0 — 01.10.2026
|
|
1084
|
+
|
|
1085
|
+
### Added
|
|
1086
|
+
|
|
1087
|
+
- **`@wirecat/cli-core/skill` installs a CLI's SKILL.md and tells agents when to.** `skillCommand`
|
|
1088
|
+
is the `skill` command, moved down from cli-messaging, with a new `install [--for claude|agents|all]`
|
|
1089
|
+
that writes the file to `~/.claude/skills/<appName>/` and `~/.agents/skills/<appName>/` and records
|
|
1090
|
+
the CLI's version as `metadata.version` in its frontmatter — the Agent Skills specification has no
|
|
1091
|
+
top-level `version`. It refuses a SKILL.md whose `name` differs from `<appName>`, the directory it
|
|
1092
|
+
writes to, which the specification requires to match. `skillHint` is a once-a-day line for an agent whose copy is
|
|
1093
|
+
missing or older than the CLI; `skillResource` serves the file to an MCP client as `<command>://skill`.
|
|
1094
|
+
An agent used to learn of the skill only by reading `--help`.
|
|
1095
|
+
What to watch for: `skillCommand` takes a third argument, the host's renderer, streams and `env`;
|
|
1096
|
+
it imports Commander at run time, so a CLI using `/skill` needs Commander installed, as all four do.
|
|
1097
|
+
- **The update state file keeps a second field, `skillHintAt`,** and `writeUpdateState` now merges
|
|
1098
|
+
into the file as it is when written, instead of replacing it, so the two daily notices do not erase
|
|
1099
|
+
each other. It accepts a partial state; `readNoticeState` reads the file whether or not npm was asked.
|
|
1100
|
+
- **`commandsPage` in `@wirecat/cli-core/commands` writes a CLI's whole `docs/commands.md`** from
|
|
1101
|
+
the command tree: every command at any depth, its usage, arguments and options with defaults, and
|
|
1102
|
+
the exit codes. The table labels come in English and Russian (`COMMANDS_PAGE_LABELS`); the CLI
|
|
1103
|
+
passes its own title, introduction and closing words. It is max-cli's generator, moved here so
|
|
1104
|
+
tg-cli gets the same page from the same code; max-cli's page comes out byte for byte the same.
|
|
1105
|
+
- **`structureProblems` in `@wirecat/cli-core/release` checks a docs folder against its
|
|
1106
|
+
`meta.json`**, the sidebar the docs portal reads: every listed page exists, every page is listed
|
|
1107
|
+
once, the required pages are there (`REQUIRED_PAGES`), `meta.json` holds only Fumadocs' keys,
|
|
1108
|
+
and each page has exactly one `# ` heading, first. `README.md` in the folder is left out — it is
|
|
1109
|
+
the contributors' index.
|
|
1110
|
+
|
|
1111
|
+
### Fixed
|
|
1112
|
+
|
|
1113
|
+
- **`Credentials.write` refuses to replace a credentials file it cannot parse.** It used to read a
|
|
1114
|
+
broken file as empty, and the next write replaced it, losing every other secret stored in it. Now
|
|
1115
|
+
it throws a `CliError` with code `configuration_error` that names the file and never quotes it.
|
|
1116
|
+
`read` still treats such a file as holding nothing, and `remove` leaves it alone.
|
|
1117
|
+
What to watch for: `write` can now throw when the keyring is unavailable and the file is broken —
|
|
1118
|
+
the user fixes the file or moves it aside. An empty file counts as broken.
|
|
1119
|
+
- **A generated Valibot schema accepts a 64-bit integer enum.** The values are matched as the
|
|
1120
|
+
decimal strings a 64-bit integer becomes, as the generated type already said; before, no input
|
|
1121
|
+
passed.
|
|
1122
|
+
- **Generation stops, naming the schema, when an `allOf` reaches its own schema**, directly or
|
|
1123
|
+
through others. It used to overflow the stack.
|
|
1124
|
+
|
|
1125
|
+
## 0.9.0 — 30.09.2026
|
|
1126
|
+
|
|
1127
|
+
### Added
|
|
1128
|
+
|
|
1129
|
+
- **`@wirecat/cli-core/release` holds the release checks that max-cli and tg-cli share.** A runner,
|
|
1130
|
+
`releaseCheck`, that runs every check and prints one `ok` or `FAIL` line each, and the checks a
|
|
1131
|
+
program can decide: a command that must exit 0, the version not yet on npm, the package contents,
|
|
1132
|
+
the changelog's shape, links and anchors in the documents, and the version in `package.json` and
|
|
1133
|
+
`src/version.ts` in step. Until now each CLI kept its own copy, and the copies had drifted apart.
|
|
1134
|
+
Each caller passes its own changelog headings, id prefixes and user pages.
|
|
1135
|
+
|
|
1136
|
+
## 0.8.0 — 27.09.2026
|
|
1137
|
+
|
|
1138
|
+
### Added
|
|
1139
|
+
|
|
1140
|
+
- **`@wirecat/cli-core/codegen` generates an API catalog from an official description, at build
|
|
1141
|
+
time.** It reads a format-neutral `ApiModel` — each operation with an `http` or `rpc` binding, an
|
|
1142
|
+
effect (`read`, `write`, `destructive`) and how far its source can be trusted — and writes
|
|
1143
|
+
TypeScript types, Valibot schemas, an operation manifest and a coverage page. `writeArtifacts`
|
|
1144
|
+
writes them, or with `check` only reports which are stale.
|
|
1145
|
+
Why: max-cli's bot commands are generated from the MAX Bot API description, and the same machinery
|
|
1146
|
+
serves any CLI that has such a description.
|
|
1147
|
+
What to watch for: generation stops, naming the problem, on colliding names, an operation not
|
|
1148
|
+
classified as a read or a write, an override that matches nothing, an unknown reference or a
|
|
1149
|
+
construct it cannot express — it never drops an operation or falls back to `any`. No parser ships:
|
|
1150
|
+
the OpenAPI or Postman adapter lives in the CLI that owns the source.
|
|
1151
|
+
- **`@wirecat/cli-core/codegen/runtime`**, the few number helpers the generated schemas import at run
|
|
1152
|
+
time. A 64-bit integer comes out as its exact decimal string from a `lossless-json` number; any
|
|
1153
|
+
other integer that does not fit a JS number fails instead of rounding.
|
|
1154
|
+
What to watch for: the schemas decode, they do not encode — validate a request with the schema,
|
|
1155
|
+
then send the original lossless value.
|