@alint-js/cli 0.7.1 → 0.7.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.
package/README.md CHANGED
@@ -189,6 +189,18 @@ Ask model-backed rules to write diagnostics in a specific language:
189
189
  alint --lang zh-CN src
190
190
  ```
191
191
 
192
+ #### --rule
193
+
194
+ Run only the rules a filter names, to read one rule's findings without paying for every other rule in the run:
195
+
196
+ ```bash
197
+ alint --rule docs/review-copy src
198
+ alint --rule 'docs/*' src
199
+ alint --rule docs/review-copy,docs/naming src
200
+ ```
201
+
202
+ A pattern matches the configured rule id (`plugin/rule`) or the rule's own name. The flag is repeatable and accepts a comma-separated list. Filtered rules are left unplanned, so the run neither calls their models nor reports their diagnostics. When the filter matches no enabled rule, the run fails and lists the rule ids it did enable, because a silent empty run is indistinguishable from a clean one.
203
+
192
204
  `alint` returns exit code `0` when diagnostics contain no errors, including warning-only runs. It returns `1` when at least one error diagnostic is reported and `2` when the command cannot complete because of a configuration, input, or runtime failure. `alint output inspect` uses the same exit-code behavior for saved results.
193
205
 
194
206
  ### Inspect Configuration and Output
@@ -421,6 +433,31 @@ export default defineConfig([
421
433
  ])
422
434
  ```
423
435
 
436
+ #### Nested configs
437
+
438
+ Every `alint.config.*` below the repository root is loaded together with the root config, and each file is scoped to the directory that contains it:
439
+
440
+ ```ts
441
+ // packages/app/alint.config.ts
442
+ import { defineConfig } from '@alint-js/cli'
443
+
444
+ import { appPlugin } from './alint/plugin'
445
+
446
+ export default defineConfig([
447
+ {
448
+ plugins: { app: appPlugin },
449
+ rules: { 'app/layer-boundary': 'error' },
450
+ },
451
+ ])
452
+ ```
453
+
454
+ The item above reaches `packages/app/**` only. `files`, `directories`, and `ignores` resolve against the directory of the config that declares them, an item that declares no target patterns covers its whole subtree, and a deeper config overrides an outer one for its own directory. A package that owns a rule therefore needs one file, not an entry in the root config plus the same scope repeated in every tool that reads it.
455
+
456
+ - Discovery skips hidden directories, `node_modules`, and build output (`build`, `coverage`, `dist`, `out`, `vendor`).
457
+ - `--config <path>` pins exactly one config file and disables discovery, so a CI job can run one specific config.
458
+ - Every config file shares one plugin alias namespace and one plugin lockfile, and `alint plugin install` installs the plugins nested configs declare. Two files that bind one alias to different specifiers fail the load instead of resolving silently to one of them.
459
+ - Keep project-scoped rules (`onTargetProject`) in the root config: the project target sits outside a nested item's base path, so a nested config cannot claim it.
460
+
424
461
  #### Executable and static configs
425
462
 
426
463
  `alint` supports executable configs (`.js`, `.ts`, `.mjs`, `.cjs`, `.mts`, and `.cts`) and data-only static configs (`.toml`, `.yaml`, `.yml`, `.json`, `.jsonc`, and `.json5`).
@@ -488,6 +525,8 @@ arch = "./rules/architecture"
488
525
 
489
526
  `name` becomes the local rule id. `builtInAgent` can be `basic-structured` for a prompt-only structured-output rule or `basic-coding-agent` for a small built-in agent with filesystem tools. `includeFiles` and `excludeFiles` define where diagnostics may be reported; they do not limit what `basic-coding-agent` can inspect.
490
527
 
528
+ Editing a rule's `instruction`, `includeFiles`, or `excludeFiles` invalidates the findings it cached: a declarative rule declares those inputs as its cache key, so a changed rule text never replays stale findings.
529
+
491
530
  Run the install command again after changing a source string, moving a local directory, or changing its symlink target. Changes inside the same local directory are loaded by the next CLI process without reinstalling.
492
531
 
493
532
  Local plugins execute as trusted Node.js code. Directory containment checks validate the installed source; they are not a sandbox.
@@ -651,6 +690,19 @@ defineRule({
651
690
  })
652
691
  ```
653
692
 
693
+ Rules whose findings depend on inputs their source does not show must declare those inputs as `cacheKey`: an imported prompt, a shared message builder, or the text of a preset that builds the rule. `alint` hashes the rule source and `cacheKey` into every cache entry:
694
+
695
+ ```ts
696
+ import prompt from './prompt.md?raw'
697
+
698
+ defineRule({
699
+ cacheKey: { agentVersion: 1, prompt },
700
+ create: ctx => ({ /* ... */ }),
701
+ })
702
+ ```
703
+
704
+ Without a cache key, editing the prompt changes what the rule asks the model while the cache entry stays valid, and the next run replays the previous findings as cache hits without running the rule at all.
705
+
654
706
  ## Packages
655
707
 
656
708
  | Package | Purpose |
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as executeCli } from "../cli-F44RJ972.mjs";
2
+ import { t as executeCli } from "../cli-_dmEoPTZ.mjs";
3
3
  import process from "node:process";
4
4
  //#region src/cli/runtime/interrupt.ts
5
5
  /** Binds one graceful process interrupt to an abort signal for the active CLI run. */
@@ -24,7 +24,7 @@ import { Minimatch, minimatch } from "minimatch";
24
24
  import fastStringTruncatedWidth from "fast-string-truncated-width";
25
25
  import { formatDuration, intervalToDuration } from "date-fns";
26
26
  //#region package.json
27
- var version = "0.7.1";
27
+ var version = "0.7.2";
28
28
  //#endregion
29
29
  //#region src/cli/output.ts
30
30
  function escapeLineValue(value) {
@@ -2940,6 +2940,7 @@ async function createRunSession(io, options = {}) {
2940
2940
  outputLanguage: runOptions.outputLanguage,
2941
2941
  progress: runOptions.progress,
2942
2942
  projectTargets: runOptions.projectTargets,
2943
+ ruleFilter: runOptions.ruleFilter,
2943
2944
  runner: runOptions.runner,
2944
2945
  setupConfig,
2945
2946
  signal: runOptions.signal
@@ -3497,6 +3498,7 @@ async function executeLint(options) {
3497
3498
  modelOverride: options.modelOverride,
3498
3499
  outputLanguage: options.outputLanguage,
3499
3500
  progress: mergeProgressReporters(options.progress, statsCollector?.reporter),
3501
+ ruleFilter: options.ruleFilter,
3500
3502
  runner,
3501
3503
  signal: options.signal ?? options.createSignal?.()
3502
3504
  });
@@ -4345,6 +4347,20 @@ function groupFailuresByRule(failures) {
4345
4347
  return [...groups];
4346
4348
  }
4347
4349
  //#endregion
4350
+ //#region src/cli/commands/lint/rule-filter.ts
4351
+ /**
4352
+ * Reads `--rule` into the patterns the run filters rules with.
4353
+ *
4354
+ * The flag accepts one pattern, a comma-separated list, or repeated `--rule` flags, because a
4355
+ * debugging session usually narrows to one rule but sometimes compares a plugin's rules.
4356
+ */
4357
+ function resolveRuleFilter(value) {
4358
+ if (value === void 0) return;
4359
+ const patterns = (Array.isArray(value) ? value : [value]).flatMap((entry) => entry.split(",")).map((entry) => entry.trim()).filter((entry) => entry !== "");
4360
+ if (patterns.length === 0) throw new Error("--rule requires a rule id, a rule name, or a glob pattern.");
4361
+ return [...new Set(patterns)];
4362
+ }
4363
+ //#endregion
4348
4364
  //#region src/cli/commands/lint/index.ts
4349
4365
  const lint = defineCommand({
4350
4366
  action: (context, files = [], options) => runLintCommand(files, {
@@ -4419,6 +4435,7 @@ async function runLintCommand(files, options, io, interceptConsoleOutput, signal
4419
4435
  modelOverride: options.model,
4420
4436
  outputLanguage: options.outputLanguage,
4421
4437
  progress: progress?.reporter,
4438
+ ruleFilter: resolveRuleFilter(options.rule),
4422
4439
  runnerOptions: options,
4423
4440
  session,
4424
4441
  signal
@@ -4462,7 +4479,7 @@ function shouldEnableProgress(options, io) {
4462
4479
  //#endregion
4463
4480
  //#region src/cli/commands/lsp/index.ts
4464
4481
  const lsp = defineCommand({
4465
- action: async (context) => (await import("./server-JWv5WkGk.mjs")).startLspServer(context.io),
4482
+ action: async (context) => (await import("./server-Dxaq_DPo.mjs")).startLspServer(context.io),
4466
4483
  description: "Run alint as a language server over stdio",
4467
4484
  examples: [["# Point an editor at the project's own alint", "alint lsp"].join("\n")],
4468
4485
  help: ["Serve alint diagnostics over the Language Server Protocol on stdin/stdout.", "The server is cache-first. It publishes diagnostics that are already cached, and it never calls a model on its own. Runs that spend tokens happen only through the `alint.runFile` and `alint.runWorkspace` commands."].join("\n\n"),
@@ -5151,7 +5168,7 @@ async function executeCli(argv, io, runtime = {}) {
5151
5168
  pendingResult = result;
5152
5169
  return result;
5153
5170
  };
5154
- cli.option("--no-cache", "Disable cache for this run").option("--cache-location <path>", "Path to the alint cache file or directory").option("--cache-only", "Report only cached diagnostics; skip rules that miss the cache and call no model").option("-c, --config <path>", "Path to alint config file").option("--format <format>", "Reporter format", { default: "stylish" }).option("--model <model>", "Force a model override").option("-l, --lang <language>", "Ask model-backed rules to write diagnostics in this language").option("--progress", "Show run progress").option("--rule-concurrency <count>", "Maximum rule executions across the entire run").option("--no-stats", "Do not record run stats for this run").option("--timeout-ms <ms>", "Rule execution timeout in milliseconds").version(version).help();
5171
+ cli.option("--no-cache", "Disable cache for this run").option("--cache-location <path>", "Path to the alint cache file or directory").option("--cache-only", "Report only cached diagnostics; skip rules that miss the cache and call no model").option("-c, --config <path>", "Path to alint config file").option("--format <format>", "Reporter format", { default: "stylish" }).option("--model <model>", "Force a model override").option("-l, --lang <language>", "Ask model-backed rules to write diagnostics in this language").option("--progress", "Show run progress").option("--rule <pattern>", "Only run rules whose id, name, or glob matches (repeatable, comma-separated)").option("--rule-concurrency <count>", "Maximum rule executions across the entire run").option("--no-stats", "Do not record run stats for this run").option("--timeout-ms <ms>", "Rule execution timeout in milliseconds").version(version).help();
5155
5172
  registerCommandTree(cli, commandTree, {
5156
5173
  globalOptions,
5157
5174
  interceptConsoleOutput,
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-F44RJ972.mjs";
1
+ import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-_dmEoPTZ.mjs";
2
2
  import { ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated } from "@alint-js/config";
3
3
  import { defineConfig } from "@alint-js/core";
4
4
  export { defineConfig, executeCli, formatDiagnostics, formatJson, formatStylish, ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated };
@@ -1,4 +1,4 @@
1
- import { a as createRunSession } from "./cli-F44RJ972.mjs";
1
+ import { a as createRunSession } from "./cli-_dmEoPTZ.mjs";
2
2
  import { CLEAR_CACHE_COMMAND, RUN_FILE_COMMAND, RUN_WORKSPACE_COMMAND } from "./lsp-commands.mjs";
3
3
  import { realpath, rm } from "node:fs/promises";
4
4
  import { AlintRunCancelledError, AlintRunError } from "@alint-js/core";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alint-js/cli",
3
3
  "type": "module",
4
- "version": "0.7.1",
4
+ "version": "0.7.2",
5
5
  "description": "Agentic code analysis CLI for model-backed lint rules",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -50,10 +50,10 @@
50
50
  "tinyexec": "^1.2.4",
51
51
  "tinyrainbow": "^3.1.1",
52
52
  "vscode-languageserver": "^10.1.0",
53
- "@alint-js/config": "0.7.1",
54
- "@alint-js/core": "0.7.1",
55
- "@alint-js/model-adapter-acp": "0.7.1",
56
- "@alint-js/utils": "0.7.1"
53
+ "@alint-js/config": "0.7.2",
54
+ "@alint-js/core": "0.7.2",
55
+ "@alint-js/model-adapter-acp": "0.7.2",
56
+ "@alint-js/utils": "0.7.2"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@pnpm/find-workspace-dir": "^1000.1.5",