@williamthorsen/nmr 0.39.0 → 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.
Files changed (89) hide show
  1. package/.meta/changelog.json +145 -4
  2. package/.readyup/kits/default.js +47 -32
  3. package/.readyup/manifest.json +12 -7
  4. package/CHANGELOG.md +44 -0
  5. package/README.md +36 -75
  6. package/agents/README.md +8 -8
  7. package/agents/guidance/rulebooks/nmr.md +8 -8
  8. package/bin/ensure-prepublish-hooks.js +1 -1
  9. package/bin/nmr-clean.js +1 -1
  10. package/bin/nmr-compile.js +1 -1
  11. package/bin/nmr-fmt.js +1 -1
  12. package/bin/nmr-report-catalog.js +1 -1
  13. package/bin/nmr-report-overrides.js +1 -1
  14. package/bin/nmr-taze.js +1 -1
  15. package/bin/nmr.js +1 -1
  16. package/dist/esm/UserError.d.ts +1 -2
  17. package/dist/esm/check-cache.d.ts +59 -61
  18. package/dist/esm/commands/build-output.d.ts +35 -36
  19. package/dist/esm/commands/build.d.ts +13 -14
  20. package/dist/esm/commands/build.js +3 -3
  21. package/dist/esm/commands/clean.d.ts +6 -6
  22. package/dist/esm/commands/ensure-prepublish-hooks.d.ts +5 -5
  23. package/dist/esm/commands/fmt.d.ts +8 -8
  24. package/dist/esm/commands/fmt.js +1 -1
  25. package/dist/esm/commands/report-catalog.d.ts +5 -7
  26. package/dist/esm/commands/report-catalog.js +1 -1
  27. package/dist/esm/commands/report-overrides.d.ts +0 -2
  28. package/dist/esm/commands/report-overrides.js +1 -1
  29. package/dist/esm/commands/taze.d.ts +9 -8
  30. package/dist/esm/config.d.ts +5 -5
  31. package/dist/esm/config.js +3 -3
  32. package/dist/esm/context.d.ts +1 -2
  33. package/dist/esm/default-scripts.d.ts +5 -6
  34. package/dist/esm/defineConfig.d.ts +1 -1
  35. package/dist/esm/git-ignored-paths.d.ts +9 -0
  36. package/dist/esm/git-ignored-paths.js +10 -0
  37. package/dist/esm/glyphs.d.ts +3 -3
  38. package/dist/esm/help.d.ts +2 -2
  39. package/dist/esm/helpers/clampToBytes.d.ts +4 -5
  40. package/dist/esm/helpers/config-path.d.ts +0 -2
  41. package/dist/esm/helpers/createBoundedBuffer.d.ts +2 -2
  42. package/dist/esm/helpers/deriveExcerpt.d.ts +4 -5
  43. package/dist/esm/helpers/duration.d.ts +8 -9
  44. package/dist/esm/helpers/filter-selection.d.ts +19 -19
  45. package/dist/esm/helpers/findClosestName.d.ts +1 -1
  46. package/dist/esm/helpers/hook-name.d.ts +2 -5
  47. package/dist/esm/helpers/package-json.d.ts +9 -8
  48. package/dist/esm/helpers/readStringValues.d.ts +2 -3
  49. package/dist/esm/helpers/reportClosing.d.ts +8 -9
  50. package/dist/esm/helpers/transcript.d.ts +13 -13
  51. package/dist/esm/helpers/type-guards.d.ts +1 -0
  52. package/dist/esm/output-style.d.ts +12 -13
  53. package/dist/esm/prettier.d.ts +2 -2
  54. package/dist/esm/recording.d.ts +20 -15
  55. package/dist/esm/recording.js +7 -7
  56. package/dist/esm/replay-assembly.d.ts +10 -10
  57. package/dist/esm/report-format.d.ts +14 -19
  58. package/dist/esm/reportCliFailure.d.ts +2 -3
  59. package/dist/esm/resolve-scripts.d.ts +4 -5
  60. package/dist/esm/resolveBinStyles.d.ts +4 -5
  61. package/dist/esm/resolver.d.ts +14 -18
  62. package/dist/esm/runCli.d.ts +6 -6
  63. package/dist/esm/runCli.js +104 -27
  64. package/dist/esm/runner.d.ts +19 -19
  65. package/dist/esm/steps.d.ts +45 -42
  66. package/dist/esm/steps.js +6 -6
  67. package/dist/esm/taze.d.ts +1 -1
  68. package/dist/esm/tests.d.ts +18 -13
  69. package/dist/esm/tests.js +2 -2
  70. package/dist/esm/tiers.d.ts +27 -23
  71. package/dist/esm/tiers.js +6 -2
  72. package/dist/esm/types.d.ts +5 -5
  73. package/dist/esm/verbosity.d.ts +22 -20
  74. package/dist/esm/verdict.d.ts +33 -33
  75. package/dist/esm/verdict.js +1 -1
  76. package/dist/esm/vitest-source-resolution.d.ts +11 -11
  77. package/dist/esm/vitest-source-resolution.js +2 -2
  78. package/dist/esm/vitest.d.ts +25 -24
  79. package/dist/esm/vitest.js +16 -8
  80. package/dist/esm/workspace.d.ts +4 -4
  81. package/docs/check-cache.md +57 -57
  82. package/docs/prettier.md +10 -10
  83. package/docs/reporting.md +46 -46
  84. package/docs/scripts.md +29 -29
  85. package/docs/upgrades.md +18 -18
  86. package/docs/utilities.md +13 -13
  87. package/docs/vitest.md +64 -62
  88. package/docs/workspace.md +19 -19
  89. package/package.json +6 -5
@@ -15,15 +15,16 @@ export interface RunTazeOptions {
15
15
  * Runs taze from nmr's own dependency tree, forwarding `args`, and returns its exit code.
16
16
  *
17
17
  * Consumers depend on nmr, not on taze, so taze is transitive and its bin is absent from the consumer's
18
- * root `node_modules/.bin`. This launcher is what bridges that gap: pnpm links nmr's own bins into the
19
- * consumer root, and nmr resolves taze from the tree it does control.
18
+ * root `node_modules/.bin`. This launcher runs taze without that bin: pnpm links nmr's own bins into the
19
+ * consumer root, and nmr resolves taze from the tree that it does control.
20
20
  *
21
- * A request timeout is the one argument added, and only where `args` carries none. Neither other site can hold
22
- * it: an invocation's trailing arguments are appended to the resolved command string, so the same flag in the
23
- * `upgrade` script would be doubled by `nmr upgrade --request-timeout ...`, and taze's parser collects the pair
24
- * into an array it reads as a near-zero deadline; a `taze.config.ts` setting lands in the object taze's own CLI
25
- * defaults overwrite. Every other argument is forwarded untouched, so invocation policy (`--recursive`) stays in
26
- * the script registry, visible in `nmr` help output and overridable per repo, and upgrade policy in `taze.ts`.
21
+ * A request timeout is the one argument added, and only when `args` does not set one. Neither other site can
22
+ * declare it: Because an invocation's trailing arguments are appended to the resolved command string, the same
23
+ * flag in the `upgrade` script would be doubled by `nmr upgrade --request-timeout ...`, and taze's parser
24
+ * collects the pair into an array that it reads as a near-zero deadline; a `taze.config.ts` setting goes into
25
+ * the object that taze's own CLI defaults overwrite. Because every other argument is forwarded untouched,
26
+ * invocation policy (`--recursive`) stays in the script registry, visible in `nmr` help output and overridable
27
+ * per repo, and upgrade policy stays in `taze.ts`.
27
28
  */
28
29
  export declare function runTaze(args: string[], options?: RunTazeOptions): number;
29
30
  /** Resolves the absolute path of taze's CLI entry from nmr's own dependency tree. */
@@ -9,15 +9,15 @@ export declare function loadConfig(baseDir: string): Promise<NmrConfig>;
9
9
  * Loads the monorepo-root `.config/nmr.config.ts`, the tier that feeds script resolution and `devBin`.
10
10
  * Returns an empty config if the file doesn't exist.
11
11
  *
12
- * Throws on a recognized key this tier does not honor. `build` governs one package's compile, which reads the
12
+ * Throws on a recognized key that this tier does not honor. `build` governs one package's compile, which reads the
13
13
  * package's own config alone, so a `build` accepted here would apply its patterns nowhere.
14
14
  */
15
15
  export declare function loadRootConfig(monorepoRoot: string): Promise<NmrConfig>;
16
16
  /**
17
- * Loads a single package's `.config/nmr.config.ts`, the tier `nmr-compile` reads from its working directory.
18
- * Returns an empty config if the file doesn't exist.
17
+ * Loads a single package's `.config/nmr.config.ts`, the tier that `nmr-compile` reads from its working
18
+ * directory. Returns an empty config if the file doesn't exist.
19
19
  *
20
- * Throws on a recognized key this tier does not honor. Dropping one would leave a package building on
21
- * settings its own config file appears to change, which nothing in the build's output would reveal.
20
+ * Throws on a recognized key that this tier does not honor. Dropping one would leave a package building on
21
+ * settings that its own config file appears to change, which nothing in the build's output would reveal.
22
22
  */
23
23
  export declare function loadWorkspaceConfig(packageDir: string): Promise<NmrConfig>;
@@ -79,7 +79,7 @@ function assertValidElements(scripts, fieldName, configPath) {
79
79
  const token = findUnexpressibleToken(element);
80
80
  if (token === undefined)
81
81
  continue;
82
- throw new UserError(`Invalid nmr config at ${configPath}: \`${fieldName}.${command}\` element \`${element}\` carries ` +
82
+ throw new UserError(`Invalid nmr config at ${configPath}: \`${fieldName}.${command}\` element \`${element}\` contains ` +
83
83
  `\`${token}\`, which is neither a command name nor an nmr flag. Name it as a script of its own and ` +
84
84
  `reference that name here.`);
85
85
  }
@@ -142,7 +142,7 @@ function assertResolvableCheckCacheCommands(config, configPath, baseDir) {
142
142
  const hook = entries.find(({ command }) => isHookName(command));
143
143
  if (hook !== undefined) {
144
144
  throw new UserError(`Invalid nmr config at ${configPath}: \`checkCache.${hook.field}\` names the hook \`${hook.command}\`, ` +
145
- 'which is never gated on its own: it runs as part of the chain of the command it wraps.');
145
+ 'which is never gated on its own: It runs as part of the chain of the command that it wraps.');
146
146
  }
147
147
  const registeredNames = new Set([
148
148
  ...Object.keys(buildRootRegistry(config)),
@@ -158,7 +158,7 @@ function assertResolvableCheckCacheCommands(config, configPath, baseDir) {
158
158
  return;
159
159
  }
160
160
  const closestName = findClosestName(unresolvableEntry.command, [...registeredNames, ...declaredNames]);
161
- throw new UserError(`Invalid nmr config at ${configPath}: \`checkCache.${unresolvableEntry.field}\` names no command: ` +
161
+ throw new UserError(`Invalid nmr config at ${configPath}: \`checkCache.${unresolvableEntry.field}\` does not name any command: ` +
162
162
  `\`${unresolvableEntry.command}\`.${closestName === undefined ? '' : ` Did you mean \`${closestName}\`?`}`);
163
163
  }
164
164
  function readDeclaredScriptNames(monorepoRoot) {
@@ -3,7 +3,6 @@ export interface ResolvedContext {
3
3
  monorepoRoot: string;
4
4
  isRoot: boolean;
5
5
  packageDir?: string;
6
- /** The workspace's package directories, resolved once here rather than swept for again by each reader. */
7
6
  workspacePackageDirs: string[];
8
7
  config: NmrConfig;
9
8
  }
@@ -11,7 +10,7 @@ export interface ResolvedContext {
11
10
  * Determines whether a directory is inside a workspace package.
12
11
  * Returns the package directory if so, or `undefined` if in root context.
13
12
  *
14
- * A workspace may nest one package inside another, so the deepest containing directory wins — matching
13
+ * A workspace may nest one package inside another, so the deepest containing directory wins. This matches
15
14
  * pnpm, which resolves a cwd to the package that encloses it most nearly.
16
15
  */
17
16
  export declare function findContainingPackageDir(dir: string, workspacePackageDirs: string[]): string | undefined;
@@ -6,18 +6,17 @@ export interface StepSpec {
6
6
  /** A command name, optionally preceded by nmr's own flags, as it would be typed after `nmr`. */
7
7
  run: string;
8
8
  /**
9
- * Set where the trailing arguments cannot narrow this step's work: it is a prerequisite the narrowed steps
10
- * run against, or the tool it reaches would be misled by them. A declining step runs unnarrowed.
9
+ * Set when the trailing arguments cannot narrow this step's work: It is a prerequisite against which the
10
+ * narrowed steps run, or the tool that it invokes would be misled by them. A declining step runs unnarrowed.
11
11
  */
12
12
  shouldDeclineArguments?: boolean;
13
13
  }
14
14
  export type ScriptValue = string | ReadonlyArray<string | StepSpec>;
15
15
  export type ScriptRegistry = Record<string, ScriptValue>;
16
16
  /**
17
- * Workspace scripts, identical for every package.
18
- * Four Vitest projects are recognized: `tool`, `localhost`, `remote`, and `unit`. The latter is also a catch-all.
19
- * Name a test file with the matching infix to associate it with a project.
20
- * Example: `nmr test:tool` runs every file carrying the `tool` infix, such as `my-file.tool.test.ts`.
17
+ * Workspace scripts, identical for every package. A `test:<tier>` script runs the Vitest project of that tier, which
18
+ * collects the test files that name it: `nmr test:tool` runs `my-file.tool.test.ts`. The `unit` project also
19
+ * collects every file that does not name any other tier.
21
20
  */
22
21
  export declare const workspaceScripts: ScriptRegistry;
23
22
  export declare const rootScripts: ScriptRegistry;
@@ -1,7 +1,7 @@
1
1
  import type { NmrConfig } from './types.js';
2
2
  export type { BuildConfig, CheckCacheConfig, CommandVerbosity, NmrConfig, OutputConfig, ScriptValue, StepSpec, } from './types.js';
3
3
  /**
4
- * Type-safe identity function for configuration files.
4
+ * Returns `config` unchanged, typing a configuration file's default export as `NmrConfig`.
5
5
  *
6
6
  * Usage in `.config/nmr.config.ts`:
7
7
  * ```ts
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Lists the untracked paths that git ignores under `dir`, relative to it and POSIX-separated, sorted. An ignored
3
+ * directory is one entry ending in `/`, standing for everything beneath it; a tracked file never appears, whatever
4
+ * pattern it matches.
5
+ *
6
+ * Returns an empty list whenever git does not answer, outside a repository or with git missing, so that a caller
7
+ * excluding these paths over-reports rather than hides a path.
8
+ */
9
+ export declare function listGitIgnoredPaths(dir: string): string[];
@@ -0,0 +1,10 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ export function listGitIgnoredPaths(dir) {
3
+ const result = spawnSync('git', ['ls-files', '-z', '--others', '--ignored', '--exclude-standard', '--directory', '--no-empty-directory'], { cwd: dir, encoding: 'utf8' });
4
+ if (result.error !== undefined || result.status !== 0)
5
+ return [];
6
+ return result.stdout
7
+ .split('\0')
8
+ .filter((entry) => entry !== '')
9
+ .toSorted();
10
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Glyphs that name no status; a status marker comes from nmr-core's `STATUS_GLYPHS`. A plain variant is empty
3
- * where a word always follows the glyph, and a word where the glyph opens a line of its own.
2
+ * Glyphs that do not name a status; a status marker comes from nmr-core's `STATUS_GLYPHS`. A plain variant is
3
+ * empty when a word always follows the glyph, and a word when the glyph opens a line of its own.
4
4
  *
5
- * `noop` is a neutral circle: nothing ran because the repo asked for nothing to run, which is neither a
5
+ * `noop` is a neutral circle: Nothing ran because the repo asked for nothing to run, which is neither a
6
6
  * failure nor a block.
7
7
  */
8
8
  export declare const NMR_GLYPHS: Readonly<Record<"plain" | "rich", Readonly<Record<"overrides" | "clean" | "package" | "catalog" | "noop" | "recording", import("@williamthorsen/toolbelt.terminal/candidate").Glyph>>>>;
@@ -1,12 +1,12 @@
1
1
  import type { NmrConfig } from './types.js';
2
2
  /**
3
- * Generates the help text for the `nmr` CLI. Renders only nmr commands —
3
+ * Generates the help text for the `nmr` CLI. Renders only nmr commands:
4
4
  * names from the workspace and root registries, excluding hooks (`*:pre`,
5
5
  * `*:post`).
6
6
  *
7
7
  * When `packageDir` is provided, tier-3 entries from that package's
8
8
  * `package.json:scripts` that match a registry name in the active section
9
- * are inlined as overrides: the registry value is replaced with the
9
+ * are inlined as overrides: The registry value is replaced with the
10
10
  * override value and the row's command name is suffixed with `*`. The
11
11
  * active section is the root section when `shouldUseRoot` is true (root cwd
12
12
  * or `-w`), otherwise the workspace section. A footnote is appended once
@@ -1,14 +1,13 @@
1
- /** Marks a value that was cut, so a reader can tell a truncated one from a complete one. */
1
+ /** Marks a value that was cut, so that a reader can tell a truncated one from a complete one. */
2
2
  export declare const TRUNCATION_MARK = "\u2026";
3
3
  /**
4
4
  * Cuts a string that would overrun a byte budget, marking the cut. What comes back is at most `budgetBytes`
5
5
  * long, the mark included.
6
6
  *
7
7
  * Cuts between code points rather than between bytes, so a multi-byte character is never left in halves.
8
- * Graphemes are left unconsidered, which can separate an emoji from a modifier following it -- a cost paid
9
- * only at a budget no caller here comes near.
8
+ * Graphemes are left unconsidered, which can separate an emoji from a modifier following it -- a risk only
9
+ * at a budget that the callers here never come near.
10
10
  *
11
- * A budget too small to hold the mark yields nothing at all, rather than a return that overruns what the
12
- * caller asked for.
11
+ * The return never exceeds the budget: A budget too small to hold the mark yields an empty string.
13
12
  */
14
13
  export declare function clampToBytes(value: string, budgetBytes: number): string;
@@ -2,7 +2,5 @@
2
2
  export declare const CONFIG_RELATIVE_PATH: string;
3
3
  /**
4
4
  * Resolves the config-file path for a directory, whether that is the monorepo root or a package.
5
- * Callers that only need to know whether a config exists -- the build, which folds it into its cache digest -- go
6
- * through this rather than spelling the path again, so that the two cannot drift into hashing a file nothing reads.
7
5
  */
8
6
  export declare function resolveConfigPath(baseDir: string): string;
@@ -9,8 +9,8 @@ export interface BoundedBuffer {
9
9
  readBuffer: () => Buffer;
10
10
  }
11
11
  /**
12
- * Creates an accumulator that retains the first and last bytes it is fed and drops the middle.
13
- * Both ends are kept because a failing command's first error and its trailing summary each carry signal
12
+ * Creates an accumulator that retains the first and last bytes that it is fed and drops the middle.
13
+ * Both ends are kept because a failing command's first error and its trailing summary each contain information
14
14
  * that the other end does not.
15
15
  */
16
16
  export declare function createBoundedBuffer(options?: BoundedBufferOptions): BoundedBuffer;
@@ -1,11 +1,10 @@
1
1
  /**
2
- * Reduces a transcript to the one line a verdict's detail slot carries, or `undefined` when it held nothing.
2
+ * Reduces a transcript to the one line shown in a verdict's detail slot, or `undefined` when it contained nothing.
3
3
  *
4
4
  * The excerpt is the last blank-line-delimited block: a tool that prints progress separates its closing
5
- * statement with a blank line, so the blank line is the tool naming where its summary starts. A fixed count of
6
- * trailing lines fits vitest's four-line summary and v8's six-line coverage summary only by coincidence.
5
+ * statement with a blank line, and that blank line is the tool's own mark of where its summary starts.
7
6
  *
8
- * The line carries a byte bound of its own, so what a caller persists is bounded. The 512-byte ceiling a
9
- * verdict line is held to is not applied here, which leaves that line's grammar with the module that owns it.
7
+ * The line is bounded by `MAX_EXCERPT_BYTES` alone; the ceiling on a verdict line is applied where that line is
8
+ * composed.
10
9
  */
11
10
  export declare function deriveExcerpt(transcript: string): string | undefined;
@@ -1,17 +1,16 @@
1
1
  /**
2
- * Renders a duration at the two coarsest units that say something, for a line a reader skims.
2
+ * Renders a duration at the two coarsest units that say something, for a line that a reader skims.
3
3
  *
4
- * Truncates at every unit rather than rounding, so a value never reads as more time than elapsed: 90 seconds is
5
- * `1m 30s`, where rounding would claim `2m`. Below a minute the tenth is kept, since that is the scale at which
6
- * one check's runtime differs from another's; a whole number sheds the `.0` rather than reading `12.0s`.
4
+ * Truncates at every unit rather than rounding, so that a value never reads as more time than elapsed: 119.9
5
+ * seconds is `1m 59s`, whereas rounding would claim `2m`. Below a minute the tenth is kept, since that is the
6
+ * scale at which one check's runtime differs from another's; a whole number is rendered without the `.0`, as
7
+ * `12s` rather than `12.0s`.
7
8
  */
8
9
  export declare function formatDuration(durationMs: number): string;
9
10
  /**
10
- * Renders the clause a skip spends on the time it saved, or `undefined` when there is no saving worth naming.
11
- * A skip that can say what it saved earns the clause; one that cannot says nothing, and the caller drops it
12
- * rather than printing a saving of `~0s`.
11
+ * Renders the clause stating the time that a skip saved, or `undefined` for a saving under a second.
13
12
  *
14
- * Guards its own input rather than trusting the caller's, because the clause is shared: a non-finite duration
15
- * compares false against the threshold, and would reach a reader as `saved ~NaNs`.
13
+ * A non-finite duration also returns `undefined`: It compares false against the threshold and would otherwise
14
+ * render as `saved ~NaNs`.
16
15
  */
17
16
  export declare function formatSaving(durationMs: number): string | undefined;
@@ -1,40 +1,40 @@
1
1
  /**
2
- * Asks pnpm what a `-F` pattern selects, so an invocation that would select nothing is caught before it
3
- * delegates, and one selecting several packages is told from one selecting a single package.
2
+ * Asks pnpm what a `-F` pattern selects, so that an invocation that would select nothing is caught before it
3
+ * delegates, and one selecting several packages is distinguished from one selecting a single package.
4
4
  *
5
- * pnpm's own selector answers rather than a matcher of nmr's: `-F` means the whole selector language, names
6
- * and globs alongside `./path`, `{dir}`, `pkg...`, `!negation`, and `[since]`, and a matcher here would leave
7
- * every form but the simplest silently unchecked.
5
+ * pnpm answers because `-F` accepts pnpm's whole selector language: names and globs alongside `./path`, `{dir}`,
6
+ * `pkg...`, `!negation`, and `[since]`.
8
7
  *
9
- * Runs from the monorepo root, where the delegate runs, so a path pattern resolves against the same directory
10
- * in the probe as in the run it stands in for.
8
+ * Runs from the monorepo root, where the delegate runs, so that a path pattern resolves against the same
9
+ * directory in the probe as in the run that it stands in for.
11
10
  *
12
- * The listing counts the root project wherever the filter leaves it standing, while the `exec` a delegation
13
- * composes runs there only where the pattern selects the root positively: `-F '!./packages/*'` lists the root
14
- * and executes nowhere. A listing of the root alone is therefore the one reading the listing cannot settle,
15
- * and it is put to `exec` itself. Every other listing settles on its own, and counts the packages beside the
16
- * root: two of them run in two scopes, while one beside the root may run in that package alone.
11
+ * The listing counts the root project wherever the filter does not exclude it, while the `exec` that a
12
+ * delegation composes runs there only when the pattern selects the root positively: `-F '!./packages/*'` lists
13
+ * the root and executes nowhere. A listing of the root alone is therefore the one reading that the listing
14
+ * cannot settle, and that reading is checked against `exec` itself. Every other listing settles on its own, and
15
+ * counts the packages beside the root: two of them run in two scopes, while one beside the root may run in that
16
+ * package alone.
17
17
  */
18
18
  export declare function readFilterSelection(pattern: string, monorepoRoot: string): FilterSelection;
19
19
  /**
20
20
  * Reduces a listing to what it proves about the selection.
21
21
  *
22
- * Every outcome the probe cannot read resolves to `unresolved`, which claims nothing about the selection, and the
23
- * invocation delegates as it would have. A pattern pnpm rejects rather than resolves, such as a bad git ref in
24
- * a changed-since selector, is pnpm's to report, and reporting it here as a match failure would name a
25
- * different fault than the one the user has.
22
+ * Every outcome that the probe cannot read resolves to `unresolved`, which claims nothing about the selection,
23
+ * and the invocation delegates as it would have. A pattern that pnpm rejects rather than resolves, such as a bad
24
+ * git ref in a changed-since selector, is pnpm's to report, and reporting it here as a match failure would name a
25
+ * different fault than the one that the user has.
26
26
  */
27
27
  export declare function interpretSelectionProbe(probe: SelectionProbe, monorepoRoot: string): ProbeReading;
28
28
  /**
29
- * Reduces a marked delegate run to what it proves: a scope that wrote the marker is a scope the run reached. The
30
- * run is made only for a listing of the root alone, so that scope is the only one.
29
+ * Reduces a marked delegate run to what it proves: a scope that wrote the marker is a scope that the run
30
+ * reached. Because the run is made only for a listing of the root alone, that scope is the only one.
31
31
  */
32
32
  export declare function interpretDelegateProbe(probe: SelectionProbe): FilterSelection;
33
33
  /** What a `-F` pattern selected, as far as pnpm could be asked. `multiple` is two or more packages beside the root. */
34
34
  export type FilterSelection = 'empty' | 'multiple' | 'single' | 'unresolved';
35
35
  /** What a listing proves, `root-only` being the reading that only the delegate can settle. */
36
36
  export type ProbeReading = FilterSelection | 'root-only';
37
- /** The part of a probe's completion a selection is read from. */
37
+ /** The part of a probe's completion from which a selection is read. */
38
38
  export interface SelectionProbe {
39
39
  error: Error | undefined;
40
40
  status: number | null;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Finds the candidate closest to a name, or `undefined` where none is near enough to be worth naming.
2
+ * Finds the candidate closest to a name, or `undefined` when none is near enough to be worth naming.
3
3
  *
4
4
  * The ceiling scales with the name's length, so a short name admits one slip and a long one a few. A fixed
5
5
  * ceiling would either miss a typo in `root:test:coverage` or offer `fix` for `ci`.
@@ -1,9 +1,6 @@
1
1
  /**
2
- * Returns true when `key` is a hook script name — that is, ends with the
3
- * `:pre` or `:post` suffix preceded by at least one character.
2
+ * Reports whether `key` is a hook script name: a `:pre` or `:post` suffix preceded by at least one character.
4
3
  *
5
- * Bare `:pre` and `:post` (no parent name) return false. The predicate is
6
- * purely about suffix shape; it does not consult the registry or care
7
- * whether the parent command exists.
4
+ * Reads the suffix alone, without consulting the registry for the parent command.
8
5
  */
9
6
  export declare function isHookName(key: string): boolean;
@@ -1,8 +1,8 @@
1
1
  /**
2
- * The `package.json` fields that carry a dependency's version specifier.
2
+ * The `package.json` fields that contain a dependency's version specifier.
3
3
  *
4
4
  * pnpm accepts the `catalog:` protocol in all four, so a reader looking for catalogued dependencies has to
5
- * sweep the whole set rather than the two that carry most of them.
5
+ * sweep the whole set rather than the two that contain most of them.
6
6
  */
7
7
  export declare const DEPENDENCY_FIELDS: readonly ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
8
8
  export type DependencyField = (typeof DEPENDENCY_FIELDS)[number];
@@ -19,26 +19,27 @@ export type PackageJson = {
19
19
  [K in DependencyField]?: Record<string, string>;
20
20
  };
21
21
  /**
22
- * Reads and parses the package.json at the given directory, keeping only the fields nmr reads.
22
+ * Reads and parses the package.json at the given directory, keeping only the fields that nmr reads.
23
23
  */
24
24
  export declare function readPackageJson(dir: string): PackageJson;
25
25
  /**
26
- * Returns the `pnpm.overrides` block a package.json declares, every key it holds and each value as written.
26
+ * Returns the `pnpm.overrides` block declared by a package.json, every key that it contains and each value as
27
+ * written.
27
28
  */
28
29
  export declare function getPnpmOverrides(packageJson: PackageJson): Record<string, unknown> | undefined;
29
30
  /**
30
31
  * Parses a `package.json`'s text, rejecting what does not parse.
31
32
  *
32
- * A file the user wrote by hand is theirs to fix, so the failure names it rather than reporting the parser's
33
+ * A file that the user wrote by hand is theirs to fix, so the failure names it rather than reporting the parser's
33
34
  * own stack.
34
35
  */
35
36
  export declare function parsePackageJson(rawText: string, file: string): unknown;
36
37
  /**
37
38
  * Narrows a `scripts` record to strings, rejecting any value that is not one.
38
39
  *
39
- * npm and pnpm read a script as a string too, so a value of any other type is malformed however it got there.
40
- * Dropping one silently would let a caller run something else in its place and report nothing.
40
+ * A value of any other type is malformed however it got there, because npm and pnpm read a script as a string
41
+ * too. Dropping one silently would let a caller run something else in its place and report nothing.
41
42
  */
42
43
  export declare function readScriptRecord(dir: string, scripts: Record<string, unknown>): Record<string, string>;
43
- /** Resolves the `package.json` path for a directory: the file tier-3 scripts are read from. */
44
+ /** Resolves the `package.json` path for a directory: the file from which tier-3 scripts are read. */
44
45
  export declare function resolvePackageJsonPath(dir: string): string;
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * Keeps the entries whose value is a string, dropping the rest.
3
3
  *
4
- * A manifest reader that rejected the whole record over one bad value would report nothing about the entries
5
- * beside it, which for a reporter is silence where there is something to say. YAML's implicit typing makes
6
- * that easy to reach without malformed intent: an unquoted `18` parses as a number.
4
+ * Drops rather than rejects, so that one malformed value does not hide the entries beside it. YAML's implicit
5
+ * typing makes such a value easy to write: An unquoted `18` parses as a number.
7
6
  */
8
7
  export declare function readStringValues(record: Record<string, unknown>): Record<string, string>;
@@ -1,16 +1,15 @@
1
1
  /**
2
2
  * Reports the line that closes a bin's output, separated from the items above it by a blank line.
3
3
  *
4
- * A bin that prints one line per item leaves a reader who reaches the end holding whichever item happened to
5
- * be last. The convention this writes: the header says what the list is, and the closing statement says what
6
- * the run came to, so the count and the remedy live here rather than in the header. The blank line is what
7
- * makes the statement findable once the lines are flattened.
4
+ * When a bin prints one line per item, the last line that a reader sees is whichever item happened to be last.
5
+ * The convention that this implements: The header says what the list is, and the closing statement says what
6
+ * the run concluded, so the count and the remedy are stated here rather than in the header. The blank line makes
7
+ * the statement findable once the lines are flattened.
8
8
  *
9
- * The blank line rides in the same call as the statement, so the closer is one write and cannot be
10
- * interleaved. `log` is what puts the closer on the stream its items went to: a bin reporting to stderr
11
- * passes `console.warn`.
9
+ * The closer is one write and cannot be interleaved: The blank line goes in the same call as the statement.
10
+ * `log` writes the closer to the stream that its items went to: A bin reporting to stderr passes `console.warn`.
12
11
  *
13
- * A bin whose whole output is one or two statements about one subject has no items to be separated from, and
14
- * closes by printing plainly rather than through here.
12
+ * A bin whose whole output is one or two statements about one subject does not have any items to be separated
13
+ * from, and closes by printing plainly rather than through here.
15
14
  */
16
15
  export declare function reportClosing(message: string, log?: (line: string) => void): void;
@@ -1,30 +1,30 @@
1
1
  import type { RetainedOutput } from '../runner.js';
2
2
  /**
3
- * The bound on what one recorded pass persists, and so on what `nmr --log` can print back.
3
+ * The bound on what one recorded pass persists, and therefore on what `nmr --log` can print back.
4
4
  *
5
- * A quantity of its own, distinct from the two that bound the same bytes elsewhere: the in-memory copy a
6
- * command's capture keeps is bounded per stream, for a failure this run may still have to report, and a
7
- * verdict line is bounded at what a pipe carries atomically. This one bounds what a cache directory
8
- * accumulates over every scope and command a repo records.
5
+ * A quantity of its own, distinct from the two that bound the same bytes elsewhere: the in-memory copy kept by a
6
+ * command's capture is bounded per stream, for a failure that this run may still have to report, and a verdict
7
+ * line is bounded at the size of an atomic pipe write. This one bounds what a cache directory accumulates over
8
+ * every scope and command recorded in a repo.
9
9
  */
10
10
  export declare const TRANSCRIPT_LIMIT_BYTES = 262144;
11
11
  /**
12
- * Reduces a command's raw output to the form nmr persists: escape sequences dropped, and a line the command
13
- * redrew reduced to what a reader was left looking at.
12
+ * Reduces a command's raw output to the form that nmr persists: escape sequences dropped, and a line redrawn by
13
+ * the command reduced to what a reader was left looking at.
14
14
  *
15
- * Applied where the bytes are stored rather than where they are captured. The copy a quiet run writes to
15
+ * Applied where the bytes are stored rather than where they are captured. The copy that a quiet run writes to
16
16
  * stderr on failure is the command's own output going to a stream that may be a terminal, and stripping its
17
17
  * color there would be a loss.
18
18
  */
19
19
  export declare function cleanTranscript(rawText: string): string;
20
20
  /**
21
- * Composes what a pass persists from what its command wrote, or `undefined` where it wrote nothing worth
21
+ * Composes what a pass persists from what its command wrote, or `undefined` when it wrote nothing worth
22
22
  * keeping.
23
23
  *
24
- * The streams follow one another rather than interleaving, in the order a quiet run already dumps them on
25
- * failure: nmr reads each through a pipe of its own, so their true interleaving is not among the facts it
26
- * holds. A stream carrying nothing contributes neither content nor marker.
24
+ * The streams follow one another rather than interleaving, in the order in which a quiet run already prints them
25
+ * on failure: nmr reads each through a pipe of its own, so it does not know their true interleaving. An empty
26
+ * stream contributes neither content nor marker.
27
27
  */
28
28
  export declare function composeTranscript(retainedOutput: RetainedOutput): string | undefined;
29
- /** Renders the line that stands in for dropped bytes, in nmr's voice so it is not mistaken for the tool's. */
29
+ /** Renders the line that stands in for dropped bytes, in nmr's voice so that it is not mistaken for the tool's. */
30
30
  export declare function formatElisionMarker(byteCount: number): string;
@@ -1,3 +1,4 @@
1
+ /** Narrows an unknown value to a plain object, excluding `null` and arrays. */
1
2
  export declare function isObject(value: unknown): value is Record<string, unknown>;
2
3
  /** Narrows an unknown value to a record of plain strings. */
3
4
  export declare function isStringRecord(value: unknown): value is Record<string, string>;
@@ -1,40 +1,39 @@
1
1
  import type { Writable } from 'node:stream';
2
2
  import { type StreamStyleResolution } from '@williamthorsen/nmr-core';
3
3
  /**
4
- * Reports whether a stream is backed by a terminal, which is what detection reads where no source names a
5
- * style. A stream carrying no `isTTY`, which is the one a test injects, is not one.
4
+ * Reports whether a stream is backed by a terminal, which detection reads when the flag and `NMR_OUTPUT_STYLE`
5
+ * do not name a style. A stream without an `isTTY` property is not one.
6
6
  */
7
7
  export declare function isTerminalStream(stream: Writable): boolean;
8
8
  /**
9
- * Carries the resolved style down the spawned chain, so the flag reaches every process rather than the first
10
- * and a child writing to a pipe renders as its parent does rather than detecting plain on its own descriptor.
9
+ * Passes the resolved style down the spawned chain, so that the flag's value is available to every process rather
10
+ * than the first and a child writing to a pipe renders as its parent does rather than detecting plain on its own
11
+ * descriptor.
11
12
  *
12
- * Deliberately not a keyed variable, on neither the pass key nor the retention key: it changes how a run
13
- * renders and never what a command concludes, so folding it into either would stop a plain run from hitting a
14
- * pass a rich one recorded.
13
+ * Neither the pass key nor the retention key includes it: It changes how a run renders and never what a command
14
+ * concludes, so a plain run can reuse a pass that a rich run recorded.
15
15
  */
16
16
  export declare const OUTPUT_STYLE_ENV_VAR = "NMR_OUTPUT_STYLE";
17
17
  /**
18
18
  * The flag naming a style for one invocation, which outranks `OUTPUT_STYLE_ENV_VAR`.
19
19
  *
20
- * `nmr` alone carries it. A standalone bin takes the variable, which `nmr <command>` exports to it, so adding
21
- * a style to a bin does not mean adding a flag to each bin's own parser.
20
+ * Only `nmr` accepts it. A standalone bin reads the variable, which `nmr <command>` exports to it.
22
21
  */
23
22
  export declare const OUTPUT_STYLE_FLAG = "--output-style";
24
23
  /**
25
24
  * Resolves the style of each output stream: the flag, then `NMR_OUTPUT_STYLE`, then detection from `CI`, the
26
25
  * stream's terminal state, and `TERM`.
27
26
  *
28
- * Never throws. A value naming no style is returned in `invalid`, for the caller to report with
27
+ * Never throws. A value that does not name any style is returned in `invalid`, for the caller to report with
29
28
  * `describeInvalidOutputStyle`, because the caller has to render that complaint in some style.
30
29
  *
31
- * The flag's raw value is handed to nmr-core as an assignment rather than narrowed here, so nmr rejects a
32
- * misspelling in the words its siblings use and no second ladder can come to name a different one.
30
+ * Passes the flag's raw value to nmr-core unnarrowed, so that nmr rejects a misspelling in the same words as
31
+ * its sibling CLIs.
33
32
  */
34
33
  export declare function resolveOutputStyles(options: ResolveOutputStylesOptions): StreamStyleResolution;
35
34
  export interface ResolveOutputStylesOptions {
36
35
  env: NodeJS.ProcessEnv;
37
- /** The value the flag was given, absent where the invocation carries none, as a bin's invocation always does. */
36
+ /** The value given to the flag, absent when the invocation omits the flag, as a bin's invocation always does. */
38
37
  flagValue?: string | undefined;
39
38
  stderrIsTty: boolean;
40
39
  stdoutIsTty: boolean;
@@ -1,8 +1,8 @@
1
1
  import type { Config } from 'prettier';
2
2
  export interface PrettierConfigOptions extends Omit<Config, 'overrides' | 'plugins'> {
3
- /** Appended to the plugins this config registers. */
3
+ /** Appended to the plugins registered by this config. */
4
4
  additionalPlugins?: NonNullable<Config['plugins']>;
5
- /** Appended to the overrides this config declares, so a later entry wins over nmr's own. */
5
+ /** Appended to the overrides declared by this config, so a later entry wins over nmr's own. */
6
6
  additionalOverrides?: NonNullable<Config['overrides']>;
7
7
  /** Replacing the override list is inexpressible; append through `additionalOverrides`. */
8
8
  overrides?: never;