@wirecat/cli-base 0.40.3 → 0.41.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/README.md +1 -0
- package/dist/commands/document.d.ts.map +1 -1
- package/dist/commands/document.js +1 -0
- package/dist/commands/document.js.map +1 -1
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +6 -4
- package/dist/commands/index.js.map +1 -1
- package/dist/standards/vocabulary.d.ts.map +1 -1
- package/dist/standards/vocabulary.js +1 -0
- package/dist/standards/vocabulary.js.map +1 -1
- package/docs/standards/README.md +111 -0
- package/docs/standards/accounts.md +148 -0
- package/docs/standards/architecture.md +214 -0
- package/docs/standards/ci.md +159 -0
- package/docs/standards/commands.md +302 -0
- package/docs/standards/docs.md +214 -0
- package/docs/standards/layout.md +128 -0
- package/docs/standards/lifecycle.md +143 -0
- package/docs/standards/mcp.md +207 -0
- package/docs/standards/new-cli.md +111 -0
- package/docs/standards/output.md +256 -0
- package/docs/standards/permissions.md +295 -0
- package/docs/standards/releases.md +191 -0
- package/docs/standards/security.md +260 -0
- package/docs/standards/store.md +177 -0
- package/docs/standards/style.md +119 -0
- package/docs/standards/testing.md +222 -0
- package/docs/standards/toolchain.md +232 -0
- package/package.json +4 -3
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Style
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
How code and history read: comments say why and only where needed, names, TypeScript habits, and commit messages.
|
|
6
|
+
|
|
7
|
+
Rule ids on this page are `WC-STYLE-<n>`. How to read a rule, how ids work and which rule wins are in the
|
|
8
|
+
[index](README.md). Formatting and the lint rules are on the [Toolchain page](toolchain.md); Biome decides
|
|
9
|
+
formatting, so this page does not repeat it.
|
|
10
|
+
|
|
11
|
+
## Rules
|
|
12
|
+
|
|
13
|
+
### WC-STYLE-1 · Write a comment only where the code cannot say it, and say why
|
|
14
|
+
|
|
15
|
+
- **Why:** a comment costs a reader's attention and goes stale silently, so it must carry what the code cannot.
|
|
16
|
+
- **Enforced by:** review only.
|
|
17
|
+
- **Example:** a comment records a decision, warns about a trap, or names a constraint that is not visible in the
|
|
18
|
+
file: `// A static import would load the whole program before ensureSqlite could swap it.`
|
|
19
|
+
- **Exceptions:** none. When in doubt, leave it out; the commit message, the pull request and the tests carry the
|
|
20
|
+
story.
|
|
21
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
22
|
+
|
|
23
|
+
### WC-STYLE-2 · Do not restate the code, narrate a change or leave old code in comments
|
|
24
|
+
|
|
25
|
+
- **Why:** these comments repeat what the code or git already says, and they turn false at the next edit.
|
|
26
|
+
- **Enforced by:** review only.
|
|
27
|
+
- **Example:** no `// increment the counter` above `count++`, no `// fixed the timeout bug`, no section banners, no
|
|
28
|
+
commented-out alternatives. A test gets a clear name, not a paragraph above it.
|
|
29
|
+
- **Exceptions:** existing comments in a file you only pass through stay; this rule is for new comments.
|
|
30
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
31
|
+
|
|
32
|
+
### WC-STYLE-3 · Name files in kebab case, and name a test after what it tests
|
|
33
|
+
|
|
34
|
+
- **Why:** one naming habit lets a reader and a glob find a module and its test without searching.
|
|
35
|
+
- **Enforced by:** review only.
|
|
36
|
+
- **Example:** `src/format-markdown.ts` and `src/format-markdown.test.ts`. A test that covers a behaviour across
|
|
37
|
+
modules is named after that behaviour, such as `src/every-failure.test.ts`.
|
|
38
|
+
- **Exceptions:** none.
|
|
39
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
40
|
+
|
|
41
|
+
### WC-STYLE-4 · Write functions in the small, and a class only where identity matters
|
|
42
|
+
|
|
43
|
+
- **Why:** a function that takes its inputs is easy to test and to reuse; a class earns its place by holding state
|
|
44
|
+
that must live together.
|
|
45
|
+
- **Enforced by:** review only.
|
|
46
|
+
- **Example:** a client that holds a connection and a session is a class. Parsing, mapping and formatting are plain
|
|
47
|
+
functions.
|
|
48
|
+
- **Exceptions:** none.
|
|
49
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
50
|
+
|
|
51
|
+
### WC-STYLE-5 · Narrow a type instead of casting it with `as`
|
|
52
|
+
|
|
53
|
+
- **Why:** a cast tells the compiler to stop checking, so a renamed field fails at run time instead of at build time.
|
|
54
|
+
- **Enforced by:** review only.
|
|
55
|
+
- **Example:** narrow with a type guard, `instanceof` or a shape check. A test fixture uses an honest type, such as
|
|
56
|
+
`Omit<T, "x"> & { x: string | null }`, not `as unknown as T`.
|
|
57
|
+
- **Exceptions:** `as const` is allowed. A cast that cannot be avoided, because a library is typed too loosely, keeps
|
|
58
|
+
a comment on that line that says why. Existing casts are not yet removed; the rule holds for new code.
|
|
59
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
60
|
+
|
|
61
|
+
### WC-STYLE-6 · In a `catch`, narrow with `instanceof` and wrap anything else
|
|
62
|
+
|
|
63
|
+
- **Why:** a caught value can be anything, and the error model needs a code and a cause to show the right message.
|
|
64
|
+
- **Enforced by:** review only.
|
|
65
|
+
- **Example:** `e instanceof CliError ? e : new CliError("provider_error", String(e), { cause: e })`. The error codes
|
|
66
|
+
and reasons are on the [Output page](output.md).
|
|
67
|
+
- **Exceptions:** none.
|
|
68
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
69
|
+
|
|
70
|
+
### WC-STYLE-7 · Annotate exports and signatures, and let the rest infer
|
|
71
|
+
|
|
72
|
+
- **Why:** a redundant annotation is noise, and a hand-written `x is T` is not checked against its body.
|
|
73
|
+
- **Enforced by:** review only.
|
|
74
|
+
- **Example:** `export function count(items: readonly Item[]): number` with `const total = items.length` inside. In
|
|
75
|
+
`.filter()`, let the callback narrow: `xs.filter((x) => x !== null)`. Write `x is T` only for a named, reused guard
|
|
76
|
+
or a check the compiler cannot follow.
|
|
77
|
+
- **Exceptions:** none.
|
|
78
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
79
|
+
|
|
80
|
+
### WC-STYLE-8 · Inline a type used once, and keep a type beside the code that owns it
|
|
81
|
+
|
|
82
|
+
- **Why:** a name for a one-off type sends the reader to another place for nothing, and a shared types file collects
|
|
83
|
+
types nobody owns.
|
|
84
|
+
- **Enforced by:** review only.
|
|
85
|
+
- **Example:** name a type when it is exported or used in three or more places. Keep it in the module that owns it. A
|
|
86
|
+
shared types file holds only a contract between several modules.
|
|
87
|
+
- **Exceptions:** none.
|
|
88
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
89
|
+
|
|
90
|
+
### WC-STYLE-9 · Spread an optional field in, and build an object in one expression
|
|
91
|
+
|
|
92
|
+
- **Why:** an object built once has one type that the compiler checks; a key added later widens it or fails to
|
|
93
|
+
compile.
|
|
94
|
+
- **Enforced by:** review only.
|
|
95
|
+
- **Example:** `{ id, ...(signal === undefined ? {} : { signal }) }`, never `{ id, signal: undefined }`. Use
|
|
96
|
+
`=== undefined` when a falsy value is valid. A small helper that returns the optional part is fine.
|
|
97
|
+
- **Exceptions:** none. The shared TypeScript config leaves `exactOptionalPropertyTypes` off, so the compiler does not
|
|
98
|
+
force this.
|
|
99
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
100
|
+
|
|
101
|
+
### WC-STYLE-10 · Write commit messages and pull request titles as conventional commits
|
|
102
|
+
|
|
103
|
+
- **Why:** the type and scope tell a reader what changed before they open it, and `!` tells the changelog guard that a
|
|
104
|
+
caller may break.
|
|
105
|
+
- **Enforced by:** review only.
|
|
106
|
+
- **Example:** `feat(standards): add the verb scan`, `docs(standards): toolchain rules`,
|
|
107
|
+
`feat!: remove the --take alias`. The body says why. A title marked breaking needs a changelog line; the
|
|
108
|
+
changelog rules are on the [Documents page](docs.md).
|
|
109
|
+
- **Exceptions:** none.
|
|
110
|
+
- **Applies to:** all repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
111
|
+
|
|
112
|
+
## Sources
|
|
113
|
+
|
|
114
|
+
These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
|
|
115
|
+
holds.
|
|
116
|
+
|
|
117
|
+
- [cli-base `CONVENTIONS.md`, "Code"](https://github.com/WireCatLabs/cli-base/blob/main/docs/dev/CONVENTIONS.md#code)
|
|
118
|
+
- [tg-cli TypeScript standards](https://github.com/WireCatLabs/tg-cli/tree/main/agent-os/standards/typescript): no casts,
|
|
119
|
+
inference and optional fields
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
How a CLI is tested: the sandbox, no network and no real waits in tests, what kind of test to write, coverage
|
|
6
|
+
floors, offline contracts, the test matrix, parity between CLIs, and the live checks that are not tests.
|
|
7
|
+
|
|
8
|
+
Rule ids on this page are `WC-TEST-<n>`. How to read a rule, how ids work and which rule wins are in the
|
|
9
|
+
[index](README.md).
|
|
10
|
+
|
|
11
|
+
Related pages: tests and the shared store are in [Store](store.md); secrets in logs are in [Security](security.md);
|
|
12
|
+
typechecking the tests and the Bun smoke test are in [Toolchain](toolchain.md); which checks run on a pull request
|
|
13
|
+
and which run after merge is in [CI](ci.md).
|
|
14
|
+
|
|
15
|
+
### Words used here
|
|
16
|
+
|
|
17
|
+
- **Sandbox:** a vitest `setupFiles` entry that runs before every test file and moves every path a test could write
|
|
18
|
+
into a temporary directory.
|
|
19
|
+
- **Offline contract:** a check that runs the built CLI from outside, with no account and no network, and compares
|
|
20
|
+
its help, its `commands --json` and its MCP tool list with reviewed snapshots. The runner is `cli-contract` from
|
|
21
|
+
`@wirecat/cli-testing`.
|
|
22
|
+
- **Test matrix:** the page that lists every command and option of a CLI, with the test that drove it or the reason
|
|
23
|
+
why no offline test can.
|
|
24
|
+
- **Full validation:** the CI run on each merge to `main`, on a release and in the monthly run. It is not the pull
|
|
25
|
+
request run.
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
### WC-TEST-1 · Point every path a test could write at a temporary directory
|
|
30
|
+
|
|
31
|
+
- **Why:** one test that falls back to a default path writes into the owner's config, state, cache or store.
|
|
32
|
+
- **Enforced by:** review only.
|
|
33
|
+
- **Example:** `src/testing/sandbox.ts` is a vitest `setupFiles` entry, so it holds for every test file, including
|
|
34
|
+
the next one. It sets the CLI's config, state and cache directories, the store variables
|
|
35
|
+
([WC-STORE-14](store.md#wc-store-14--tests-never-open-the-owners-store)) and `TMPDIR`, `TMP` and `TEMP` to a
|
|
36
|
+
directory of its own. It closes resources first, then removes that directory and restores the variables when the
|
|
37
|
+
file is done.
|
|
38
|
+
- **Exceptions:** keep coverage reports and debug traces outside the sandbox, with bounded retention. Never clean
|
|
39
|
+
another session's scratch directory as test teardown.
|
|
40
|
+
- **Applies to:** all CLIs and the shared packages. drive has no sandbox yet, and zoom's sandbox moves only the
|
|
41
|
+
temporary directory. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
42
|
+
|
|
43
|
+
### WC-TEST-2 · No test reaches the real keyring
|
|
44
|
+
|
|
45
|
+
- **Why:** the owner's tokens live in the real keychain, and one test that forgets an option would write there.
|
|
46
|
+
- **Enforced by:** `src/keyring.test.ts`.
|
|
47
|
+
- **Example:** every test passes `memoryKeyring()` from `@wirecat/cli-base/testing`. cli-base's own sandbox also
|
|
48
|
+
replaces `@napi-rs/keyring` with a module that throws, so a forgotten option fails the test instead of reaching the
|
|
49
|
+
keychain, and `src/keyring.test.ts` asserts that `systemKeyring` throws under it.
|
|
50
|
+
- **Exceptions:** none. The CLIs' sandboxes do not replace `@napi-rs/keyring` yet; tg and max only scope the keyring
|
|
51
|
+
entry through environment variables.
|
|
52
|
+
- **Applies to:** all CLIs and the shared packages. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
53
|
+
|
|
54
|
+
### WC-TEST-3 · No test contacts a provider or the network
|
|
55
|
+
|
|
56
|
+
- **Why:** a test that reaches the network is slow, flaky, and can act on a real account.
|
|
57
|
+
- **Enforced by:** `max-cli: src/testing/unscripted.ts`.
|
|
58
|
+
- **Example:** max-cli's `src/testing/mock-max.ts` scripts the service: an answer per request, a refusal, or silence
|
|
59
|
+
to test a timeout. A request with no scripted answer fails the test that sent it, through a second `setupFiles`
|
|
60
|
+
entry. tg's `scripted({...})` adapter does the same job.
|
|
61
|
+
- **Exceptions:** none. No CLI has a global guard that refuses sockets and `fetch` in tests yet.
|
|
62
|
+
- **Applies to:** all CLIs and the shared packages. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
63
|
+
|
|
64
|
+
### WC-TEST-4 · Give a command that must not connect an adapter that throws
|
|
65
|
+
|
|
66
|
+
- **Why:** a command that swallows an adapter error would otherwise pass while it still connects.
|
|
67
|
+
- **Enforced by:** review only.
|
|
68
|
+
- **Example:** an `--offline` test passes an adapter that throws "--offline must never open Telegram". When the
|
|
69
|
+
adapter is shared across a file, it is a `vi.fn`, and `afterAll` checks `expect(refuse).not.toHaveBeenCalled()`.
|
|
70
|
+
The test leaves the provider credentials out of `env` to show that none are needed.
|
|
71
|
+
- **Exceptions:** none.
|
|
72
|
+
- **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
73
|
+
|
|
74
|
+
### WC-TEST-5 · No test waits for real time
|
|
75
|
+
|
|
76
|
+
- **Why:** a test that sleeps a real second crosses the time limit on a slow CI runner and fails at random.
|
|
77
|
+
- **Enforced by:** review only.
|
|
78
|
+
- **Example:** waits go through an injected `SleepLike`, and `fakeClock()` from `@wirecat/cli-base/testing` records
|
|
79
|
+
them without waiting. A test harness passes `sleep: async () => {}`. `pnpm test:slow` lists the 20 slowest tests
|
|
80
|
+
and the 10 slowest files.
|
|
81
|
+
- **Exceptions:** none. A new wait in the code gets a seam, never a longer test timeout.
|
|
82
|
+
- **Applies to:** all CLIs and the shared packages. **Since:** cli-base 0.41.0. **Rulings:** dev-process:4.
|
|
83
|
+
|
|
84
|
+
### WC-TEST-6 · Test mostly through the command line, with `run()`
|
|
85
|
+
|
|
86
|
+
- **Why:** a test that drives `run()` checks what a person or an agent types, from parsing to output.
|
|
87
|
+
- **Enforced by:** review only.
|
|
88
|
+
- **Example:** most tests call `run(["chats", "list", "--json"], environment)` with fake effects and check stdout,
|
|
89
|
+
stderr and the exit code. Unit tests cover pure logic with many cases. Adapter contract cases (cli-core
|
|
90
|
+
`./testing`) cover implementations that must behave the same.
|
|
91
|
+
- **Exceptions:** none.
|
|
92
|
+
- **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
93
|
+
|
|
94
|
+
### WC-TEST-7 · Write the test that pins a promise someone could break
|
|
95
|
+
|
|
96
|
+
- **Why:** a test that restates the code passes when the code is wrong; a test of a promise fails.
|
|
97
|
+
- **Enforced by:** review only.
|
|
98
|
+
- **Example:** reading history marks nothing read; a retried send reuses its id; a send with no answer is
|
|
99
|
+
`outcome_unknown`, never failed and never sent; an ambiguous chat name is refused, not guessed.
|
|
100
|
+
- **Exceptions:** none.
|
|
101
|
+
- **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
102
|
+
|
|
103
|
+
### WC-TEST-8 · Prove that content does not leak, with a marker and visibly fake data
|
|
104
|
+
|
|
105
|
+
- **Why:** "the output has no message text" only means something when the text was there to leak; a convention alone
|
|
106
|
+
proves nothing.
|
|
107
|
+
- **Enforced by:** review only.
|
|
108
|
+
- **Example:** test data is visibly fake: `synthetic text ${id}`, the phone number `+71234567890`, the device id
|
|
109
|
+
`00000000-0000-0000-0000-000000000001`, `your-token-here`. Content that must stay hidden carries a unique marker,
|
|
110
|
+
and the test asserts that the marker is absent from output, errors and run events, while the id is present:
|
|
111
|
+
`expect(err).not.toContain(token)`. The positive check stops the test from passing by recording nothing.
|
|
112
|
+
- **Exceptions:** none.
|
|
113
|
+
- **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
114
|
+
|
|
115
|
+
### WC-TEST-9 · Give each test its own profile or its own store
|
|
116
|
+
|
|
117
|
+
- **Why:** the sandbox is per file, so tests in one file share config, the send journal and the store.
|
|
118
|
+
- **Enforced by:** review only.
|
|
119
|
+
- **Example:** each test passes its own profile name first, or a file-level constant. A test that needs an empty
|
|
120
|
+
store makes a fresh directory and passes `MESSAGING_STORE`.
|
|
121
|
+
- **Exceptions:** none.
|
|
122
|
+
- **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
123
|
+
|
|
124
|
+
### WC-TEST-10 · A skip is not a pass: report the suite that ran and its counts
|
|
125
|
+
|
|
126
|
+
- **Why:** a suite that ran nothing, or skipped what mattered, still exits 0.
|
|
127
|
+
- **Enforced by:** review only.
|
|
128
|
+
- **Example:** when you report work, name the suite that ran and give its counts: passed, failed and skipped. A
|
|
129
|
+
skipped test is counted as skipped, never as passed. That the tests are typechecked at all is
|
|
130
|
+
[WC-TOOL-5](toolchain.md#wc-tool-5--typecheck-every-typescript-file-source-tests-and-scripts).
|
|
131
|
+
- **Exceptions:** none.
|
|
132
|
+
- **Applies to:** all CLIs and the shared packages. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
133
|
+
|
|
134
|
+
### WC-TEST-11 · Keep a coverage floor, and raise it; never lower it
|
|
135
|
+
|
|
136
|
+
- **Why:** a floor stops coverage from falling one pull request at a time.
|
|
137
|
+
- **Enforced by:** `pnpm test:coverage` · `node-ci.yml:check`.
|
|
138
|
+
- **Example:** `vitest.config.ts` holds thresholds for lines, statements, functions and branches over `src/`, a little
|
|
139
|
+
under what the suite reaches, and `perFile: { lines: 50 }`. A change that falls below gets a test, not a lower
|
|
140
|
+
number. Each excluded file has its reason written beside it.
|
|
141
|
+
- **Exceptions:** generated code, types-only files, the entry point, and code that only runs under Bun or as a
|
|
142
|
+
separate process, each with its reason.
|
|
143
|
+
- **Applies to:** all CLIs and the shared packages. memo has no thresholds yet; drive and zoom have no per-file
|
|
144
|
+
floor. **Since:** cli-base 0.41.0. **Rulings:** dev-process:4.
|
|
145
|
+
|
|
146
|
+
### WC-TEST-12 · Every command and option has a test, or a written reason
|
|
147
|
+
|
|
148
|
+
- **Why:** a flag that no test passes can break without anyone noticing.
|
|
149
|
+
- **Enforced by:** `tg-cli: pnpm test:matrix` · `max-cli: pnpm test:matrix` · `whatsapp-cli: pnpm test:matrix` ·
|
|
150
|
+
`zoom-cli: pnpm test:matrix:check`.
|
|
151
|
+
- **Example:** under vitest, `run()` appends each parsed command path and option name (never a value) to
|
|
152
|
+
`coverage/argv.jsonl`. `pnpm test:matrix` turns that into `docs/dev/test-matrix.md` and fails on a command or
|
|
153
|
+
option with neither a test nor a reason. A reason names the live scenario that covers it. A test that calls a
|
|
154
|
+
function directly does not count.
|
|
155
|
+
- **Exceptions:** none.
|
|
156
|
+
- **Applies to:** all CLIs. tg, max, zoom and wa have the matrix; memo and drive do not yet. **Since:** cli-base
|
|
157
|
+
0.41.0. **Rulings:** NEED-359.
|
|
158
|
+
|
|
159
|
+
### WC-TEST-13 · Keep offline contracts for help, discovery, errors and the MCP tool list
|
|
160
|
+
|
|
161
|
+
- **Why:** agents depend on `commands --json` and the MCP tool list; a change to them must be seen and reviewed.
|
|
162
|
+
- **Enforced by:** `tg-cli: pnpm contracts:check` · `max-cli: pnpm contracts:check` ·
|
|
163
|
+
`whatsapp-cli: pnpm contracts:check` · `drive-cli: pnpm contracts:check` · `zoom-cli: pnpm contracts:check`.
|
|
164
|
+
- **Example:** `pnpm contracts:check` runs `cli-contract contracts/plan.json` against the built CLI. It checks the
|
|
165
|
+
help snapshot, that discovery is one JSON value on stdout with empty stderr, that a bad option gives the documented
|
|
166
|
+
exit code and one JSON error on stderr, and the MCP tool names, schemas and annotations. A change is accepted with
|
|
167
|
+
`pnpm exec cli-contract contracts/plan.json --update` and a reviewed diff.
|
|
168
|
+
- **Exceptions:** the contracts run in full validation, not on pull requests.
|
|
169
|
+
- **Applies to:** all CLIs. memo has no contracts yet. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
170
|
+
|
|
171
|
+
### WC-TEST-14 · Check the upgrade from the previous published version
|
|
172
|
+
|
|
173
|
+
- **Why:** a release that cannot read what the previous one wrote loses the owner's data.
|
|
174
|
+
- **Enforced by:** `tg-cli: pnpm contracts:upgrade` · `max-cli: pnpm contracts:upgrade` ·
|
|
175
|
+
`drive-cli: pnpm contracts:upgrade` · `zoom-cli: pnpm contracts:upgrade`.
|
|
176
|
+
- **Example:** `pnpm contracts:upgrade` runs the previous published package and this build on the same synthetic
|
|
177
|
+
state and checks that the data survives. Each store migration also has its own upgrade test (WC-STORE-9).
|
|
178
|
+
- **Exceptions:** a CLI with no local state.
|
|
179
|
+
- **Applies to:** all CLIs with local state. memo and wa have no upgrade contract yet. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
180
|
+
|
|
181
|
+
### WC-TEST-15 · A refactor keeps `commands --json` and the MCP tool list as they were
|
|
182
|
+
|
|
183
|
+
- **Why:** a change that is meant to move code must not change what agents see.
|
|
184
|
+
- **Enforced by:** review only.
|
|
185
|
+
- **Example:** capture `commands --json` and the MCP tool list from `main` before the first edit, and compare them
|
|
186
|
+
after the last. The offline contract snapshots (WC-TEST-13) do the same job in full validation.
|
|
187
|
+
- **Exceptions:** a refactor that changes behaviour on purpose says so in its pull request.
|
|
188
|
+
- **Applies to:** all CLIs and cli-core. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
189
|
+
|
|
190
|
+
### WC-TEST-16 · A messenger CLI matches its column of the parity manifest
|
|
191
|
+
|
|
192
|
+
- **Why:** tg, max and wa promise the same commands and options where their messengers allow it.
|
|
193
|
+
- **Enforced by:** `<app>: pnpm parity:check` · `cli-core: parity.yml` · `cli-core: src/parity/manifest.test.ts`.
|
|
194
|
+
- **Example:** `pnpm parity:check` compares the CLI's `commands --json` with its column of `parity.json` from the
|
|
195
|
+
cli-core version it installed. cli-core's `parity.yml` builds tg, max and wa from `main` and runs the same check in
|
|
196
|
+
full validation.
|
|
197
|
+
- **Exceptions:** a row marked `planned` passes whether the command exists or not.
|
|
198
|
+
- **Applies to:** messenger CLIs (tg, max, wa). **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
199
|
+
|
|
200
|
+
### WC-TEST-17 · Merged into [WC-TOOL-6](toolchain.md#wc-tool-6--support-node-22-and-later-and-bun-and-run-the-built-exports-under-bun)
|
|
201
|
+
|
|
202
|
+
### WC-TEST-18 · Check the real service by hand, never in the test suite
|
|
203
|
+
|
|
204
|
+
- **Why:** a check against a real account needs a live login and can send messages to people.
|
|
205
|
+
- **Enforced by:** review only.
|
|
206
|
+
- **Example:** live scenarios run by hand, by the owner or with the owner's yes, on test profiles and test chats
|
|
207
|
+
only. The cast lives in an ignored file, no profile is assumed, and the record keeps the shape of each answer,
|
|
208
|
+
never its content. When a scenario is run again, the sentence it supports is updated.
|
|
209
|
+
- **Exceptions:** none.
|
|
210
|
+
- **Applies to:** all CLIs that talk to a real account. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
211
|
+
|
|
212
|
+
## Sources
|
|
213
|
+
|
|
214
|
+
These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
|
|
215
|
+
holds.
|
|
216
|
+
|
|
217
|
+
- [cli-base `TESTING.md`](https://github.com/WireCatLabs/cli-base/blob/main/docs/dev/TESTING.md)
|
|
218
|
+
- [cli-core `TESTING.md`](https://github.com/WireCatLabs/cli-core/blob/main/docs/dev/TESTING.md)
|
|
219
|
+
- [max-cli `TESTING.md`](https://github.com/WireCatLabs/max-cli/blob/main/docs/dev/TESTING.md)
|
|
220
|
+
- [cli-testing contracts guide](https://github.com/WireCatLabs/cli-testing/blob/main/docs/ci/CONTRACTS.md) and
|
|
221
|
+
[upgrade guide](https://github.com/WireCatLabs/cli-testing/blob/main/docs/ci/UPGRADES.md)
|
|
222
|
+
- [cli-testing CI docs](https://github.com/WireCatLabs/cli-testing/tree/main/docs/ci)
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Toolchain
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
How a repository is built and checked before review: the shared presets and `standards:check`, strict TypeScript,
|
|
6
|
+
the shared Biome preset and its grit plugins, the file size cap, import cycles, layer boundaries as lint, the command
|
|
7
|
+
lint, spelling and Markdown lint.
|
|
8
|
+
|
|
9
|
+
Rule ids on this page are `WC-TOOL-<n>`. How to read a rule, how ids work and which rule wins are in the
|
|
10
|
+
[index](README.md). What runs on which trigger is on the [CI page](ci.md).
|
|
11
|
+
|
|
12
|
+
The [community standards](https://github.com/WireCatLabs/community/blob/main/standards/README.md) repository is the
|
|
13
|
+
one source of the presets. Each repository holds a copy of them in `config/wirecat/`, installed by
|
|
14
|
+
`adopt-standards.py`.
|
|
15
|
+
|
|
16
|
+
"The ten repositories" on this page means the six CLIs (tg, max, memo, drive, zoom, wa), cli-base, cli-core,
|
|
17
|
+
cli-testing, cli-docs, plus community itself.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
|
|
21
|
+
### WC-TOOL-1 · Install the shared presets with `adopt-standards.py`, and never edit the copies
|
|
22
|
+
|
|
23
|
+
- **Why:** one reviewed set of presets keeps ten repositories alike; an edited copy drifts without anyone seeing it.
|
|
24
|
+
- **Enforced by:** `pnpm standards:check` · `standards.yml:standards`.
|
|
25
|
+
- **Example:** `python3 scripts/adopt-standards.py /path/to/project` from a community checkout, then commit
|
|
26
|
+
`config/wirecat/` and the lockfile. `standards:check` compares each file in `config/wirecat/` with the hash in
|
|
27
|
+
`config/wirecat/manifest.json`.
|
|
28
|
+
- **Exceptions:** none. A general improvement goes to community and comes back through a new adoption. A
|
|
29
|
+
project-only setting goes in the root config (WC-TOOL-2).
|
|
30
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
31
|
+
|
|
32
|
+
### WC-TOOL-2 · Make each root config extend its copy in `config/wirecat/`
|
|
33
|
+
|
|
34
|
+
- **Why:** a root config that does not extend the preset runs none of the shared rules, and nothing else would say so.
|
|
35
|
+
- **Enforced by:** `pnpm standards:check` · `standards.yml:standards`.
|
|
36
|
+
- **Example:** `biome.json` has `"extends": ["./config/wirecat/biome.base.json"]`. `cspell.json` imports
|
|
37
|
+
`./config/wirecat/cspell.json`. `.markdownlint-cli2.jsonc` extends `./config/wirecat/markdownlint.json`.
|
|
38
|
+
`lefthook.yml` extends `config/wirecat/lefthook.yml`.
|
|
39
|
+
- **Exceptions:** do not extend `@wirecat/cli-base/biome` or `@wirecat/cli-base/lefthook.yml`. No repository uses
|
|
40
|
+
them, and `standards:check` accepts only the paths above.
|
|
41
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
42
|
+
|
|
43
|
+
### WC-TOOL-3 · Pin the tool versions that `toolchain.json` names
|
|
44
|
+
|
|
45
|
+
- **Why:** two Biome versions give two verdicts on the same file.
|
|
46
|
+
- **Enforced by:** `pnpm standards:check` · `standards.yml:standards`.
|
|
47
|
+
- **Example:** `package.json` has `"packageManager": "pnpm@11.20.0"` and exact `devDependencies` for
|
|
48
|
+
`@biomejs/biome`, `cspell` and its three dictionaries, `lefthook` and `markdownlint-cli2`, as in the manifest.
|
|
49
|
+
- **Exceptions:** none.
|
|
50
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
51
|
+
|
|
52
|
+
### WC-TOOL-4 · Extend the shared TypeScript config, and do not loosen it
|
|
53
|
+
|
|
54
|
+
- **Why:** strict options catch at build time what would otherwise fail on a user's machine.
|
|
55
|
+
- **Enforced by:** review only.
|
|
56
|
+
- **Example:** `tsconfig.json` has `"extends": "@wirecat/cli-base/tsconfig.base.json"` and adds only `rootDir`,
|
|
57
|
+
`outDir`, `include` and `exclude`. The base turns on `strict`, `noUncheckedIndexedAccess`, `noImplicitOverride`,
|
|
58
|
+
`noFallthroughCasesInSwitch`, `verbatimModuleSyntax` and `isolatedModules`.
|
|
59
|
+
- **Exceptions:** cli-docs is a Next.js site with its own config. cli-testing reaches the same file through
|
|
60
|
+
`./node_modules/@wirecat/cli-base/config/tsconfig.base.json`. A repository may add stricter options.
|
|
61
|
+
- **Applies to:** the CLIs, cli-core, cli-base and cli-testing. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
62
|
+
|
|
63
|
+
### WC-TOOL-5 · Typecheck every TypeScript file: source, tests and scripts
|
|
64
|
+
|
|
65
|
+
- **Why:** a folder that no `tsconfig` covers breaks without a sign, and a test that compares against a constant that
|
|
66
|
+
does not exist passes for any input while CI stays green.
|
|
67
|
+
- **Enforced by:** `pnpm typecheck` · `pnpm ci:quick` · `node-ci.yml:check`.
|
|
68
|
+
- **Example:** `tsconfig.test.json` extends `@wirecat/cli-base/tsconfig.test.json`, covers all of `src/`, tests
|
|
69
|
+
included, checks them with `noEmit` and carries `"exclude": []`. Without that line it inherits the build's
|
|
70
|
+
`exclude`, checks no test file and still passes. `tsconfig.scripts.json` extends
|
|
71
|
+
`@wirecat/cli-base/tsconfig.scripts.json` and covers `scripts/`. The `typecheck` script runs all three projects.
|
|
72
|
+
- **Exceptions:** a new folder of TypeScript goes into one of these projects in the same pull request. memo has no
|
|
73
|
+
`tsconfig.scripts.json` yet.
|
|
74
|
+
- **Applies to:** the CLIs, cli-core, cli-base and cli-testing. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
75
|
+
|
|
76
|
+
### WC-TOOL-6 · Support Node 22 and later, and Bun, and run the built exports under Bun
|
|
77
|
+
|
|
78
|
+
- **Why:** users install the CLIs with either runtime, and a static import of one runtime's module fails to load on
|
|
79
|
+
the other.
|
|
80
|
+
- **Enforced by:** `pnpm smoke:bun` · `node-ci.yml:bun`.
|
|
81
|
+
- **Example:** `"engines": { "node": ">=22" }` in `package.json`. Full validation runs on Node 24. `bun test` cannot
|
|
82
|
+
run the vitest suite, so `scripts/smoke.ts` runs the built exports with plain assertions, and the Bun job runs it
|
|
83
|
+
(`pnpm build && pnpm smoke:bun`). A new entry point gets a line there. Node 22 runs in the Windows install matrix of
|
|
84
|
+
tg, max and wa, in zoom's full validation and in cli-core's old-Node job.
|
|
85
|
+
- **Exceptions:** cli-docs and community publish no runtime package. memo, drive and cli-base do not run Node 22 in
|
|
86
|
+
any workflow yet. memo has no Bun smoke test yet.
|
|
87
|
+
- **Applies to:** the CLIs, cli-core and cli-base. **Since:** cli-base 0.41.0. **Rulings:** NEED-11.
|
|
88
|
+
|
|
89
|
+
### WC-TOOL-7 · Let Biome format the code, and do not format by hand
|
|
90
|
+
|
|
91
|
+
- **Why:** one formatter ends every argument about layout, and review reads only the change.
|
|
92
|
+
- **Enforced by:** `pnpm lint` · `standards.yml:standards`.
|
|
93
|
+
- **Example:** the shared preset sets 2 spaces, double quotes, semicolons only where needed, trailing commas, arrow
|
|
94
|
+
parentheses always and 120 columns. Run `pnpm lint:fix` to apply them.
|
|
95
|
+
- **Exceptions:** none.
|
|
96
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
97
|
+
|
|
98
|
+
### WC-TOOL-8 · Keep the shared Biome rules at error
|
|
99
|
+
|
|
100
|
+
- **Why:** each of these rules catches a real class of bug, and a warning gets ignored.
|
|
101
|
+
- **Enforced by:** `pnpm lint` · `standards.yml:standards`.
|
|
102
|
+
- **Example:** the preset turns on Biome's recommended rules and adds, as errors: useConst, noNonNullAssertion,
|
|
103
|
+
noUnusedImports, noUnusedVariables and noExplicitAny.
|
|
104
|
+
- **Exceptions:** a repository may add rules or raise a level. It may not turn a shared rule off (index, "Which rule
|
|
105
|
+
wins").
|
|
106
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
107
|
+
|
|
108
|
+
### WC-TOOL-9 · Write to the console only with `console.error`, except in `scripts/`
|
|
109
|
+
|
|
110
|
+
- **Why:** stdout carries data only, so a stray `console.log` breaks every caller that parses it.
|
|
111
|
+
- **Enforced by:** `pnpm lint` · `standards.yml:standards`.
|
|
112
|
+
- **Example:** the preset sets noConsole to error and allows `error`. Command output goes through the renderer and the
|
|
113
|
+
streams of cli-base.
|
|
114
|
+
- **Exceptions:** files under `scripts/` may print, because they are development tools. A shared package prints
|
|
115
|
+
nothing at all, not even with `console.error`
|
|
116
|
+
([WC-ARCH-19](architecture.md#wc-arch-19--shared-packages-print-nothing-and-log-nothing-on-their-own)).
|
|
117
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
118
|
+
|
|
119
|
+
### WC-TOOL-10 · Keep the secret lint on, and suppress a finding only with its reason
|
|
120
|
+
|
|
121
|
+
- **Why:** a token caught at commit time never reaches the history; gitleaks is the second net.
|
|
122
|
+
- **Enforced by:** `pnpm lint` · `standards.yml:standards`.
|
|
123
|
+
- **Example:** noSecrets runs at error with an entropy threshold of 50. A reviewed site reads
|
|
124
|
+
`// biome-ignore lint/security/noSecrets: Crockford base32 alphabet, not a key`.
|
|
125
|
+
- **Exceptions:** the rule is off in test files, `test/`, `tests/`, `__tests__/`, `fixtures/` and `generated/`,
|
|
126
|
+
because those hold fake credentials or cannot keep a suppression comment.
|
|
127
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
128
|
+
|
|
129
|
+
### WC-TOOL-11 · Keep the three grit plugins that block unsafe calls
|
|
130
|
+
|
|
131
|
+
- **Why:** a shell or an evaluated string built from input is how a command line tool runs an attacker's code.
|
|
132
|
+
- **Enforced by:** `pnpm lint` · `standards.yml:standards`.
|
|
133
|
+
- **Example:** these plugins report at error. no-shell-true reports `shell: true` in `spawn`, `exec`, `execFile` or
|
|
134
|
+
`fork` and their `Sync` forms. no-exec-interpolation reports `exec` or `execSync` with a template literal or a `+`
|
|
135
|
+
concatenation. no-new-function reports `new Function(...)` and `Function(...)`.
|
|
136
|
+
- **Exceptions:** a reviewed site may keep a `biome-ignore` comment with the reason, for example a Windows `.cmd` shim
|
|
137
|
+
with fixed arguments. The plugins read syntax, not data flow, so review and CodeQL at release cover the rest.
|
|
138
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
139
|
+
|
|
140
|
+
### WC-TOOL-12 · Do not spread a list of user data into call arguments
|
|
141
|
+
|
|
142
|
+
- **Why:** V8 throws at about 125,000 arguments, so `push(...items)` fails on a large mailbox or chat.
|
|
143
|
+
- **Enforced by:** `pnpm lint` · `standards.yml:standards`.
|
|
144
|
+
- **Example:** write `for (const item of items) out.push(item)`, not `out.push(...items)`. The no-unbounded-spread
|
|
145
|
+
plugin reports `.push(...x)`, `Math.max(...x)` and `Math.min(...x)` as a warning.
|
|
146
|
+
- **Exceptions:** a spread over a list that is small by construction may stay. The plugin skips tests, `testing/`,
|
|
147
|
+
`scripts/`, `bench/` and `performance/`.
|
|
148
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
149
|
+
|
|
150
|
+
### WC-TOOL-13 · Cap every file at 1,000 lines with Biome
|
|
151
|
+
|
|
152
|
+
- **Why:** a file past 1,000 lines always holds more than one job; the cap stops it before review has to.
|
|
153
|
+
- **Enforced by:** `<app>: biome noExcessiveLinesPerFile` · `cli-core: biome noExcessiveLinesPerFile`.
|
|
154
|
+
- **Example:** `biome.json` sets the style rule noExcessiveLinesPerFile to error with `"maxLines": 1000`, and turns it
|
|
155
|
+
off for `**/*.test.ts`, `test/**` and `**/generated/**`. Below the cap, the review signals at 300 and 500 lines are
|
|
156
|
+
in [WC-LAY-7](layout.md#wc-lay-7--treat-300-and-500-lines-as-review-signals).
|
|
157
|
+
- **Exceptions:** a file that is one cohesive unit may get its own override, listed by path in `biome.json` (tg
|
|
158
|
+
`src/telegram/adapter.ts`; four files in cli-core). A smaller cap is allowed: zoom uses 500. cli-base, cli-testing,
|
|
159
|
+
cli-docs and community have no cap yet.
|
|
160
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
161
|
+
|
|
162
|
+
### WC-TOOL-14 · Turn on the import cycle rule
|
|
163
|
+
|
|
164
|
+
- **Why:** a cycle makes load order decide which value a module sees, and the failure shows only at run time.
|
|
165
|
+
- **Enforced by:** `<app>: biome noImportCycles` · `cli-core: biome noImportCycles`.
|
|
166
|
+
- **Example:** `biome.json` sets the suspicious rule noImportCycles to error.
|
|
167
|
+
- **Exceptions:** cli-base, cli-testing, cli-docs and community do not have it yet.
|
|
168
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
169
|
+
|
|
170
|
+
### WC-TOOL-15 · Declare layer boundaries as restricted imports in `biome.json`
|
|
171
|
+
|
|
172
|
+
- **Why:** a boundary that only a document states is crossed in the first busy week.
|
|
173
|
+
- **Enforced by:** `<app>: biome noRestrictedImports` · `cli-testing: biome noRestrictedImports`.
|
|
174
|
+
- **Example:** an override with `"includes": ["src/commands/**"]` sets the style rule noRestrictedImports with the
|
|
175
|
+
folders that layer may not import, and a `message` that says why, such as "commands speak the domain model; only
|
|
176
|
+
`src/client.ts` may reach the protocol". Which layers exist and which way they depend is on the
|
|
177
|
+
[Architecture page](architecture.md).
|
|
178
|
+
- **Exceptions:** cli-base and cli-docs have no layer overrides. cli-core has them, but its last override replaces
|
|
179
|
+
the earlier ones today, so they catch nothing until it is fixed.
|
|
180
|
+
- **Applies to:** the CLIs, cli-core and cli-testing. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
181
|
+
|
|
182
|
+
### WC-TOOL-16 · Run the command lint on the built CLI, and let its baseline only shrink
|
|
183
|
+
|
|
184
|
+
- **Why:** the command tree is what users and agents see; the lint holds it to the shared vocabulary on every pull
|
|
185
|
+
request.
|
|
186
|
+
- **Enforced by:** `<app>: pnpm lint:commands`.
|
|
187
|
+
- **Example:** `"lint:commands": "cli-dev lint --cli dist/bin/max.js"`, run by `ci:quick` after the build. Known
|
|
188
|
+
violations live in `lint/baseline/<rule-id>.json`; an entry with no violation left fails the run. A permanent
|
|
189
|
+
exception goes in `lint/overrides.json` with `rule`, `target`, `reason`, `owner` and `review_after`. More than 10
|
|
190
|
+
overrides fail the run, and so does one past its date. The rules themselves are on the
|
|
191
|
+
[Commands page](commands.md).
|
|
192
|
+
- **Exceptions:** zoom runs `lint:commands` in full validation only. cli-core runs its own command lint test in
|
|
193
|
+
`ci:quick`. cli-base, cli-testing, cli-docs and community have no command tree.
|
|
194
|
+
- **Applies to:** the CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
195
|
+
|
|
196
|
+
### WC-TOOL-17 · Spell-check prose with the shared `cspell` config
|
|
197
|
+
|
|
198
|
+
- **Why:** a typo in a page or a help text is the first thing a reader sees.
|
|
199
|
+
- **Enforced by:** `pnpm docs:spell`.
|
|
200
|
+
- **Example:** `cspell.json` imports `./config/wirecat/cspell.json` (English, British English, Russian, Spanish and the
|
|
201
|
+
WireCat word list) and adds only the project's own words. Code blocks and inline code are not checked.
|
|
202
|
+
- **Exceptions:** a general word goes into the community word list, not into each project. In tg, max, wa, zoom and
|
|
203
|
+
cli-testing, `cspell` also runs inside `docs:check` in full validation.
|
|
204
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
205
|
+
|
|
206
|
+
### WC-TOOL-18 · Lint Markdown with `markdownlint-cli2` and the shared preset
|
|
207
|
+
|
|
208
|
+
- **Why:** a code block with no language or an empty link breaks the docs site and agent readers alike.
|
|
209
|
+
- **Enforced by:** `pnpm docs:lint` · `standards.yml:standards`.
|
|
210
|
+
- **Example:** the preset turns on only: no tabs (MD010), at most two blank lines in a row (MD012), a language on
|
|
211
|
+
every fenced code block (MD040) and no empty links (MD042). `.markdownlint-cli2.jsonc` lists the files to check.
|
|
212
|
+
- **Exceptions:** a repository may turn on more rules in its root config.
|
|
213
|
+
- **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
214
|
+
|
|
215
|
+
### WC-TOOL-19 · Check user pages with `rumdl` and the shared `rumdl.toml`
|
|
216
|
+
|
|
217
|
+
- **Why:** user pages feed the docs site, so their Markdown form is checked more closely than developer notes.
|
|
218
|
+
- **Enforced by:** `tg-cli: pnpm docs:check` · `max-cli: pnpm docs:check` · `whatsapp-cli: pnpm docs:check` ·
|
|
219
|
+
`zoom-cli: pnpm docs:check` · `cli-testing: pnpm docs:check`.
|
|
220
|
+
- **Example:** `rumdl check --config config/wirecat/rumdl.toml README.md docs/*.md`, inside `docs:check`. The preset
|
|
221
|
+
turns off line length (MD013), first-line heading (MD041) and relative links (MD057), because other checks cover
|
|
222
|
+
them.
|
|
223
|
+
- **Exceptions:** memo, drive, cli-base and cli-core do not run `rumdl` yet.
|
|
224
|
+
- **Applies to:** the CLIs and cli-testing. **Since:** cli-base 0.41.0. **Rulings:** none.
|
|
225
|
+
|
|
226
|
+
## Sources
|
|
227
|
+
|
|
228
|
+
These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
|
|
229
|
+
holds.
|
|
230
|
+
|
|
231
|
+
- [community standards](https://github.com/WireCatLabs/community/blob/main/standards/README.md)
|
|
232
|
+
- [cli-base `TOOLING.md`](https://github.com/WireCatLabs/cli-base/blob/main/docs/TOOLING.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirecat/cli-base",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.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",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
18
|
"config",
|
|
19
|
+
"docs/standards",
|
|
19
20
|
"README.md",
|
|
20
21
|
"LICENSE",
|
|
21
22
|
"THIRD_PARTY_NOTICES"
|
|
@@ -88,7 +89,7 @@
|
|
|
88
89
|
"typecheck": "tsc --build --force --emitDeclarationOnly && tsc -p tsconfig.test.json && tsc -p tsconfig.scripts.json",
|
|
89
90
|
"lint": "biome check .",
|
|
90
91
|
"lint:fix": "biome check --write .",
|
|
91
|
-
"docs:check": "pnpm build && node dist/dev/bin.js docs-check --ids CLI,MAX,OPS,CORE,SPEC,DOC",
|
|
92
|
+
"docs:check": "pnpm build && node dist/dev/bin.js docs-check --ids CLI,MAX,OPS,CORE,SPEC,DOC && node scripts/standards-ids.ts",
|
|
92
93
|
"test": "vitest run",
|
|
93
94
|
"test:watch": "vitest",
|
|
94
95
|
"test:coverage": "vitest run --coverage",
|
|
@@ -99,7 +100,7 @@
|
|
|
99
100
|
"prepublishOnly": "pnpm build",
|
|
100
101
|
"standards:check": "node config/wirecat/check.mjs",
|
|
101
102
|
"docs:lint": "markdownlint-cli2",
|
|
102
|
-
"docs:spell": "cspell lint --config cspell.json --no-progress README.md",
|
|
103
|
+
"docs:spell": "cspell lint --config cspell.json --no-progress README.md \"docs/standards/**/*.md\"",
|
|
103
104
|
"ci:quick": "pnpm typecheck"
|
|
104
105
|
},
|
|
105
106
|
"dependencies": {
|