@wirecat/cli-base 0.60.0 → 0.61.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,40 @@ Versions before 0.8.0 are in the [git tags](https://github.com/WireCatLabs/cli-b
8
8
  Every entry says what changed as a caller sees it, why, and what to watch for — the rules are
9
9
  [`docs/dev/CONVENTIONS.md`](docs/dev/CONVENTIONS.md#the-changelog).
10
10
 
11
+ ## 0.61.1 — 26.10.2026
12
+
13
+ ### Fixed
14
+
15
+ - **The `--record` flag's meaning says what a run keeps now.** It read "keep this run under runs: ids and timings,
16
+ never content", which stopped being true when a run started keeping the command line as typed. It now reads cli-core
17
+ 0.440.0's help line: "keep this run, with the command as typed and secrets hidden; record_input false leaves the
18
+ typed words out". cli-core's option catalogue picks it up at its next cli-base bump.
19
+ [Lifecycle](docs/standards/lifecycle.md#runs) also says how a CLI with a program of its own hands cli-core the
20
+ words it parsed, without which its runs keep no command line.
21
+
22
+ ### Security
23
+
24
+ - **The secret-handling rule lists what a run record hides by content.** Besides secret-named flags, a URL password
25
+ and a long opaque string, cli-core finds a token of a known format, a `Bearer` or `Basic` credential, the value of a
26
+ secret-named `name=value` pair and a random-looking string of 20 or more characters inside any typed word, and the
27
+ same in a kept error message (`WC-SECR-1`).
28
+ - **`release-checks.yml` runs CodeQL action v4.39.1, pinned by its commit.** It was pinned to the `v4` tag object,
29
+ which still pointed at v4.38.3. A caller gets the newer analysis when it moves its `release-checks.yml` pin to the
30
+ release that carries this.
31
+
32
+ ## 0.61.0 — 26.10.2026
33
+
34
+ ### Changed — may break callers
35
+
36
+ - **A run record keeps the command line as typed**
37
+ ([Security](docs/standards/security.md#wc-secr-1--private-data-and-secrets-never-reach-a-log-a-fixture-or-a-committed-document)).
38
+ The handbook said a run record never holds message text; a run's `argv` now keeps the words typed, so the owner can
39
+ read back what was run. A secret stays hidden: an option or argument marked with cli-core's `secretInput(...)`, one
40
+ named for a token, password, secret, credential, cookie, authorization or API key, a password in a URL, a long
41
+ opaque string. `record_input: false` in a CLI's config masks as before. A CLI's tests that assert a typed marker is
42
+ absent from its run folder now look outside `argv` ([Testing](docs/standards/testing.md)), and a CLI's own document
43
+ that says its run log hides what was typed needs the same change.
44
+
11
45
  ## 0.60.0 — 26.10.2026
12
46
 
13
47
  ### Added
@@ -330,7 +330,7 @@ export const HOW_FLAGS = [
330
330
  name: "--record",
331
331
  role: "mode",
332
332
  type: "switch",
333
- meaning: "keep this run under runs: ids and timings, never content",
333
+ meaning: "keep this run, with the command as typed and secrets hidden; record_input false leaves the typed words out",
334
334
  },
335
335
  { name: "--regex", role: "mode", type: "switch", meaning: "the words are one regular expression" },
336
336
  { name: "--silent", role: "mode", type: "switch", meaning: "deliver without a notification" },
@@ -14,8 +14,8 @@ A "one-shot" command does one job and ends: most commands. A "long-running" comm
14
14
  `lifetime: "persistent"` (it runs until it is stopped, such as `serve` or `watch`) or `lifetime: "interactive"` (it
15
15
  waits for a person, such as a login).
16
16
 
17
- A "run" is one command's record: what it was, how it ended, and its events, never content. The rules on what a
18
- run's events may hold are [WC-SECR-1](security.md#wc-secr-1--private-data-and-secrets-never-reach-a-log-a-fixture-or-a-committed-document)
17
+ A "run" is one command's record: what it was, as typed, how it ended, and its events, which never hold content. The
18
+ rules on what a run may hold are [WC-SECR-1](security.md#wc-secr-1--private-data-and-secrets-never-reach-a-log-a-fixture-or-a-committed-document)
19
19
  and [WC-SECR-2](security.md#wc-secr-2--a-log-keeps-only-known-attribute-keys-and-hides-content-keys).
20
20
 
21
21
  ### Who follows these rules today
@@ -198,7 +198,10 @@ provider's limit as often as it ends. These three rules make the next run carry
198
198
  ### WC-LIFE-15 · Keep a run log through cli-core, and read it back with `runs`
199
199
 
200
200
  A failed command is always kept as a run, unless the person turned recording off with `--no-record` or
201
- `record: false` in the config. `--record` keeps every run of a command that does its work inside cli-core's run
201
+ `record: false` in the config. A run keeps the command line as typed, secrets hidden; `record_input: false` masks
202
+ every value that may be content
203
+ ([WC-SECR-1](security.md#wc-secr-1--private-data-and-secrets-never-reach-a-log-a-fixture-or-a-committed-document)).
204
+ `--record` keeps every run of a command that does its work inside cli-core's run
202
205
  (`context.run`, or `startRecording` in a program of its own). A run is a folder `<state>/runs/<day>/<run_id>/` with
203
206
  `run.json` and `events.jsonl`, one log record per line. `runs list` and `runs show` read it.
204
207
 
@@ -207,6 +210,8 @@ A failed command is always kept as a run, unless the person turned recording off
207
210
  returns the owner's `record` and `keep_runs_for_days` as `keepFailedRuns` and `keepRunsForDays`, never fixed values.
208
211
  - A CLI with a program of its own opens each command's run with `startRecording` from `@wirecat/cli-core/cli`,
209
212
  ends it with `succeed` or `fail`, adds `--record` and `--no-record` at the root and registers `runsCommand(app)`.
213
+ Its run keeps the command line only when cli-core is given the words it parsed: `context: runContextOf({ program,
214
+ argv, … })` to `startRecording`, or `argv` in the program's environment (`provide`) under `recordRuns`.
210
215
 
211
216
  - **Why:** when a command fails, a person or an agent needs to see what it did, in the same place and shape in every
212
217
  CLI. Without the rule, three CLIs shipped with no run log, and one switched cli-core's off.
@@ -21,13 +21,31 @@ Rule ids on this page are `WC-SECR-<n>`. How to read a rule, how ids work and wh
21
21
  ### WC-SECR-1 · Private data and secrets never reach a log, a fixture or a committed document
22
22
 
23
23
  Command output is the only place where a message the owner asked to read may appear. A log, a run record, a test
24
- fixture, a document and a commit message never hold message text, a token or a phone number.
24
+ fixture, a document and a commit message never hold message text, a token or a phone number — with one exception:
25
+ a run record keeps the command line the person typed.
26
+
27
+ A run record's `argv` keeps the words as typed by default, so the history of what was run can be read back. A secret
28
+ in them is always `[redacted]`: the value of an option or argument the CLI marks with cli-core's `secretInput(...)`,
29
+ one whose name says token, password, passphrase, secret, credential, cookie, authorization or API key, a password
30
+ inside a URL, and a long opaque string. Inside any typed word cli-core also finds a secret by its content and replaces
31
+ only the secret: a token of a known format (GitHub `ghp_…`/`github_pat_…`, `sk-…`, Slack `xox…-`, AWS `AKIA…`, Google
32
+ `AIza…`, Stripe `sk_`/`rk_`, npm `npm_…`, a Telegram bot token, a JWT, a PEM private key), a `Bearer` or `Basic`
33
+ credential, the value of a secret-named pair (`password=…`, `API_TOKEN=…`, `client_secret:…`), a random-looking string
34
+ of 20 or more characters, and a phone number. The same search runs on a kept error message. `record_input: false` in the CLI's config masks every value that may be content, and a
35
+ config that will not load masks the same way. A problem report sent to other people (`doctor reports create`) masks
36
+ the typed words always.
25
37
 
26
38
  - **Why:** a log or a repository is copied and kept far longer than anyone remembers; private data in it is a leak.
27
39
  - **Enforced by:** `node-ci.yml:secrets`.
28
40
  - **Example:** a log line says `{ "event": "send", "outcome": "sent", "count": 1 }`, not the text that was sent.
29
- - **Exceptions:** none. The scanners catch secrets of known shapes; message text and names are caught only in review.
30
- - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
41
+ `tg messages send Mom "see you at 5"` is kept in its run as typed; `tg bot api set-webhook --body '{…}'` keeps
42
+ `--body [redacted]`, since cli-core marks `--body` with `secretInput`. A CLI's own option that takes a secret is
43
+ declared `secretInput(new Option("--pin <code>"))` — although under
44
+ [WC-SECR-5](#wc-secr-5--a-secret-is-never-taken-on-the-command-line) such an option should not exist.
45
+ - **Exceptions:** a run record's `argv`, as above: messaging CLIs already keep every message in the store, so the
46
+ words typed are not hidden from the owner's own run log. The scanners catch secrets of known shapes; message text
47
+ and names elsewhere are caught only in review.
48
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** NEED-1829.
31
49
 
32
50
  ### WC-SECR-2 · A log keeps only known attribute keys, and hides content keys
33
51
 
@@ -124,7 +124,8 @@ and which run after merge is in [CI](ci.md).
124
124
  - **Enforced by:** review only.
125
125
  - **Example:** test data is visibly fake: `synthetic text ${id}`, the phone number `+71234567890`, the device id
126
126
  `00000000-0000-0000-0000-000000000001`, `your-token-here`. Content that must stay hidden carries a unique marker,
127
- and the test asserts that the marker is absent from output, errors and run events, while the id is present:
127
+ and the test asserts that the marker is absent from output, errors and run events (a run's `argv` keeps what was
128
+ typed, so a marker typed on the command line is looked for outside it), while the id is present:
128
129
  `expect(err).not.toContain(token)`. The positive check stops the test from passing by recording nothing.
129
130
  - **Exceptions:** none.
130
131
  - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-base",
3
- "version": "0.60.0",
3
+ "version": "0.61.1",
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",