@monochange/skill 0.0.0 → 0.4.2

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.
@@ -0,0 +1,539 @@
1
+ # Linting skill
2
+
3
+ <!-- {=lintingPolicyReference} -->
4
+
5
+ Use this guide when the task is to configure or explain monochange's **manifest lint rules**.
6
+
7
+ These are the rules that run through **`mc check`** and are configured in `monochange.toml` under the top-level **`[lints]`** section.
8
+
9
+ They are separate from Rust compiler or Clippy lints used to develop monochange itself.
10
+
11
+ ## What `mc check` does
12
+
13
+ `mc check` runs two phases:
14
+
15
+ 1. normal workspace validation, similar to `mc validate`
16
+ 2. manifest lint rules for supported package ecosystems
17
+
18
+ Common commands:
19
+
20
+ ```bash
21
+ mc check
22
+ mc check --fix
23
+ mc check --format json
24
+ mc lint list
25
+ mc lint explain cargo/recommended
26
+ ```
27
+
28
+ Use `--fix` when you want monochange to apply auto-fixes where a rule supports them.
29
+
30
+ ## Where lint rules live
31
+
32
+ Configure presets, global rules, and scoped overrides in the top-level `[lints]` section of `monochange.toml`:
33
+
34
+ ```toml
35
+ [lints]
36
+ use = ["cargo/recommended", "npm/recommended", "dart/recommended"]
37
+
38
+ [lints.rules]
39
+ "cargo/internal-dependency-workspace" = "error"
40
+ "npm/workspace-protocol" = "error"
41
+ "dart/sdk-constraint-modern" = { level = "warning", minimum = "3.6.0", require_upper_bound = false }
42
+ "dart/no-unexpected-dependency-overrides" = { level = "warning", allow_for_private = true, allow_packages = ["app_shell"] }
43
+
44
+ [[lints.scopes]]
45
+ name = "published cargo packages"
46
+ match = { ecosystems = ["cargo"], managed = true, publishable = true }
47
+ rules = { "cargo/required-package-fields" = "error" }
48
+ ```
49
+
50
+ Rule configuration supports two forms:
51
+
52
+ - simple severity: `"rule-id" = "error"`, `"warning"`, or `"off"`
53
+ - detailed config: `{ level = "error", ...rule_specific_options }`
54
+
55
+ ## Changeset lint rules
56
+
57
+ Changeset lint rules use the same `[lints.rules]` table as manifest rules. They are evaluated while markdown changesets are loaded by validation and release workflows.
58
+
59
+ ```toml
60
+ [lints.rules]
61
+ "changesets/duplicate" = "error"
62
+ "changesets/no_section_headings" = "error"
63
+ "changesets/summary" = { level = "error", required = true, heading_level = 2, min_length = 12, max_length = 80, forbid_trailing_period = true, forbid_conventional_commit_prefix = true }
64
+ "changesets/bump/major" = { level = "error", required_sections = ["Impact", "Migration"], min_body_chars = 120, require_code_block = true }
65
+ "changesets/types/breaking" = { level = "error", forbidden_headings = ["Breaking", "Breaking changes"], required_sections = ["Impact", "Migration"], required_bump = "major" }
66
+ ```
67
+
68
+ Supported changeset rule ids:
69
+
70
+ - `changesets/duplicate` — validates that a changeset does not target the same effective package more than once.
71
+ - `changesets/no_section_headings` — rejects headings that duplicate a change type used by that changeset.
72
+ - `changesets/summary` — configures the one-line summary heading. Options: `required`, `heading_level`, `min_length`, `max_length`, `forbid_trailing_period`, `forbid_conventional_commit_prefix`.
73
+ - `changesets/bump/<severity>` — configures rules for `major`, `minor`, or `patch` entries. Options: `required_sections`, `forbidden_headings`, `min_body_chars`, `max_body_chars`, `require_code_block`, `required_bump`.
74
+ - `changesets/types/<type>` — configures rules for a configured changelog type such as `breaking`, `feature`, `fix`, `security`, or a custom type like `unicorns`. It accepts the same scoped options as bump rules. The `<type>` segment must match a configured changelog type.
75
+
76
+ ## Current rule coverage
77
+
78
+ Today, built-in manifest lint rules exist for:
79
+
80
+ - **Cargo** manifests (`Cargo.toml`)
81
+ - **npm-family** manifests (`package.json`)
82
+ - **Dart / Flutter** manifests (`pubspec.yaml`)
83
+
84
+ Lint suites still live in ecosystem crates, but monochange routes all manifest lint configuration through the top-level `[lints]` section via preset selection, rule overrides, and scoped matches.
85
+
86
+ ## Cargo manifest lint rules
87
+
88
+ ### `cargo/dependency-field-order`
89
+
90
+ **Why:** keeps inline dependency tables visually consistent.
91
+
92
+ **What it checks:** preferred key order inside dependency tables:
93
+
94
+ 1. `workspace` or `version`
95
+ 2. `default-features` / `default_features`
96
+ 3. `features`
97
+ 4. other keys like `optional`, `path`, `registry`, `package`, `git`, `branch`, `tag`, `rev`
98
+
99
+ **Without the rule:**
100
+
101
+ ```toml
102
+ serde = { features = ["derive"], workspace = true }
103
+ ```
104
+
105
+ **With the rule:**
106
+
107
+ ```toml
108
+ serde = { workspace = true, features = ["derive"] }
109
+ ```
110
+
111
+ **Useful option:**
112
+
113
+ - `fix` — defaults to `true`
114
+
115
+ ### `cargo/internal-dependency-workspace`
116
+
117
+ **Why:** internal workspace dependencies should usually be declared through the workspace rather than carrying their own explicit version strings.
118
+
119
+ **Without the rule:**
120
+
121
+ ```toml
122
+ [dependencies]
123
+ monochange_core = { path = "../monochange_core", version = "0.1.0" }
124
+ ```
125
+
126
+ **With the rule:**
127
+
128
+ ```toml
129
+ [dependencies]
130
+ monochange_core = { workspace = true }
131
+ ```
132
+
133
+ **When to use it:** when the repository wants one workspace-owned version source for internal crates.
134
+
135
+ **Useful options:**
136
+
137
+ - `require_workspace` — defaults to `true`
138
+ - `fix` — defaults to `true`
139
+
140
+ ### `cargo/required-package-fields`
141
+
142
+ **Why:** published crates should consistently carry the metadata your repository expects.
143
+
144
+ **Default required fields:**
145
+
146
+ - `description`
147
+ - `license`
148
+ - `repository`
149
+
150
+ **Without the rule:**
151
+
152
+ ```toml
153
+ [package]
154
+ name = "example"
155
+ version = "0.1.0"
156
+ ```
157
+
158
+ **With the rule:** monochange reports the missing fields so package metadata stays consistent.
159
+
160
+ **Useful option:**
161
+
162
+ - `fields` — replace the default required-field list
163
+
164
+ Example:
165
+
166
+ ```toml
167
+ [lints.rules]
168
+ "cargo/required-package-fields" = { level = "error", fields = ["description", "license"] }
169
+ ```
170
+
171
+ ### `cargo/sorted-dependencies`
172
+
173
+ **Why:** alphabetized dependency tables are easier to review and reduce noisy diffs.
174
+
175
+ **Without the rule:**
176
+
177
+ ```toml
178
+ [dependencies]
179
+ zzzz = "1.0"
180
+ aaaa = "1.0"
181
+ mmmm = "1.0"
182
+ ```
183
+
184
+ **With the rule:**
185
+
186
+ ```toml
187
+ [dependencies]
188
+ aaaa = "1.0"
189
+ mmmm = "1.0"
190
+ zzzz = "1.0"
191
+ ```
192
+
193
+ **Useful option:**
194
+
195
+ - `fix` — defaults to `true`
196
+
197
+ ### `cargo/unlisted-package-private`
198
+
199
+ **Why:** a Cargo package that is not listed in `monochange.toml` should not be accidentally publishable.
200
+
201
+ **Without the rule:** an unmanaged crate can remain publicly publishable by accident.
202
+
203
+ **With the rule:** monochange requires either:
204
+
205
+ - adding the package to `monochange.toml`, or
206
+ - marking it private with `publish = false`
207
+
208
+ **Without the rule:**
209
+
210
+ ```toml
211
+ [package]
212
+ name = "experimental-crate"
213
+ version = "0.1.0"
214
+ ```
215
+
216
+ **With the rule:**
217
+
218
+ ```toml
219
+ [package]
220
+ name = "experimental-crate"
221
+ version = "0.1.0"
222
+ publish = false
223
+ ```
224
+
225
+ **Useful option:**
226
+
227
+ - `fix` — defaults to `true`
228
+
229
+ ## npm-family manifest lint rules
230
+
231
+ ### `npm/workspace-protocol`
232
+
233
+ **Why:** internal workspace dependencies should use the `workspace:` protocol so local workspace intent is explicit.
234
+
235
+ **Without the rule:**
236
+
237
+ ```json
238
+ {
239
+ "dependencies": {
240
+ "@acme/shared": "^1.2.0"
241
+ }
242
+ }
243
+ ```
244
+
245
+ **With the rule:**
246
+
247
+ ```json
248
+ {
249
+ "dependencies": {
250
+ "@acme/shared": "workspace:*"
251
+ }
252
+ }
253
+ ```
254
+
255
+ **When to use it:** npm, pnpm, and Bun workspaces where internal packages should not drift to plain registry ranges.
256
+
257
+ **Useful options:**
258
+
259
+ - `require_for_private` — defaults to `false`
260
+ - `fix` — defaults to `true`
261
+
262
+ ### `npm/sorted-dependencies`
263
+
264
+ **Why:** alphabetized dependency sections reduce review noise and make package diffs easier to scan.
265
+
266
+ **Without the rule:**
267
+
268
+ ```json
269
+ {
270
+ "dependencies": {
271
+ "zod": "^4.0.0",
272
+ "chalk": "^5.0.0"
273
+ }
274
+ }
275
+ ```
276
+
277
+ **With the rule:**
278
+
279
+ ```json
280
+ {
281
+ "dependencies": {
282
+ "chalk": "^5.0.0",
283
+ "zod": "^4.0.0"
284
+ }
285
+ }
286
+ ```
287
+
288
+ **Useful option:**
289
+
290
+ - `fix` — defaults to `true`
291
+
292
+ ### `npm/required-package-fields`
293
+
294
+ **Why:** package metadata should stay consistent across publishable npm packages.
295
+
296
+ **Default required fields:**
297
+
298
+ - `description`
299
+ - `repository`
300
+ - `license`
301
+
302
+ **Without the rule:**
303
+
304
+ ```json
305
+ {
306
+ "name": "@acme/app",
307
+ "version": "1.0.0"
308
+ }
309
+ ```
310
+
311
+ **With the rule:** monochange reports the missing metadata fields.
312
+
313
+ **Useful option:**
314
+
315
+ - `fields` — replace the default required-field list
316
+
317
+ ### `npm/root-no-prod-deps`
318
+
319
+ **Why:** the workspace root `package.json` is usually orchestration-only and should keep runtime dependencies out of the root package.
320
+
321
+ **Without the rule:**
322
+
323
+ ```json
324
+ {
325
+ "dependencies": {
326
+ "react": "^19.0.0"
327
+ }
328
+ }
329
+ ```
330
+
331
+ **With the rule:** move those to `devDependencies` when the root package is only a workspace manager.
332
+
333
+ **Useful option:**
334
+
335
+ - `fix` — defaults to `true`
336
+
337
+ ### `npm/no-duplicate-dependencies`
338
+
339
+ **Why:** the same dependency should not appear in multiple dependency sections unless the repository has a very deliberate reason.
340
+
341
+ **Without the rule:**
342
+
343
+ ```json
344
+ {
345
+ "dependencies": {
346
+ "typescript": "^5.0.0"
347
+ },
348
+ "devDependencies": {
349
+ "typescript": "^5.0.0"
350
+ }
351
+ }
352
+ ```
353
+
354
+ **With the rule:** monochange reports the duplicate and can suggest removing the redundant non-dev entry when appropriate.
355
+
356
+ **Useful option:**
357
+
358
+ - `fix` — defaults to `true`
359
+
360
+ ### `npm/unlisted-package-private`
361
+
362
+ **Why:** a package not declared in `monochange.toml` should not remain publishable by accident.
363
+
364
+ **Without the rule:** an unmanaged package can still look publishable.
365
+
366
+ **With the rule:** monochange requires either:
367
+
368
+ - adding the package to `monochange.toml`, or
369
+ - marking it private in `package.json`
370
+
371
+ **Without the rule:**
372
+
373
+ ```json
374
+ {
375
+ "name": "@acme/experimental",
376
+ "version": "0.1.0"
377
+ }
378
+ ```
379
+
380
+ **With the rule:**
381
+
382
+ ```json
383
+ {
384
+ "name": "@acme/experimental",
385
+ "private": true,
386
+ "version": "0.1.0"
387
+ }
388
+ ```
389
+
390
+ **Useful option:**
391
+
392
+ - `fix` — defaults to `true`
393
+
394
+ ## Dart manifest lint rules
395
+
396
+ ### `dart/sdk-constraint-present`
397
+
398
+ **Why:** every managed Dart package should declare the SDK range it expects rather than inheriting whatever the developer machine happens to provide.
399
+
400
+ **With the rule:** monochange reports any `pubspec.yaml` that omits `environment.sdk`.
401
+
402
+ ### `dart/sdk-constraint-modern`
403
+
404
+ **Why:** old or overly broad SDK ranges quietly expand your support policy and make releases harder to reason about.
405
+
406
+ **Default policy:**
407
+
408
+ - minimum lower bound: `3.0.0`
409
+ - upper bound required by default
410
+
411
+ **Useful options:**
412
+
413
+ - `minimum` — override the minimum lower bound for your workspace
414
+ - `require_upper_bound` — set to `false` if your policy intentionally omits an upper bound
415
+
416
+ Example:
417
+
418
+ ```toml
419
+ [lints.rules]
420
+ "dart/sdk-constraint-modern" = { level = "warning", minimum = "3.6.0", require_upper_bound = false }
421
+ ```
422
+
423
+ ### `dart/dependency-sorted`
424
+
425
+ **Why:** alphabetized `dependencies`, `dev_dependencies`, and `dependency_overrides` blocks reduce review noise and make Dart manifest diffs easier to scan.
426
+
427
+ **Useful option:**
428
+
429
+ - `fix` — defaults to `true`
430
+
431
+ ### `dart/no-unexpected-dependency-overrides`
432
+
433
+ **Why:** `dependency_overrides` are sometimes necessary, but they should usually be limited to private packages or a small allow list of explicitly approved packages.
434
+
435
+ **Useful options:**
436
+
437
+ - `allow_for_private` — defaults to `true`
438
+ - `allow_packages` — list package names that may keep `dependency_overrides`
439
+
440
+ Example:
441
+
442
+ ```toml
443
+ [lints.rules]
444
+ "dart/no-unexpected-dependency-overrides" = { level = "warning", allow_for_private = true, allow_packages = ["app_shell"] }
445
+ ```
446
+
447
+ ### Workspace-aware Dart rules
448
+
449
+ ### `dart/internal-path-dependency-policy`
450
+
451
+ **Why:** monorepos usually want one consistent policy for how internal Dart packages reference each other.
452
+
453
+ **Default policy:** strict mode expects internal packages to use `path:` references.
454
+
455
+ **Useful option:**
456
+
457
+ - `mode` — choose `"path"` or `"hosted"`
458
+
459
+ Example:
460
+
461
+ ```toml
462
+ [lints.rules]
463
+ "dart/internal-path-dependency-policy" = { level = "error", mode = "hosted" }
464
+ ```
465
+
466
+ ### `dart/workspace-internal-version-consistency`
467
+
468
+ **Why:** when workspace packages reference each other with hosted version ranges, those ranges should not drift away from the current workspace version.
469
+
470
+ **With the rule:** monochange compares internal dependency version references against the discovered workspace package version and reports mismatches.
471
+
472
+ ### Flutter-only rules
473
+
474
+ ### `dart/flutter-package-metadata-consistent`
475
+
476
+ **Why:** packages with a `flutter` section should declare the Flutter SDK dependency consistently so they are unmistakably Flutter packages.
477
+
478
+ **With the rule:** monochange requires `dependencies.flutter = { sdk = flutter }` in `pubspec.yaml` terms, expressed as the YAML mapping form.
479
+
480
+ ### `dart/assets-sorted`
481
+
482
+ **Why:** stable ordering for `flutter.assets` and `flutter.fonts` reduces noisy diffs in Flutter packages.
483
+
484
+ **Useful option:**
485
+
486
+ - `fix` — defaults to `true`
487
+
488
+ ### Dart presets
489
+
490
+ - `dart/recommended` enables metadata/publishability checks, `dart/sdk-constraint-present`, and `dart/dependency-sorted` as a warning.
491
+ - `dart/strict` adds `dart/sdk-constraint-modern`, `dart/no-unexpected-dependency-overrides`, `dart/internal-path-dependency-policy`, `dart/workspace-internal-version-consistency`, `dart/flutter-package-metadata-consistent`, and `dart/assets-sorted`, while promoting `dart/dependency-sorted` to an error.
492
+
493
+ Use `mc lint list` to inspect registered rules and presets, and `mc lint explain <id>` to understand a rule or preset before enabling it.
494
+
495
+ ## What `mc check` looks like in practice
496
+
497
+ Use plain text for local review:
498
+
499
+ ```bash
500
+ mc check
501
+ ```
502
+
503
+ Apply safe auto-fixes where possible:
504
+
505
+ ```bash
506
+ mc check --fix
507
+ ```
508
+
509
+ Use JSON for CI or MCP-style tooling:
510
+
511
+ ```bash
512
+ mc check --format json
513
+ ```
514
+
515
+ `mc check` fails when lint errors are present, so it is appropriate for CI gates.
516
+
517
+ ## Recommended workflow
518
+
519
+ For repository work:
520
+
521
+ ```bash
522
+ mc validate
523
+ mc check
524
+ mc release --dry-run --diff
525
+ ```
526
+
527
+ If you changed shared docs too:
528
+
529
+ ```bash
530
+ devenv shell docs:check
531
+ ```
532
+
533
+ <!-- {/lintingPolicyReference} -->
534
+
535
+ ## Related references
536
+
537
+ - [reference.md](./reference.md)
538
+ - [configuration.md](./configuration.md)
539
+ - [commands.md](./commands.md)