@wirecat/cli-base 0.62.0 → 0.64.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.
@@ -10,8 +10,9 @@ Rule ids on this page are `WC-CI-<n>`. How to read a rule, how ids work and whic
10
10
  [Releases page](releases.md); which scanners must exist and how workflows are hardened is on the
11
11
  [Security page](security.md).
12
12
 
13
- "The ten repositories" on this page means the six CLIs (tg, max, memo, drive, zoom, wa), cli-base, cli-core,
14
- cli-testing, cli-docs, plus community itself. cli-template follows every rule here as a CLI does
13
+ "The WireCat repositories" on this page means every WireCat CLI (today tg, max, memo, drive, zoom, wa and gcal; a
14
+ CLI made with `npx @wirecat/cli-template new` counts from its first commit), cli-base, cli-core, cli-testing, cli-docs,
15
+ plus community itself. cli-template follows every rule here as a CLI does
15
16
  ([New CLI](new-cli.md#the-template-repository-itself)).
16
17
 
17
18
  ## Rules
@@ -24,7 +25,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
24
25
  `gitleaks git --staged --redact`. A clone without gitleaks gets a warning and can still commit; CI scans anyway.
25
26
  The `prepare` script installs the hooks; `LEFTHOOK=0 git commit` skips them for one commit.
26
27
  - **Exceptions:** none.
27
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
28
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
28
29
 
29
30
  ### WC-CI-2 · Add no push hook, and no hook that installs, builds, checks types, generates or tests
30
31
 
@@ -34,7 +35,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
34
35
  does not run `standards:check`, the full lint, spelling, a build or the test suite on each commit or push; it runs a
35
36
  targeted check when it needs one.
36
37
  - **Exceptions:** none. cli-base `config/lefthook.yml` still has a pre-push typecheck, but no repository extends it.
37
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
38
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
38
39
 
39
40
  ### WC-CI-3 · Run the fast standards job on every pull request and every push to `main`
40
41
 
@@ -45,7 +46,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
45
46
  commit cancels the run it replaces. The job times out after five minutes, a ceiling for a stalled setup, not an
46
47
  expected time.
47
48
  - **Exceptions:** none. Runner queues and cold downloads are outside the budget.
48
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
49
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
49
50
 
50
51
  ### WC-CI-4 · Keep `ci:quick` to early bug checks that finish within two minutes
51
52
 
@@ -61,7 +62,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
61
62
  - **Exceptions:** never put live-account suites, agent suites or platform jobs here. Full tests and coverage run in
62
63
  the pull request validation job ([WC-CI-5](#wc-ci-5--run-the-full-linux-validation-on-every-pull-request-and-keep-platform-suites-out)),
63
64
  not in `ci:quick`.
64
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
65
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
65
66
 
66
67
  ### WC-CI-5 · Run the full Linux validation on every pull request, and keep platform suites out
67
68
 
@@ -139,10 +140,13 @@ cannot pass yet; the `skip` input names it.
139
140
 
140
141
  The shared workflows are not in the npm package, because CI runs the pinned commit, not the installed copy. To see
141
142
  what CI runs, an audit reads the `uses: WireCatLabs/cli-base/.github/workflows/…@<commit>` lines in `ci.yml`,
142
- `release.yml` and `monthly.yml`, and opens each workflow file at that commit in cli-base.
143
+ `release.yml` and `monthly.yml`, and opens each workflow file at that commit in cli-base. The fresh-agent audit on the
144
+ [New CLI](new-cli.md#done-when) page is given these files for this reason, beside the handbook and the repository;
145
+ its prompt in cli-template says so from cli-template 0.8.0. A CLI on an older template takes the prompt with
146
+ `upgrade`.
143
147
 
144
148
  - **Why:** one shared workflow keeps the full suite the same everywhere, and a pin keeps a cli-base change from
145
- breaking ten repositories at once.
149
+ breaking every repository at once.
146
150
  - **Enforced by:** `ci.yml:ci`.
147
151
  - **Example:** `uses: WireCatLabs/cli-base/.github/workflows/node-ci.yml@<commit> # v0.31.0`, with `cli: true` for
148
152
  the CLI steps (WC-CI-7), the project's extra checks in the `checks` input and `bun-run` for the Bun job. A job that only one repository needs stays beside it in
@@ -158,12 +162,29 @@ what CI runs, an audit reads the `uses: WireCatLabs/cli-base/.github/workflows/
158
162
  - **Example:** `monthly.yml`, from the community template, calls the repository's `ci.yml` and the pinned cli-base
159
163
  `release-checks.yml`. Each repository has its own minute, between 02:17 and 03:20 UTC, so runs do not overlap. No
160
164
  check compares the minutes across repositories; review keeps them apart. A CLI made from cli-template starts with
161
- the template's own minute and changes it (see [New CLI](new-cli.md)).
165
+ the template's own minute and changes it (see [New CLI](new-cli.md)). Taken minutes, from each `monthly.yml` on
166
+ the default branch:
167
+
168
+ | UTC | Repository |
169
+ |---|---|
170
+ | 02:17 | cli-base |
171
+ | 02:24 | whatsapp-cli |
172
+ | 02:27 | gcal-cli |
173
+ | 02:31 | cli-memo |
174
+ | 02:38 | cli-core |
175
+ | 02:45 | drive-cli |
176
+ | 02:52 | cli-testing |
177
+ | 02:59 | max-cli |
178
+ | 03:02 | cli-template |
179
+ | 03:06 | tg-cli |
180
+ | 03:13 | zoom-cli |
181
+ | 03:20 | cli-docs |
182
+
162
183
  - **Exceptions:** cli-core also builds and probes its native packages in their own workflows, after the window:
163
184
  `onnx.yml` at 03:27 and `sqlite.yml` at 03:37 UTC. A scheduled run of either never publishes; only a manual run
164
185
  with `publish` does. community has no build, so it runs only the release security checks, at 03:47 UTC. A monthly
165
186
  run never publishes a package or deploys the site.
166
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
187
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
167
188
 
168
189
  ### WC-CI-10 · Run heavy security checks only at release, monthly or on request
169
190
 
@@ -177,7 +198,7 @@ what CI runs, an audit reads the `uses: WireCatLabs/cli-base/.github/workflows/
177
198
  job ([WC-CI-5](#wc-ci-5--run-the-full-linux-validation-on-every-pull-request-and-keep-platform-suites-out)); it
178
199
  takes seconds. The dependency audit, `zizmor` and CodeQL stay out. Do not add a heavy scanner to an editor hook, a
179
200
  stop hook or an ordinary pull request job.
180
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** sc:9.
201
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** sc:9.
181
202
 
182
203
  ### WC-CI-11 · Moved to [WC-SECR-20](security.md#wc-secr-20--pin-each-third-party-action-to-a-commit-and-give-each-workflow-read-only-defaults)
183
204
 
@@ -195,7 +216,7 @@ what CI runs, an audit reads the `uses: WireCatLabs/cli-base/.github/workflows/
195
216
  release changes `main` the same way
196
217
  ([WC-REL-2](releases.md#wc-rel-2--main-changes-only-through-a-pull-request-also-during-a-release)).
197
218
  - **Exceptions:** none.
198
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** NEED-381.
219
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** NEED-381.
199
220
 
200
221
  ### WC-CI-13 · Start no live messenger or account test from a workflow
201
222
 
@@ -77,8 +77,9 @@ catalogue and parity manifest stay in cli-core
77
77
  - **Example:** ranking is `stats messages top`, not a ranking mode on `search messages`. Options choose the scope,
78
78
  measure, order or format of the same action. No command both shows and changes something.
79
79
  - **Exceptions:** a documented preparatory fetch such as `--sync-first`. It keeps its own permissions and reports
80
- its outcome.
81
- - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
80
+ its outcome. `mcp --revoke` forgets every login given to a browser app; it stays an option on `mcp` because it
81
+ belongs with the HTTP server's login state.
82
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** NEED-1864.
82
83
 
83
84
  ### WC-CMD-7 · Never let two commands overlap
84
85
 
@@ -18,11 +18,11 @@ nothing from either package.
18
18
  | Package and path | Exports |
19
19
  |---|---|
20
20
  | `@wirecat/cli-base` | `catchCrashes`, `CliError`, `configFilePath`, `mcpErrorResult`, `resolvePaths` |
21
- | `@wirecat/cli-base/commands` | `annotate`, `CommandInfo`, `describeProgram` |
21
+ | `@wirecat/cli-base/commands` | `annotate`, `CommandInfo`, `COMMANDS_PAGE_LABELS` (in `scripts/`), `commandsPage` (in `scripts/`), `describeOptions` (in `scripts/`), `describeProgram` |
22
22
  | `@wirecat/cli-base/codegen` | `writeArtifacts` (in `scripts/`) |
23
23
  | `@wirecat/cli-base/release` | `DocsRules`, `JOURNAL_IDS`, `markdownFiles`, `packContents` (in `scripts/`) |
24
- | `@wirecat/cli-core/cli` | `AppIdentity`, `changesAuthorityAt`, `commandsCommand`, `configCommand`, `Configuration`, `createProgram`, `environmentOf`, `GlobalFlags`, `itemOf`, `LOCAL_READ`, `outputFor`, `privateFiles`, `profileFree`, `ProgramDefinition`, `ProgramOptions`, `readOnlyLockOf`, `REMOTE_WRITE`, `renderAnswer`, `rootOf`, `run`, `RunOptions`, `runsCommand`, `settingsFor`, `skillCommand`, `upgradeCommand` |
25
- | `@wirecat/cli-core/mcp` | `McpCommand`, `registerCommands`, `runCommandForAgent`, `toolsFromCommands` |
24
+ | `@wirecat/cli-core/cli` | `AppIdentity`, `changesAuthorityAt`, `commandHelpMarkdown` (in `scripts/`), `commandsCommand`, `configCommand`, `Configuration`, `createProgram`, `environmentOf`, `GlobalFlags`, `httpTokenFile`, `itemOf`, `LOCAL_READ`, `MCP_HTTP_DEFAULT_PORT`, `mcpServerCommand`, `outputFor`, `privateFiles`, `profileFree`, `ProgramDefinition`, `ProgramOptions`, `readOnlyLockOf`, `refuseUnderReadOnly`, `REMOTE_WRITE`, `renderAnswer`, `rootOf`, `run`, `RunOptions`, `runsCommand`, `settingsFor`, `skillCommand`, `upgradeCommand` |
25
+ | `@wirecat/cli-core/mcp` | `httpLockFile`, `MCP_PATH`, `McpCommand`, `portOf`, `publicUrlOf`, `registerCommands`, `runCommandForAgent`, `serveOverHttp`, `toolsFromCommands` |
26
26
  | `@wirecat/cli-core/sends` | `Level` |
27
27
  | `@wirecat/cli-core/update` | `appUpdate` |
28
28
  | `@wirecat/cli-core/testing` | `ARGV_LOG`, `argvLogSetup` |
@@ -122,6 +122,38 @@ Rule ids on this page are `WC-LAY-<n>`. How to read a rule, how ids work and whi
122
122
  - **Exceptions:** none.
123
123
  - **Applies to:** all CLIs and libraries. **Since:** cli-base 0.41.0. **Rulings:** none.
124
124
 
125
+ ### WC-LAY-10 · Ship the bin as a bundle that `cli-dev bundle` builds
126
+
127
+ A command that imports about a thousand module files spends most of its start resolving and reading them. tg's
128
+ bundle halved `--help` and every other short command
129
+ ([measurements](https://github.com/WireCatLabs/cli-testing/blob/main/performance/startup/tg-bundle/README.md)).
130
+
131
+ - **Why:** one shared build keeps what tg learned in one place: lazy imports stay lazy, files and packages are found
132
+ where they were installed, and a running server survives an in-place upgrade.
133
+ - **Enforced by:** `<app>: pnpm build` · `<app>: pnpm smoke:node` · `<app>: pnpm smoke:bun`.
134
+ - **Example:** `"build": "tsc --build --force && cli-dev bundle --bin dist/bin/tg.js --external '@mtcute/*' --external undici"`,
135
+ with `esbuild` as a devDependency in cli-base's peer range. `dist/bundle/` holds the bundle, split so every lazy
136
+ `import()` stays a chunk of its own; `dist/bin/tg.js` stays the path `"bin"` names and becomes a loader. What it
137
+ does and checks:
138
+ - The loader answers `--version` from the version built into it, turns the compile cache on, and imports the
139
+ bundle. Under `serve`, `watch` and `mcp` it loads every chunk 2 s after start and resolves imports between chunks
140
+ without looking on disk: an upgrade deletes the old chunks, whose names carry a hash.
141
+ - In the CLI's own modules and in cli-core's and cli-base's (`--anchor` adds a package), `import.meta.url` is the
142
+ module's place before bundling, so skills, fonts, scenarios, migrations and child scripts are found. A package
143
+ they load at run time resolves from that place too (a resolve hook under Node, `Bun.resolveSync` under Bun):
144
+ pnpm installs cli-core's dependencies beside cli-core.
145
+ - A dynamic import of CommonJS (`yaml`) keeps its named exports. Names are kept (`keepNames`), so `commands --json`
146
+ and errors read as before.
147
+ - Native modules, Bun's SQLite and the packages cli-core loads by name stay outside; `--external` adds the CLI's
148
+ own (`*` matches anything).
149
+ - The build fails when a bundled module would look for a file or package from the chunk's place, or when the loader
150
+ names a chunk that was not built. A third-party file read and found harmless is named with `--harmless`.
151
+ - The CLI's smoke test runs the built bin under Node and Bun and checks that the store opens and the document
152
+ readers resolve.
153
+ - **Exceptions:** a CLI moves when its outputs are byte-identical before and after and its start gains 15% or more;
154
+ until then it ships `tsc`'s output. cli-base, cli-core and cli-testing ship libraries, not a bin.
155
+ - **Applies to:** all CLIs. **Since:** cli-base 0.64.0. **Rulings:** none.
156
+
125
157
  ## Sources
126
158
 
127
159
  These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
@@ -12,7 +12,7 @@ built on are on the [Kit surface](kit-surface.md) page.
12
12
  ## Start with the template
13
13
 
14
14
  ```sh
15
- npx @wirecat/cli-template new cal-cli --command cal --package @wirecat/cal-cli --owner WireCatLabs \
15
+ npx @wirecat/cli-template new gcal-cli --command gcal --package @wirecat/gcal-cli --owner WireCatLabs \
16
16
  --category calendar --content-lang en,ru --sign-in oauth --api official-client --filters time,person,text \
17
17
  --never-store tokens,secret-links --untrusted names,links
18
18
  ```
@@ -24,7 +24,7 @@ the choices. Nothing is guessed.
24
24
  |---|---|---|
25
25
  | `<name>-cli` | the repository folder | any name |
26
26
  | `--command` | the command word people type | one word |
27
- | `--package` | the npm package name | a scoped name, such as `@wirecat/cal-cli` |
27
+ | `--package` | the npm package name | a scoped name, such as `@wirecat/gcal-cli` |
28
28
  | `--owner` | the GitHub owner of the repository | an owner |
29
29
  | `--category` | what the CLI reads | `messenger`, `mail`, `notes`, `files`, `calendar`, `meetings` |
30
30
  | `--content-lang` | the languages of the content | a list, such as `en,ru` |
@@ -42,11 +42,11 @@ a reference CLI for your category in `AGENTS.md`. It does not install packages,
42
42
  publish. Then:
43
43
 
44
44
  ```sh
45
- cd cal-cli && pnpm install && pnpm ci:quick
45
+ cd gcal-cli && pnpm install && pnpm ci:quick
46
46
  git add -A && git commit -m "chore: start from @wirecat/cli-template"
47
47
  ```
48
48
 
49
- Give the agent `docs/dev/DESIGN.md` next. Every example passes a profile explicitly, such as `cal personal doctor`.
49
+ Give the agent `docs/dev/DESIGN.md` next. Every example passes a profile explicitly, such as `gcal personal doctor`.
50
50
  The reference CLI is the one to compare with when a step is unclear.
51
51
 
52
52
  The copy already holds every file this handbook asks for: the required root commands (`commands`, `doctor`,
@@ -61,6 +61,15 @@ The rules they keep are on the area pages: [Commands](commands.md), [MCP](mcp.md
61
61
  Later template changes come in with `npx @wirecat/cli-template upgrade`, file by file: apply, replace, skip or diff.
62
62
  See [Kit surface](kit-surface.md#how-your-cli-stays-current).
63
63
 
64
+ The template's `template.json` splits the copy in two. A **seed** (`DESIGN.md`, `CLAUDE.md`, `README.md`, the user
65
+ pages, `src/`) is the CLI's own from the first commit: rewrite it freely. A **template-owned** file (`AGENTS.md`,
66
+ `docs/dev/TESTING.md`, `docs/dev/reference-clis.md`, the skills under `docs/dev/skills/`, `.github/`) holds only what
67
+ is true for every CLI made from the template. Do not rewrite one to fit this CLI: put the CLI's own facts in a seed.
68
+ A template-owned page that is wrong for this CLI is a gap in cli-template, under
69
+ [WC-DOC-3](docs.md#wc-doc-3--every-document-states-current-facts-rewrite-a-wrong-sentence-in-place) like any other
70
+ wrong sentence: fix it there, and `upgrade` brings the fix. Change it in the CLI only where the CLI must differ for
71
+ good; `upgrade` then asks before it touches the change.
72
+
64
73
  ## Four steps that need a person
65
74
 
66
75
  `new` prints these at the end.
@@ -69,12 +78,14 @@ See [Kit surface](kit-surface.md#how-your-cli-stays-current).
69
78
  changes only through a pull request, required status checks, and no bypass. Add the ruleset after the first
70
79
  commit is on `main`, since a pull request rule leaves an empty repository no way to get one, and the required
71
80
  check names exist only once CI has run. See [Releases](releases.md).
72
- 2. **Set npm trusted publishing** for the new package, naming `release.yml`, and add any secrets the CI needs. See
81
+ 2. **Set npm trusted publishing** for the new package, naming `release.yml`, and add any secrets the CI needs. npm
82
+ offers this only once the package exists, so the owner publishes the first version with `bin/release --local`
83
+ and sets it right after. See
73
84
  [WC-REL-11](releases.md#wc-rel-11--publish-from-github-actions-with-npm-trusted-publishing).
74
- 3. **Pick a monthly cron minute** between 02:17 and 03:20 UTC that no other repository uses. The copy of
75
- `.github/workflows/monthly.yml` keeps the template's own minute, 03:02, and no check compares minutes across
76
- repositories, so change it by hand. See
85
+ 3. **Pick a monthly cron minute** between 02:17 and 03:20 UTC that is not in the list of taken minutes under
77
86
  [WC-CI-9](ci.md#wc-ci-9--run-full-validation-and-release-security-on-the-first-day-of-each-month-without-publishing).
87
+ The copy of `.github/workflows/monthly.yml` keeps the template's own minute, 03:02, and no check compares minutes
88
+ across repositories, so change it by hand, and add the new minute to the list in the step 4 pull request.
78
89
  4. **WireCat CLIs only: join the shared lists.** A pull request to cli-base's `PARITY_GROUPS` (at least the `all`
79
90
  group, which compares the shared root commands), a line in cli-core's `WIRECAT_TOOLS` and a line in cli-docs'
80
91
  `tools.json`. A messenger also joins cli-core's `parity.json`. A CLI outside WireCatLabs keeps its parity groups
@@ -89,17 +100,20 @@ All of these pass on `main`, before the first release:
89
100
  - `cli-dev lint` against the built CLI. It also makes the CLI fail once in an empty home and checks that
90
101
  `runs list` shows the failed run
91
102
  - `cli-dev audit --for <cli> --lint <cli>=lint` with no new finding, run with the command trees of the CLIs in
92
- the same parity groups. `--lint` judges the CLI's lint rules by its own `lint/` folder. What it shares with the
93
- other CLIs is judged by cli-base's `audit/baseline`; the pull request that adds the CLI to a parity group adds its
94
- shared findings there
103
+ the same parity groups (`pnpm audit:commands`). `--lint` judges the CLI's lint rules by its own `lint/` folder.
104
+ What it shares with the other CLIs has no baseline: `audit/baseline` does not accept a shared-contract finding
105
+ (cli-base 0.51.0). Fix each one, or, where the CLI must differ for good, the pull request that adds it to a parity
106
+ group declares the exact difference with its reason in that group's `differences`
95
107
  - `pnpm contracts:check`
96
108
  - `cli-dev test-matrix --check`
97
109
  - `pnpm docs:check`, with `--pages`, and the CLI's `generate:check`
98
110
  - the changelog guard on a pull request
99
111
  - `pnpm release:check`
100
112
 
101
- The last test is a fresh agent. Give it only this handbook's [index](README.md) and the new repository, and ask it to
102
- audit the CLI. Every gap it lists is either a gap in the CLI, to fix before the first release, or a hole in the
113
+ The last test is a fresh agent. Give it only this handbook's [index](README.md), the new repository and the cli-base
114
+ workflow files its own workflows pin
115
+ ([WC-CI-8](ci.md#wc-ci-8--call-cli-base-node-ciyml-from-ciyml-pinned-to-a-tag-or-commit)), and ask it to audit the
116
+ CLI. Every gap it lists is either a gap in the CLI, to fix before the first release, or a hole in the
103
117
  handbook, to fix here.
104
118
 
105
119
  ## The template repository itself
@@ -118,7 +132,7 @@ upgrade, and no script or agent reads its answers.
118
132
  | [WC-DOC-12](docs.md#wc-doc-12--a-runnable-command-in-a-document-has-no-placeholder-in-it) | Exempt only for the placeholder names `clidev`, `clidev-cli`, `@wirecat/clidev-cli` and `WireCatLabs/clidev-cli`, and the upper-case prefix `CLIDEV_` (as in `CLIDEV_PROFILE`). | `new` replaces each of them with the CLI's own name. Any other placeholder is still a gap. |
119
133
  | [WC-DOC-17](docs.md#wc-doc-17--each-entry-says-what-changed-for-the-caller-why-and-what-to-watch-for) | A changelog entry may name a file path. | The template's readers are CLI authors, who edit those files or take them with `upgrade`; for them a path is what they see. |
120
134
 
121
- Every other rule that applies to all CLIs, or to the ten repositories, applies to cli-template as it is written,
135
+ Every other rule that applies to all CLIs, or to the WireCat repositories, applies to cli-template as it is written,
122
136
  with one limit for the copy tool. It follows the rules for code and the repository: Toolchain, Layout, Style,
123
137
  Testing, Security and Documents. It has no profile, no machine mode, no MCP server, no store and no agent reading its
124
138
  answers, so the rules for a CLI's commands and runtime do not reach it: Commands, Output, MCP, Accounts, Permissions,
@@ -20,8 +20,9 @@ Rule ids on this page are `WC-PERM-<n>`. How to read a rule, how ids work and wh
20
20
  tg, max and wa use cli-core's permissions and write guard in full. memo uses them for the shared commands only. drive
21
21
  has its own policy and guard, with its own `--read-only` flag. zoom has per-profile `permissions` from zoom-cli 0.35.0,
22
22
  read with cli-core's `levelFor`; its writes change Zoom meetings, its built-in default is `remote-meetings: ask`, and
23
- it has no send journal or recipient list, since it sends no messages. Where this page says "every CLI that writes",
24
- drive is a known gap.
23
+ it has no send journal or recipient list, since it sends no messages. gcal declares its own keys through cli-core's
24
+ `commandPermissions` and runs its event writes through cli-core's write guard (WC-PERM-22). Where this page says
25
+ "every CLI that writes", drive is a known gap.
25
26
 
26
27
  WC-PERM-10 and WC-PERM-11 need cli-core 0.321.0, which tg, max and wa pin. WC-PERM-12 as written needs cli-core
27
28
  0.337.0; before it, the lock let through some local writes that overwrite what the owner saved. A command other
@@ -114,7 +115,8 @@ A default is never made stricter without the owner's word.
114
115
  - **Exceptions:** where the messenger has replies, `replies.send` is `deny`: a reply rule writes to people with nobody
115
116
  typing a command, so it waits for the owner's own `allow`. A messenger with no `replies` group, such as wa, has no
116
117
  use for the key.
117
- - **Applies to:** messenger CLIs. **Since:** cli-base 0.41.0. **Rulings:** NEED-568.
118
+ - **Applies to:** messenger CLIs. A CLI that is not a messenger sets its own defaults (WC-PERM-22). **Since:** cli-base
119
+ 0.41.0. **Rulings:** NEED-568.
118
120
 
119
121
  ### WC-PERM-7 · A built-in default only ever tightens
120
122
 
@@ -310,6 +312,34 @@ Moderation rules use the same four levels for each kind of action (delete, remov
310
312
  looser than the profile's `chats.moderate`; the code does not check that yet.
311
313
  - **Applies to:** messenger CLIs. **Since:** cli-base 0.41.0. **Rulings:** NEED-306, NEED-310.
312
314
 
315
+ ### WC-PERM-22 · A CLI that is not a messenger declares its own keys and defaults with `commandPermissions`
316
+
317
+ A messenger's keys come from its resources (`messages`, `chats`). Any other CLI names its own with cli-core's
318
+ `commandPermissions({ keyOf, extra, defaults })`, passed as `settingsFor(app, { permissions })` (cli-core 0.450.0):
319
+
320
+ - **Keys.** Each command is checked against its own path (`events.create`), the default `keyOf`. Housekeeping has no
321
+ key (WC-PERM-5). `extra` adds the keys a command checks inside itself, such as one per generated API method
322
+ (`api.calendar.events.insert`). A key that names no command is refused when it is set or saved.
323
+ - **Defaults.** `defaults` holds the CLI's built-in levels, beside cli-core's. They only ever tighten (WC-PERM-7). A
324
+ CLI picks them for what its writes do, not by WC-PERM-6's messenger list: they ask before a write people other
325
+ than the owner see or cannot easily undo, and deny what an agent must never do unasked.
326
+ - **Read-only lock and guard.** `<PREFIX>_READ_ONLY` refuses every write to the service, as in WC-PERM-12. Every
327
+ write runs through cli-core's write guard with `permissionDefaults: configuration.permissions.defaults`
328
+ (cli-core 0.455.0), so `ask` is a y/N question at a terminal (WC-PERM-9) and every attempt goes into the send journal
329
+ (WC-PERM-17). A CLI that sends no messages has no recipient list or hourly limit to set.
330
+
331
+ - **Why:** one permission model for every CLI; a CLI-own layer drifts from the shared one and is audited by nobody.
332
+ - **Enforced by:** `cli-core: src/cli/command-permissions.test.ts` · `cli-core: src/calendar/cli/writes.test.ts`.
333
+ - **Example:** a calendar CLI takes cli-core's `CALENDAR_WRITE_DEFAULTS` and `CALENDAR_WRITE_KEYS`
334
+ (`@wirecat/cli-core/calendar`, cli-core 0.458.0): `events create`, `update`, `respond` and `delete` ask, since each
335
+ changes a calendar other people may share or be invited from; `events.delete.series` (a whole repeating series) and
336
+ `events.notify` (mail the attendees) are `deny` until the owner allows them. gcal adds its own: a generated
337
+ `api <method>` that writes asks, and one that shares, empties or gives away a calendar is `deny`.
338
+ - **Exceptions:** known gaps: drive keeps its own policy and `--read-only` flag, zoom reads its own
339
+ `remote-meetings` key with `levelFor`, and memo uses cli-core's permissions for the shared commands only. None of
340
+ them declares `commandPermissions` yet.
341
+ - **Applies to:** every CLI that writes and is not a messenger. **Since:** cli-base 0.64.0. **Rulings:** none.
342
+
313
343
  ## Sources
314
344
 
315
345
  These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
@@ -125,7 +125,11 @@ on the [CI](ci.md) page.
125
125
  - **Example:** `bin/release` starts `release.yml` and follows it. Only the `publish` job has the OIDC permission (the
126
126
  short-lived identity npm trusts), and it runs no project code: it only runs `npm publish` on the validated file.
127
127
  - **Exceptions:** npm trusts the workflow by file name: renaming `release.yml` stops publishing until npm's trusted
128
- publisher settings are updated.
128
+ publisher settings are updated. npm sets a trusted publisher on the package's settings page
129
+ ([npm docs](https://docs.npmjs.com/trusted-publishers)), which a package has only once it is published, so its
130
+ first version is published with `bin/release --local` by the owner, from a clean `main`. Right after it, the owner
131
+ adds the trusted publisher on npmjs.com (step 2 of [New CLI](new-cli.md#four-steps-that-need-a-person)), and every
132
+ later version goes through `release.yml`.
129
133
  - **Applies to:** all CLIs and shared libraries. **Since:** cli-base 0.41.0. **Rulings:** none.
130
134
 
131
135
  ### WC-REL-12 · Publish only after full validation and the release security checks pass
@@ -181,12 +185,18 @@ on the [CI](ci.md) page.
181
185
 
182
186
  ### WC-REL-16 · The package ships only the files it names
183
187
 
188
+ A CLI's `files` holds only what the installed CLI runs from or shows its user: `dist`, the agent skill (`skills`),
189
+ `README.md`, `LICENSE`, and files its code reads or runs after install, such as `scenarios` for `guide`, an `install`
190
+ script, third-party notices and licenses. `CHANGELOG.md` may ship too. It never holds `src/`, tests, fakes or
191
+ fixtures, `scripts/`, `.github/`, `bin/release`, `config/`, `lint/`, `contracts/`, `docs/dev/` or `template.json`.
192
+
184
193
  - **Why:** a stray file in the package can leak local data and grows every install.
185
194
  - **Enforced by:** `node-ci.yml:check` · `<app>: pnpm package:check` · `whatsapp-cli: pnpm release:check`.
186
195
  - **Example:** `package.json` `files` lists what ships. The CLI's `pnpm release:check` runs `packContents` from
187
196
  `@wirecat/cli-base/release` and fails on any other path in `npm pack --dry-run`.
188
- - **Exceptions:** none. Each CLI's `package:check` runs `packContents`; tg and max as
189
- `release-check.ts --package-only`.
197
+ - **Exceptions:** cli-template's own package ships the skeleton's sources and configs, since `new` copies them; the
198
+ `files` list `new` writes into a CLI follows this rule. Each CLI's `package:check` runs `packContents`; tg and max
199
+ as `release-check.ts --package-only`.
190
200
  - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
191
201
 
192
202
  ## Sources
@@ -67,8 +67,9 @@ name. Any other top-level key is written as `[not allowed]`. A key that names co
67
67
  ### WC-SECR-4 · Secrets come from the environment, then the OS keyring, then a private file
68
68
 
69
69
  cli-base's `Credentials` reads the environment variable first (for CI), then the OS keyring, then a file with mode
70
- `0600`. The keyring service is the command's name. When the config directory comes from the environment, the service
71
- name is scoped to that directory (`isolated: true`).
70
+ `0600`. The keyring service is the CLI's app name, `appName` in its identity (`max-cli`, `gcal-cli`, `cli-memo`), not
71
+ the command word people type (`max`, `gcal`). When the config directory comes from the environment, the service name
72
+ is scoped to that directory (`isolated: true`).
72
73
 
73
74
  - **Why:** the keyring is the safest store on the computer, and a throwaway config directory must not overwrite the
74
75
  owner's real keyring entry.
@@ -274,7 +275,7 @@ general words.
274
275
  asks for it on that job only. The `zizmor` scan in `release-checks.yml` reports high findings at release, but does
275
276
  not fail on them.
276
277
  - **Exceptions:** none.
277
- - **Applies to:** the ten repositories: the six CLIs, cli-base, cli-core, cli-testing, cli-docs and community; and
278
+ - **Applies to:** the WireCat repositories: every CLI, cli-base, cli-core, cli-testing, cli-docs and community; and
278
279
  cli-template.
279
280
  **Since:** cli-base 0.41.0. **Rulings:** none.
280
281
 
@@ -30,7 +30,7 @@ Related pages: which account a read covers, and how a read across accounts is as
30
30
  `%LOCALAPPDATA%\WireCat\Data\` on Windows). Rows are keyed by provider and account. `storePath` is the only code
31
31
  that reads `MESSAGING_STORE` and `WIRECAT_STATE_DIR`.
32
32
  - **Exceptions:** none. Older documents that name `messages.db` describe a store that is no longer used.
33
- - **Applies to:** CLIs that keep local data through cli-core (tg, max, wa, memo, drive, zoom). **Since:** cli-base 0.41.0.
33
+ - **Applies to:** CLIs that keep local data through cli-core (tg, max, wa, memo, drive, zoom, gcal). **Since:** cli-base 0.41.0.
34
34
  **Rulings:** NEED-383.
35
35
 
36
36
  ### WC-STORE-2 · Reach the data through its area, and add a new kind of record as a new area
@@ -44,7 +44,7 @@ and which run after merge is in [CI](ci.md).
44
44
  file, listed after the shared one, adds only what is its own, such as a default profile.
45
45
  - **Exceptions:** keep coverage reports and debug traces outside the sandbox, with bounded retention. Never clean
46
46
  another session's scratch directory as test teardown.
47
- - **Applies to:** all CLIs and the shared packages. cli-base, cli-core, the six CLIs and cli-template load the shared
47
+ - **Applies to:** all CLIs and the shared packages. cli-base, cli-core, every CLI and cli-template load the shared
48
48
  setup first in `setupFiles`; cli-testing does not use it yet. **Since:** cli-base 0.41.0. **Rulings:** none.
49
49
 
50
50
  ### WC-TEST-2 · No test opens a real credential store
@@ -94,7 +94,9 @@ and which run after merge is in [CI](ci.md).
94
94
  - **Enforced by:** review only.
95
95
  - **Example:** waits go through an injected `SleepLike`, and `fakeClock()` from `@wirecat/cli-base/testing` records
96
96
  them without waiting. A test harness passes `sleep: async () => {}`. `pnpm test:slow` lists the 20 slowest tests
97
- and the 10 slowest files.
97
+ and the 10 slowest files. A test may wait for a local process or server it started, for example polling its
98
+ status with `vi.waitFor` and a timeout shorter than the test's own; that waits for an event, not for time. A
99
+ fixed sleep or `setTimeout` is still a wait for real time.
98
100
  - **Exceptions:** none. A new wait in the code gets a seam, never a longer test timeout.
99
101
  - **Applies to:** all CLIs and the shared packages. **Since:** cli-base 0.41.0. **Rulings:** dev-process:4.
100
102
 
@@ -171,7 +173,11 @@ and which run after merge is in [CI](ci.md).
171
173
  `coverage/argv.jsonl`. `pnpm test:matrix` turns that into `docs/dev/test-matrix.md` and fails on a command or
172
174
  option with neither a test nor a reason. A reason names the live scenario that covers it. A test that calls a
173
175
  function directly does not count.
174
- - **Exceptions:** none.
176
+ - **Exceptions:** commands generated from a service's API description, such as drive's and gcal's
177
+ `api <method>` from a Google Discovery snapshot, share one reason for the whole group (`api *` and its options).
178
+ It names two tests: one that checks every generated command's options against the snapshot, and one that drives a
179
+ generated command through `run()` into the executor every generated command shares. A hand-written command in the
180
+ same CLI still needs its own test or live scenario.
175
181
  - **Applies to:** all CLIs. memo's check fails only on a stale page, not yet on an option with no test.
176
182
  **Since:** cli-base 0.41.0. **Rulings:** NEED-359.
177
183
 
@@ -15,22 +15,23 @@ The [community standards](https://github.com/WireCatLabs/community/blob/main/sta
15
15
  one source of the presets. Each repository holds a copy of them in `config/wirecat/`, installed by
16
16
  `adopt-standards.py`.
17
17
 
18
- "The ten repositories" on this page means the six CLIs (tg, max, memo, drive, zoom, wa), cli-base, cli-core,
19
- cli-testing, cli-docs, plus community itself. cli-template follows every rule here as a CLI does
18
+ "The WireCat repositories" on this page means every WireCat CLI (today tg, max, memo, drive, zoom, wa and gcal; a
19
+ CLI made with `npx @wirecat/cli-template new` counts from its first commit), cli-base, cli-core, cli-testing, cli-docs,
20
+ plus community itself. cli-template follows every rule here as a CLI does
20
21
  ([New CLI](new-cli.md#the-template-repository-itself)).
21
22
 
22
23
  ## Rules
23
24
 
24
25
  ### WC-TOOL-1 · Install the shared presets with `adopt-standards.py`, and never edit the copies
25
26
 
26
- - **Why:** one reviewed set of presets keeps ten repositories alike; an edited copy drifts without anyone seeing it.
27
+ - **Why:** one reviewed set of presets keeps the repositories alike; an edited copy drifts without anyone seeing it.
27
28
  - **Enforced by:** `pnpm standards:check` · `standards.yml:standards`.
28
29
  - **Example:** `python3 scripts/adopt-standards.py /path/to/project` from a community checkout, then commit
29
30
  `config/wirecat/` and the lockfile. `standards:check` compares each file in `config/wirecat/` with the hash in
30
31
  `config/wirecat/manifest.json`.
31
32
  - **Exceptions:** none. A general improvement goes to community and comes back through a new adoption. A
32
33
  project-only setting goes in the root config (WC-TOOL-2).
33
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
34
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
34
35
 
35
36
  ### WC-TOOL-2 · Make each root config extend its copy in `config/wirecat/`
36
37
 
@@ -41,7 +42,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
41
42
  `lefthook.yml` extends `config/wirecat/lefthook.yml`.
42
43
  - **Exceptions:** do not extend `@wirecat/cli-base/biome` or `@wirecat/cli-base/lefthook.yml`. No repository uses
43
44
  them, and `standards:check` accepts only the paths above.
44
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
45
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
45
46
 
46
47
  ### WC-TOOL-3 · Pin the tool versions that `toolchain.json` names
47
48
 
@@ -50,7 +51,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
50
51
  - **Example:** `package.json` has `"packageManager": "pnpm@11.20.0"` and exact `devDependencies` for
51
52
  `@biomejs/biome`, `cspell` and its three dictionaries, `lefthook` and `markdownlint-cli2`, as in the manifest.
52
53
  - **Exceptions:** none.
53
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
54
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
54
55
 
55
56
  ### WC-TOOL-4 · Extend the shared TypeScript config, and do not loosen it
56
57
 
@@ -101,7 +102,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
101
102
  - **Example:** the shared preset sets 2 spaces, double quotes, semicolons only where needed, trailing commas, arrow
102
103
  parentheses always and 120 columns. Run `pnpm lint:fix` to apply them.
103
104
  - **Exceptions:** none.
104
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
105
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
105
106
 
106
107
  ### WC-TOOL-8 · Keep the shared Biome rules at error
107
108
 
@@ -111,7 +112,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
111
112
  noUnusedImports, noUnusedVariables and noExplicitAny.
112
113
  - **Exceptions:** a repository may add rules or raise a level. It may not turn a shared rule off (index, "Which rule
113
114
  wins").
114
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
115
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
115
116
 
116
117
  ### WC-TOOL-9 · Write to the console only with `console.error`, except in `scripts/`
117
118
 
@@ -122,7 +123,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
122
123
  - **Exceptions:** files under `scripts/` may print, because they are development tools. A shared package prints
123
124
  nothing at all, not even with `console.error`
124
125
  ([WC-ARCH-19](architecture.md#wc-arch-19--shared-packages-print-nothing-and-log-nothing-on-their-own)).
125
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
126
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
126
127
 
127
128
  ### WC-TOOL-10 · Keep the secret lint on, and suppress a finding only with its reason
128
129
 
@@ -132,7 +133,7 @@ cli-testing, cli-docs, plus community itself. cli-template follows every rule he
132
133
  `// biome-ignore lint/security/noSecrets: Crockford base32 alphabet, not a key`.
133
134
  - **Exceptions:** the rule is off in test files, `test/`, `tests/`, `__tests__/`, `fixtures/` and `generated/`,
134
135
  because those hold fake credentials or cannot keep a suppression comment.
135
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
136
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
136
137
 
137
138
  ### WC-TOOL-11 · Keep the three grit plugins that block unsafe calls
138
139
 
@@ -149,7 +150,7 @@ no-unbounded-spread ([WC-TOOL-12](#wc-tool-12--do-not-spread-a-list-of-user-data
149
150
  concatenation. no-new-function reports `new Function(...)` and `Function(...)`.
150
151
  - **Exceptions:** a reviewed site may keep a `biome-ignore` comment with the reason, for example a Windows `.cmd` shim
151
152
  with fixed arguments. The plugins read syntax, not data flow, so review and CodeQL at release cover the rest.
152
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
153
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
153
154
 
154
155
  ### WC-TOOL-12 · Do not spread a list of user data into call arguments
155
156
 
@@ -159,7 +160,7 @@ no-unbounded-spread ([WC-TOOL-12](#wc-tool-12--do-not-spread-a-list-of-user-data
159
160
  plugin reports `.push(...x)`, `Math.max(...x)` and `Math.min(...x)` as a warning.
160
161
  - **Exceptions:** a spread over a list that is small by construction may stay. The plugin skips tests, `testing/`,
161
162
  `scripts/`, `bench/` and `performance/`.
162
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
163
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
163
164
 
164
165
  ### WC-TOOL-13 · Cap every file at 1,000 lines with Biome
165
166
 
@@ -172,7 +173,7 @@ no-unbounded-spread ([WC-TOOL-12](#wc-tool-12--do-not-spread-a-list-of-user-data
172
173
  `src/telegram/adapter.ts`; four files in cli-core). A smaller cap is allowed: zoom uses 500. cli-docs turns it off for
173
174
  stylesheets. Biome reads only JavaScript and TypeScript, so the cap does not cover
174
175
  code in another language, such as wa's Go engine; the review signals of WC-LAY-7 still apply to it.
175
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
176
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
176
177
 
177
178
  ### WC-TOOL-14 · Turn on the import cycle rule
178
179
 
@@ -180,7 +181,7 @@ no-unbounded-spread ([WC-TOOL-12](#wc-tool-12--do-not-spread-a-list-of-user-data
180
181
  - **Enforced by:** `pnpm lint` · `standards.yml:standards` (the shared Biome base, like WC-TOOL-8).
181
182
  - **Example:** the shared Biome base sets the suspicious rule noImportCycles to error.
182
183
  - **Exceptions:** none.
183
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
184
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
184
185
 
185
186
  ### WC-TOOL-15 · Declare layer boundaries as restricted imports in `biome.json`
186
187
 
@@ -218,7 +219,7 @@ no-unbounded-spread ([WC-TOOL-12](#wc-tool-12--do-not-spread-a-list-of-user-data
218
219
  - **Exceptions:** a general word goes into the community word list, not into each project. cli-base checks
219
220
  `README.md` and `docs/standards/`; cli-docs its site pages in `content/docs/`; community every Markdown file it
220
221
  publishes. cli-core, zoom and cli-testing check only `README.md` yet.
221
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
222
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
222
223
 
223
224
  ### WC-TOOL-18 · Lint Markdown with `markdownlint-cli2` and the shared preset
224
225
 
@@ -227,7 +228,7 @@ no-unbounded-spread ([WC-TOOL-12](#wc-tool-12--do-not-spread-a-list-of-user-data
227
228
  - **Example:** the preset turns on only: no tabs (MD010), at most two blank lines in a row (MD012), a language on
228
229
  every fenced code block (MD040) and no empty links (MD042). `.markdownlint-cli2.jsonc` lists the files to check.
229
230
  - **Exceptions:** a repository may turn on more rules in its root config.
230
- - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
231
+ - **Applies to:** the WireCat repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
231
232
 
232
233
  ### WC-TOOL-19 · Check user pages with `rumdl` and the shared `rumdl.toml`
233
234
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-base",
3
- "version": "0.62.0",
3
+ "version": "0.64.0",
4
4
  "description": "The parts every command line tool needs: output modes, terminal rendering, error model, exit codes, credentials, clocks",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Viacheslav Ptsarev",
@@ -135,6 +135,7 @@
135
135
  "@vitest/coverage-v8": "^5.0.5",
136
136
  "commander": "^15.0.0",
137
137
  "cspell": "10.4.0",
138
+ "esbuild": "0.28.2",
138
139
  "lefthook": "2.2.2",
139
140
  "markdownlint-cli2": "0.24.0",
140
141
  "typescript": "^7.0.2",
@@ -146,12 +147,16 @@
146
147
  },
147
148
  "peerDependencies": {
148
149
  "commander": ">=15",
150
+ "esbuild": "^0.28.0",
149
151
  "vitest": ">=5"
150
152
  },
151
153
  "peerDependenciesMeta": {
152
154
  "commander": {
153
155
  "optional": true
154
156
  },
157
+ "esbuild": {
158
+ "optional": true
159
+ },
155
160
  "vitest": {
156
161
  "optional": true
157
162
  }