@williamthorsen/nmr 2.0.1 → 2.0.3

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.
Files changed (93) hide show
  1. package/.meta/changelog.json +107 -0
  2. package/.readyup/kits/default.js +41 -5
  3. package/.readyup/manifest.json +14 -9
  4. package/CHANGELOG.md +30 -0
  5. package/README.md +2 -8
  6. package/dist/esm/{check-cache-build-output.d.ts → check-cache/check-cache-build-output.d.ts} +1 -1
  7. package/dist/esm/{check-cache-build-output.js → check-cache/check-cache-build-output.js} +6 -6
  8. package/dist/esm/{check-cache-delegation.d.ts → check-cache/check-cache-delegation.d.ts} +3 -3
  9. package/dist/esm/{check-cache-delegation.js → check-cache/check-cache-delegation.js} +2 -2
  10. package/dist/esm/{check-cache-entries.js → check-cache/check-cache-entries.js} +1 -1
  11. package/dist/esm/{check-cache-gate.d.ts → check-cache/check-cache-gate.d.ts} +5 -4
  12. package/dist/esm/{check-cache-gate.js → check-cache/check-cache-gate.js} +10 -10
  13. package/dist/esm/{check-cache-key.d.ts → check-cache/check-cache-key.d.ts} +1 -1
  14. package/dist/esm/{check-cache-record.d.ts → check-cache/check-cache-record.d.ts} +6 -5
  15. package/dist/esm/{check-cache-record.js → check-cache/check-cache-record.js} +7 -6
  16. package/dist/esm/{check-cache.d.ts → check-cache/check-cache.d.ts} +10 -2
  17. package/dist/esm/{check-cache.js → check-cache/check-cache.js} +7 -4
  18. package/dist/esm/{config-check-cache.d.ts → check-cache/config-check-cache.d.ts} +1 -1
  19. package/dist/esm/{config-check-cache.js → check-cache/config-check-cache.js} +4 -4
  20. package/dist/esm/{pass-manifest.d.ts → check-cache/pass-manifest.d.ts} +1 -1
  21. package/dist/esm/{pass-manifest.js → check-cache/pass-manifest.js} +1 -1
  22. package/dist/esm/{recording.js → check-cache/recording.js} +2 -2
  23. package/dist/esm/{replay-assembly.d.ts → check-cache/replay-assembly.d.ts} +1 -1
  24. package/dist/esm/{replay-assembly.js → check-cache/replay-assembly.js} +2 -2
  25. package/dist/esm/child-env.d.ts +1 -1
  26. package/dist/esm/child-env.js +2 -2
  27. package/dist/esm/commands/actionlint.d.ts +2 -7
  28. package/dist/esm/commands/actionlint.js +5 -11
  29. package/dist/esm/commands/build-output.d.ts +2 -1
  30. package/dist/esm/commands/clean.js +1 -1
  31. package/dist/esm/commands/fmt-cache.js +3 -2
  32. package/dist/esm/commands/fmt.d.ts +6 -13
  33. package/dist/esm/commands/fmt.js +47 -30
  34. package/dist/esm/commands/node-pin.d.ts +15 -5
  35. package/dist/esm/commands/node-pin.js +43 -10
  36. package/dist/esm/commands/package-manifest.d.ts +28 -0
  37. package/dist/esm/commands/package-manifest.js +32 -0
  38. package/dist/esm/commands/run-vitest.js +21 -20
  39. package/dist/esm/commands/shellcheck.d.ts +2 -7
  40. package/dist/esm/commands/shellcheck.js +3 -11
  41. package/dist/esm/commands/spawn-inherited.d.ts +21 -0
  42. package/dist/esm/commands/spawn-inherited.js +11 -0
  43. package/dist/esm/commands/taze.d.ts +6 -6
  44. package/dist/esm/commands/taze.js +3 -7
  45. package/dist/esm/config-validation.js +1 -1
  46. package/dist/esm/config.js +3 -12
  47. package/dist/esm/{delegate-host.d.ts → delegation/delegate-host.d.ts} +3 -3
  48. package/dist/esm/{delegate-host.js → delegation/delegate-host.js} +9 -8
  49. package/dist/esm/{delegation-target.js → delegation/delegation-target.js} +1 -1
  50. package/dist/esm/{remote-probe.js → delegation/remote-probe.js} +2 -2
  51. package/dist/esm/{remote-run.js → delegation/remote-run.js} +5 -5
  52. package/dist/esm/{remote-session.js → delegation/remote-session.js} +1 -1
  53. package/dist/esm/{user-config.js → delegation/user-config.js} +4 -13
  54. package/dist/esm/env-switch.d.ts +25 -0
  55. package/dist/esm/env-switch.js +26 -0
  56. package/dist/esm/fan-out.d.ts +4 -1
  57. package/dist/esm/fan-out.js +1 -3
  58. package/dist/esm/help.js +1 -1
  59. package/dist/esm/helpers/filter-selection.d.ts +2 -0
  60. package/dist/esm/helpers/importConfigDefault.d.ts +7 -0
  61. package/dist/esm/helpers/importConfigDefault.js +45 -0
  62. package/dist/esm/invocation.d.ts +7 -3
  63. package/dist/esm/machine-lock.js +2 -1
  64. package/dist/esm/route.d.ts +6 -0
  65. package/dist/esm/route.js +15 -2
  66. package/dist/esm/run-chain.d.ts +1 -1
  67. package/dist/esm/run-chain.js +1 -1
  68. package/dist/esm/runCli.d.ts +9 -0
  69. package/dist/esm/runCli.js +24 -9
  70. package/dist/esm/runner.d.ts +2 -0
  71. package/dist/esm/runner.js +1 -1
  72. package/dist/esm/verdict.d.ts +1 -1
  73. package/docs/check-cache.md +7 -7
  74. package/docs/delegate.md +2 -2
  75. package/docs/machine-lock.md +4 -4
  76. package/docs/scripts.md +4 -0
  77. package/docs/upgrades.md +9 -1
  78. package/docs/utilities.md +4 -2
  79. package/package.json +2 -2
  80. /package/dist/esm/{check-cache-entries.d.ts → check-cache/check-cache-entries.d.ts} +0 -0
  81. /package/dist/esm/{check-cache-key.js → check-cache/check-cache-key.js} +0 -0
  82. /package/dist/esm/{recording.d.ts → check-cache/recording.d.ts} +0 -0
  83. /package/dist/esm/{delegation-target.d.ts → delegation/delegation-target.d.ts} +0 -0
  84. /package/dist/esm/{remote-host-session.d.ts → delegation/remote-host-session.d.ts} +0 -0
  85. /package/dist/esm/{remote-host-session.js → delegation/remote-host-session.js} +0 -0
  86. /package/dist/esm/{remote-probe-host.d.ts → delegation/remote-probe-host.d.ts} +0 -0
  87. /package/dist/esm/{remote-probe-host.js → delegation/remote-probe-host.js} +0 -0
  88. /package/dist/esm/{remote-probe.d.ts → delegation/remote-probe.d.ts} +0 -0
  89. /package/dist/esm/{remote-run.d.ts → delegation/remote-run.d.ts} +0 -0
  90. /package/dist/esm/{remote-session.d.ts → delegation/remote-session.d.ts} +0 -0
  91. /package/dist/esm/{remote-snapshot.d.ts → delegation/remote-snapshot.d.ts} +0 -0
  92. /package/dist/esm/{remote-snapshot.js → delegation/remote-snapshot.js} +0 -0
  93. /package/dist/esm/{user-config.d.ts → delegation/user-config.d.ts} +0 -0
@@ -2,25 +2,28 @@ import { reportError } from '@williamthorsen/nmr-core';
2
2
  import { runCli as runRouter } from '@williamthorsen/nmr-core/cli';
3
3
  import { prependBinDirs } from "./bin-path.js";
4
4
  import { NMR_BIN } from "./bins.js";
5
- import { NO_CACHE_ENV_VAR, resolveRunId, RUN_ID_ENV_VAR } from "./check-cache.js";
6
- import { openGate, runGated } from "./check-cache-gate.js";
7
- import { reportRecording } from "./check-cache-record.js";
5
+ import { GIT_TREE_READER, NO_CACHE_ENV_VAR, resolveRunId, RUN_ID_ENV_VAR, } from "./check-cache/check-cache.js";
6
+ import { openGate, runGated } from "./check-cache/check-cache-gate.js";
7
+ import { reportRecording } from "./check-cache/check-cache-record.js";
8
8
  import { addLockEnv, buildChildEnv, takeMachineLock } from "./child-env.js";
9
9
  import { resolveContext } from "./context.js";
10
10
  import { assertNoSelfReference } from "./crossing-diagnostics.js";
11
- import { resolveExecutionTarget, runInvocationOnHost } from "./delegate-host.js";
11
+ import { resolveExecutionTarget, runInvocationOnHost } from "./delegation/delegate-host.js";
12
+ import { DELEGATE_TO_FLAG } from "./delegation/remote-run.js";
12
13
  import { enterChain } from "./entry-chain.js";
14
+ import { isEnvSwitchOn } from "./env-switch.js";
13
15
  import { composeDelegation, runDelegation } from "./fan-out.js";
16
+ import { readFilterSelection as readFilterSelectionDefault, } from "./helpers/filter-selection.js";
14
17
  import { RUN_IF_PRESENT_ENV_VAR, USAGE_EXIT_CODE, VERSION, } from "./invocation.js";
15
18
  import { formatMisplacedFlagHint } from "./invocation-args.js";
16
19
  import { readInvocationFlags } from "./nmr-flags.js";
17
20
  import { reportVerdict } from "./presentation.js";
18
- import { DELEGATE_TO_FLAG } from "./remote-run.js";
19
21
  import { buildRootRegistry, buildWorkspaceRegistry, resolveScript } from "./resolver.js";
20
22
  import { buildRoot, buildVersionRoot } from "./route.js";
21
23
  import { assembleChain, formatOverrideNotice } from "./run-chain.js";
24
+ import { runSteps as runStepsDefault } from "./runner.js";
22
25
  export async function runCli(options) {
23
- const { args, cwd, env, stdout, stderr } = options;
26
+ const { args, cwd, env, readFilterSelection = readFilterSelectionDefault, readTree = GIT_TREE_READER, runSteps = runStepsDefault, stdout, stderr, } = options;
24
27
  const reading = readInvocationFlags(args);
25
28
  const firstPass = reading.ok ? reading.parsedArgs : undefined;
26
29
  const routerOptions = { name: NMR_BIN, context: undefined, stdout, stderr, baseDir: cwd, version: () => VERSION };
@@ -33,7 +36,10 @@ export async function runCli(options) {
33
36
  cwd,
34
37
  env,
35
38
  firstPass,
39
+ readFilterSelection,
40
+ readTree,
36
41
  runInvocation: (invocation) => runInvocation(invocation, options),
42
+ runSteps,
37
43
  stderr,
38
44
  stdout,
39
45
  });
@@ -74,10 +80,11 @@ async function planRun(invocation, target) {
74
80
  env,
75
81
  monorepoRoot: context.monorepoRoot,
76
82
  passthrough: parsedArgs.passthrough,
83
+ readTree: invocation.readTree,
77
84
  stderr,
78
85
  style: styles.stderr,
79
86
  });
80
- const shouldBypassCache = parsedArgs.shouldBypassCache || env[NO_CACHE_ENV_VAR] === '1';
87
+ const shouldBypassCache = parsedArgs.shouldBypassCache || isEnvSwitchOn(env, NO_CACHE_ENV_VAR);
81
88
  const runId = resolveRunId(env);
82
89
  const childEnv = buildChildEnv({
83
90
  env,
@@ -103,7 +110,15 @@ async function planRun(invocation, target) {
103
110
  let result;
104
111
  try {
105
112
  const heldDelegation = { ...delegation, env: addLockEnv(delegation.env, lock) };
106
- result = await runDelegation({ context, delegation: heldDelegation, parsedArgs, runOptions, stderr });
113
+ result = await runDelegation({
114
+ context,
115
+ delegation: heldDelegation,
116
+ parsedArgs,
117
+ readFilterSelection: invocation.readFilterSelection,
118
+ runOptions,
119
+ runSteps: invocation.runSteps,
120
+ stderr,
121
+ });
107
122
  }
108
123
  finally {
109
124
  await lock?.release();
@@ -123,7 +138,7 @@ async function planRun(invocation, target) {
123
138
  });
124
139
  const resolvedScript = resolveScript(command, registry, anchorDir, parsedArgs.isWorkspaceRoot);
125
140
  if (!resolvedScript) {
126
- if (env[RUN_IF_PRESENT_ENV_VAR] === '1') {
141
+ if (isEnvSwitchOn(env, RUN_IF_PRESENT_ENV_VAR)) {
127
142
  return { settled: true, result: { exitCode: 0 } };
128
143
  }
129
144
  const delegateToHint = parsedArgs.shouldDelegate && parsedArgs.delegateHosts === undefined
@@ -18,6 +18,8 @@ export interface RunStepsResult {
18
18
  /** The outcome that each foreground opaque step stated, absent unless a step that exited 0 stated one. */
19
19
  statedOutcomes?: Map<Step, StatedOutcome>;
20
20
  }
21
+ /** Runs a step list, as `runSteps` does: the form in which a caller receives it. */
22
+ export type RunSteps = typeof runSteps;
21
23
  /**
22
24
  * Runs a step list in order and resolves once one fails or all have run, implementing the `&&` semantics that
23
25
  * nmr promises: The first non-zero exit ends the sequence and is the code returned.
@@ -2,7 +2,7 @@ import { mkdtemp, rm } from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import process from 'node:process';
5
- import { writeDebugNote } from "./check-cache.js";
5
+ import { writeDebugNote } from "./check-cache/check-cache.js";
6
6
  import { describeSignalExitCode, startSpawned, } from "./child-process.js";
7
7
  import { createOutputRecorder } from "./helpers/createOutputRecorder.js";
8
8
  import { isTerminal, resolveChannel, resolveInheritedChannel } from "./output-channel.js";
@@ -1,6 +1,6 @@
1
1
  import type { Writable } from 'node:stream';
2
2
  import { type OutputStyle } from '@williamthorsen/nmr-core';
3
- import type { ReplayLine } from './check-cache-entries.js';
3
+ import type { ReplayLine } from './check-cache/check-cache-entries.js';
4
4
  import type { ReportFormat } from './report-format.js';
5
5
  import type { StatedOutcome } from './stated-outcome.js';
6
6
  /**
@@ -65,7 +65,7 @@ The gate never wrongly skips. When it cannot be sure, it does nothing and the co
65
65
  - When the repository does not have a pnpm install to fingerprint.
66
66
  - For any invocation carrying arguments after the command name, and for every step below it: the arguments narrow what runs, and a step served from a recorded pass is a step that did not.
67
67
 
68
- `NMR_DEBUG=1` reports why a run did not skip and why the cache did not apply.
68
+ `NMR_DEBUG=1` reports why a run did not skip and why the cache did not apply. [Environment switches](scripts.md#environment-switches) lists the values that `NMR_DEBUG` accepts.
69
69
 
70
70
  ## Delegated passes
71
71
 
@@ -154,12 +154,12 @@ $ nmr --log test
154
154
 
155
155
  Try these in order; the first is almost always the right one.
156
156
 
157
- | Step | Effect |
158
- | -------------------------------------- | ---------------------------------------------------------------------------- |
159
- | `nmr --no-cache <command>` | Runs the command, then records the fresh result. Applies to the whole chain. |
160
- | `NMR_NO_CACHE=1` | The same, for every nmr invocation in the shell. |
161
- | `rm -rf node_modules/.cache/nmr-check` | Forgets every recorded pass, leaving build output alone. |
162
- | `nmr clean` | Forgets every recorded pass and removes build output, at any scope. |
157
+ | Step | Effect |
158
+ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
159
+ | `nmr --no-cache <command>` | Runs the command, then records the fresh result. Applies to the whole chain. |
160
+ | `NMR_NO_CACHE=1` | The same, for every nmr invocation in the shell. [Environment switches](scripts.md#environment-switches) lists the values that it accepts. |
161
+ | `rm -rf node_modules/.cache/nmr-check` | Forgets every recorded pass, leaving build output alone. |
162
+ | `nmr clean` | Forgets every recorded pass and removes build output, at any scope. |
163
163
 
164
164
  `--no-cache` and `NMR_NO_CACHE=1` also bypass the Prettier cache that `nmr-fmt` keeps, because nmr exports `NMR_NO_CACHE=1` to the commands that it runs. nmr exports it too when a command is given trailing arguments, so `nmr fmt:check <pathspec>` runs uncached. See [`nmr-fmt`'s cache](utilities.md#cache).
165
165
 
package/docs/delegate.md CHANGED
@@ -55,7 +55,7 @@ The first rule that applies decides where a command runs:
55
55
  - **A step and a `-F` or `-R` child run where their parent runs.** nmr gives every process that it starts an empty `NMR_DELEGATE`, which rule 6 reads as "here"; the run on a host already passes `--no-delegate`, so a host does not apply its own user config. A git hook that an agent's command starts is an agent run.
56
56
  - **A repo whose checks must run on the machine that has the tree** declares `delegate: false` in `.config/nmr.config.ts`, the only value that the repo config accepts for the key. It outranks `NMR_DELEGATE` and the user config, but not a flag.
57
57
  - **A command in a package install hook runs here unless a flag asks otherwise.** During `pnpm add`, a hook such as `postinstall` sees a manifest that its lockfile does not match yet, and the host's frozen install of that tree fails. A command in any other `package.json` script, such as `test`, delegates as usual.
58
- - **`NMR_DEBUG=1` names what sent a command to a host**, such as `delegating ci per ~/.config/nmr/config.ts (when: agent)`, `per NMR_DELEGATE`, or `per --delegate-to`.
58
+ - **`NMR_DEBUG=1` names what sent a command to a host**, such as `delegating ci per ~/.config/nmr/config.ts (when: agent)`, `per NMR_DELEGATE`, or `per --delegate-to`. [Environment switches](scripts.md#environment-switches) lists the values that `NMR_DEBUG` accepts.
59
59
 
60
60
  ### Choosing among several hosts
61
61
 
@@ -92,7 +92,7 @@ $ nmr --delegate-to imac2 ci
92
92
  - **A pass earned on a host is recorded here** with that host, and a later delegation whose list includes that host recalls it as `passed 4m ago on imac2`, without asking any host whether it is free. A run here, or a delegation to other hosts, does not recall it. `nmr --log <command>` prints the output that the host sent back, under a header that names the host.
93
93
  - **A delegated composite records its constituents' passes too**, as the host reports them, so `nmr --delegate-to imac2 check` after `nmr --delegate-to imac2 ci` recalls without contacting the host, and a recall of `ci` replays its constituents' excerpts. A composite that the host itself recalled records only its own pass, and a `-F` or `-R` delegation does not record any pass; [delegated passes](check-cache.md#delegated-passes) has the rules.
94
94
  - **Only a miss reaches the host**, and it does not take the [machine lock](machine-lock.md) here.
95
- - **`--no-cache` and `NMR_NO_CACHE=1` skip the lookup** and reach the host, where they bypass its cache too.
95
+ - **`--no-cache` and `NMR_NO_CACHE=1` skip the lookup** and reach the host, where they bypass its cache too. [Environment switches](scripts.md#environment-switches) lists the values that `NMR_NO_CACHE` accepts.
96
96
  - **An invocation that nmr settles while planning**, such as an unknown command or an empty override, settles here without contacting the host.
97
97
  - **A `-F` or `-R` invocation is sent whole**, without consulting this machine's cache, and the host fans it out.
98
98
 
@@ -46,10 +46,10 @@ A holder removes the lock when its command ends, whether the command passed or f
46
46
 
47
47
  ## Bypassing the lock
48
48
 
49
- | Step | Effect |
50
- | ------------------------- | ---------------------------------------------------------- |
51
- | `nmr --no-lock <command>` | Runs without waiting. Applies to the whole chain. |
52
- | `NMR_NO_LOCK=1` | The same, for every nmr invocation that sees the variable. |
49
+ | Step | Effect |
50
+ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
51
+ | `nmr --no-lock <command>` | Runs without waiting. Applies to the whole chain. |
52
+ | `NMR_NO_LOCK=1` | The same, for every nmr invocation that sees the variable. [Environment switches](scripts.md#environment-switches) lists the values that it accepts. |
53
53
 
54
54
  `--no-lock` belongs before the command name. After it, it is an argument to the command rather than a flag to nmr; nmr reports this rather than silently ignoring the bypass.
55
55
 
package/docs/scripts.md CHANGED
@@ -132,6 +132,10 @@ All fields are optional. [Script values](#script-values) describes `ScriptValue`
132
132
 
133
133
  Each field belongs to exactly one tier, and nmr loads from a config only the fields that its tier honors: `build` in a package config, every other field in the monorepo-root config. Declaring a field at the wrong tier fails with a message naming it and where it goes, as does a key that nmr does not recognize at all: A typo cannot degrade into a setting that silently applies nowhere.
134
134
 
135
+ ### Environment switches
136
+
137
+ `NMR_DEBUG`, `NMR_NO_CACHE`, `NMR_NO_LOCK`, and `NMR_RUN_IF_PRESENT` are on/off switches. Each is on when set to `1`, and off when set to `0`, set to an empty value, or unset. Any other value, such as `true`, makes nmr exit 2 before it runs a command, with a message that names the variable, its value, and the accepted values; `nmr-fmt` rejects such an `NMR_NO_CACHE` the same way. What each switch does is in [check-result cache](check-cache.md) (`NMR_DEBUG`, `NMR_NO_CACHE`) and [machine lock](machine-lock.md) (`NMR_NO_LOCK`); nmr sets `NMR_RUN_IF_PRESENT` itself, for the runs that it fans out.
138
+
135
139
  ### Package-level configuration
136
140
 
137
141
  A package may have its own `.config/nmr.config.ts`, which `nmr-compile` reads from the package that it is compiling. This tier honors `build` alone; declaring `workspaceScripts`, `rootScripts`, or any other root-config field there fails with a message naming them, rather than being quietly ignored: Those belong in the monorepo-root config, and a package that appeared to set them would otherwise build on settings that nothing applied. The monorepo-root config has the mirror restriction: `build` there fails the same way, since only a package's own config affects the compile.
package/docs/upgrades.md CHANGED
@@ -92,10 +92,16 @@ nodejs 24.22.1 → 24.22.3 is available. Run with --write to update .tool-versio
92
92
  `--write` rewrites that version and leaves the rest of the file unchanged. A newer major line is never proposed, whatever range mode the invocation passes: Changing majors is left to an edit of `.tool-versions`.
93
93
 
94
94
  - A release is proposed once it is at least 24 hours old. The index dates a release by UTC day alone, so a release dated D is proposed from the start of D+2, UTC.
95
+ - A release is proposed only once [node-build](https://github.com/nodenv/node-build/tree/main/share/node-build) defines it on its `main` branch, which asdf-nodejs installs from. node-build adds definitions by hand, some time after the index lists a release. When a newer release lacks a definition, the check proposes the newest release that has one and reports the newer one as held back:
96
+
97
+ ```text
98
+ nodejs 24.22.3 is held back: node-build does not define it yet.
99
+ ```
100
+
95
101
  - Only a plain `X.Y.Z` pin is checked, and only the first version on the `nodejs` line. Any other pin, such as `lts`, is skipped with a note.
96
102
  - A repo without `.tool-versions`, or without a `nodejs` entry in it, is skipped silently.
97
103
  - `--no-node-version`, which turns off taze's own checks of `.node-version` and `.nvmrc`, turns off this check too.
98
- - An unreachable index, or a file that cannot be read or written, produces a warning and does not fail the upgrade.
104
+ - An unreachable index, node-build definitions that cannot be read, or a file that cannot be read or written produces a warning and does not fail the upgrade. The check writes nothing when it cannot read the definitions.
99
105
  - `--silent` suppresses the report but not the warnings. The report goes to stderr, so `--json` output is unaffected.
100
106
 
101
107
  ## Request timeout
@@ -152,6 +158,8 @@ Run the [taze](https://github.com/antfu-collective/taze) dependency-upgrade tool
152
158
 
153
159
  Under pnpm's isolated `node_modules`, a transitive package's binary is absent from the consuming repo's `node_modules/.bin`, so a repo that depends on nmr cannot run `taze` directly. `nmr-taze` can, because nmr is a direct dependency, and it resolves the tool from the tree that nmr controls.
154
160
 
161
+ Its exit status is that of the first taze run that fails, or 128 plus the signal number when a signal ends that run.
162
+
155
163
  ```bash
156
164
  nmr-taze --recursive
157
165
  ```
package/docs/utilities.md CHANGED
@@ -44,10 +44,12 @@ nmr-compile
44
44
 
45
45
  Format, or check the formatting of, the files that git reports for the working directory. Exactly one of `--check` and `--write` is required; a bare invocation prints usage and exits non-zero rather than defaulting to a mutation. `--write` also lists the files that it rewrote. This is what `fmt` and `fmt:check` resolve to, in both registries.
46
46
 
47
- `prettier` is a dependency of nmr, but a repo's own copy takes precedence: `nmr-fmt` resolves Prettier from the working directory first and from nmr's installation second. A repository's formatter has to be the one that its editor and pre-commit hook also run, and resolution goes through the module graph rather than `PATH`, so the copy that runs is the one that the repo declares and not whichever `prettier` happens to come first. A repo that does not install Prettier, or nmr, formats with nmr's copy; when it does not have a Prettier config either, the [house config](prettier.md) applies.
47
+ `prettier` is a dependency of nmr, but a repo's own copy takes precedence: `nmr-fmt` resolves Prettier from the working directory first and from nmr's installation second. A repository's formatter has to be the one that its editor and pre-commit hook also run, and resolution goes through the module graph rather than `PATH`, so the copy that runs is the one that the repo declares and not whichever `prettier` happens to come first. A repo that does not install Prettier, or nmr, formats with nmr's copy; when it does not have a Prettier config either, the [house config](prettier.md) applies. A repo's copy whose manifest is malformed, unreadable, or without a CLI fails the run with an error that names where it is installed, rather than giving way to nmr's copy.
48
48
 
49
49
  A repo's own copy must be Prettier 3.0.0 or later. The design requires `--ignore-path` to honour every flag rather than only the last, so that a repository-root ignore file passed alongside a package-level one is not silently dropped, and 2.x honoured only the final flag.
50
50
 
51
+ A long file list is split into batches that Prettier runs one after another. The exit status is that of the first batch that fails, or 128 plus the signal number when a signal ends that batch.
52
+
51
53
  ```bash
52
54
  nmr-fmt --check
53
55
  nmr-fmt --write packages/nmr
@@ -68,7 +70,7 @@ A file that git ignores is never formatted, even when named directly. Because tr
68
70
 
69
71
  A cached entry is reused only while the Prettier version, the Node version, the resolved Prettier options, and the repository's lockfile are all unchanged. Prettier's own key covers the first three. It does not cover plugin code, so each cache file's name also contains a fingerprint of the root's lockfile, and a dependency change, a plugin upgrade included, starts a fresh cache. `nmr-fmt` deletes cache files with an outdated fingerprint, and it discards a cache file that is not valid JSON rather than letting Prettier fail on it. A failure to prepare the cache prints a warning and leaves the run uncached; it never fails the run.
70
72
 
71
- Pass `--no-cache`, or set `NMR_NO_CACHE=1`, to run uncached. `nmr --no-cache fmt:check` sets that variable, so it bypasses both nmr's [check cache](check-cache.md) and this one. Because the fingerprint makes a cache from an earlier lockfile harmless, CI can restore the whole `node_modules/.cache/prettier/nmr-fmt/` directory under a fallback key.
73
+ Pass `--no-cache`, or set `NMR_NO_CACHE=1`, to run uncached; [environment switches](scripts.md#environment-switches) lists the values that the variable accepts. `nmr --no-cache fmt:check` sets that variable, so it bypasses both nmr's [check cache](check-cache.md) and this one. Because the fingerprint makes a cache from an earlier lockfile harmless, CI can restore the whole `node_modules/.cache/prettier/nmr-fmt/` directory under a fallback key.
72
74
 
73
75
  ```bash
74
76
  nmr-fmt --check --no-cache
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williamthorsen/nmr",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "private": false,
5
5
  "description": "Context-aware script runner for pnpm monorepos",
6
6
  "keywords": [
@@ -80,7 +80,7 @@
80
80
  "!docs/*.v*.md"
81
81
  ],
82
82
  "dependencies": {
83
- "@williamthorsen/nmr-core": "0.16.1",
83
+ "@williamthorsen/nmr-core": "0.16.2",
84
84
  "@williamthorsen/toolbelt.errors": "0.9.1",
85
85
  "@williamthorsen/toolbelt.filesystem": "0.10.1",
86
86
  "glob": "14.0.4",