@konvert7/klint 0.18.0 → 0.19.1
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 +39 -1
- package/cli.ts +244 -25
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ Rules give agents room to move quickly because the unsafe moves are blocked stru
|
|
|
98
98
|
## CLI
|
|
99
99
|
|
|
100
100
|
```sh
|
|
101
|
-
klint [--config <dir>] [--rules <file>] [--fix] [--json]
|
|
101
|
+
klint [--config <dir>] [--rules <file>] [--engine ts|rust|compare|auto] [--fix] [--json]
|
|
102
102
|
klint install-skill [--agents <list>] [--symlink | --copy]
|
|
103
103
|
```
|
|
104
104
|
|
|
@@ -106,6 +106,7 @@ klint install-skill [--agents <list>] [--symlink | --copy]
|
|
|
106
106
|
|------|-------------|
|
|
107
107
|
| `--config <dir>` | Directory containing `klint.yaml` or `klint.config.json` (default: cwd) |
|
|
108
108
|
| `--rules <file>` | Path to custom rules file (default: `<configDir>/klint.rules.ts` when present) |
|
|
109
|
+
| `--engine <name>` | Engine mode: `ts` (default), `rust`, `compare`, or `auto` |
|
|
109
110
|
| `--fix` | Apply auto-fixes for fixable violations in-place |
|
|
110
111
|
| `--json` | Emit structured JSON to stdout for agents and CI |
|
|
111
112
|
|
|
@@ -115,6 +116,43 @@ klint install-skill [--agents <list>] [--symlink | --copy]
|
|
|
115
116
|
klint install-skill --agents claude,opencode,cursor,codex --copy
|
|
116
117
|
```
|
|
117
118
|
|
|
119
|
+
## Engines
|
|
120
|
+
|
|
121
|
+
klint currently ships a TypeScript engine and an experimental Rust engine. The Rust path is built for portable architecture checks and syntax-local rules; type-aware checks stay in TypeScript for now.
|
|
122
|
+
|
|
123
|
+
Maintainer migration notes live in [`docs/rust-engine.md`](docs/rust-engine.md).
|
|
124
|
+
|
|
125
|
+
| Engine | What it does | When to use it |
|
|
126
|
+
|--------|--------------|----------------|
|
|
127
|
+
| `ts` | Runs the full TypeScript implementation. This is the default. | Maximum compatibility |
|
|
128
|
+
| `rust` | Runs only rules supported by the Rust engine. Unsupported TS-only rules are rejected. | Strict Rust smoke tests and native-engine debugging |
|
|
129
|
+
| `compare` | Runs TS and Rust on the same supported config and fails if JSON output differs. Requires `--json`. | Parity verification while porting rules |
|
|
130
|
+
| `auto` | Runs Rust-supported rules in Rust, TS-only rules in TypeScript, then merges output. | Recommended experimental migration path |
|
|
131
|
+
|
|
132
|
+
Examples:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
klint --engine auto
|
|
136
|
+
klint --engine rust --json # strict Rust-only run; rejects unsupported TS-only rules
|
|
137
|
+
klint --engine compare --json # parity check; rejects unsupported TS-only rules
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Rust currently supports:
|
|
141
|
+
|
|
142
|
+
- `arch` rules: imports, forbidden patterns, singleton locations
|
|
143
|
+
- `no-unguarded-json-parse`
|
|
144
|
+
- `no-nested-template-literals`
|
|
145
|
+
- `no-consecutive-array-push`
|
|
146
|
+
- `no-string-match`
|
|
147
|
+
|
|
148
|
+
These rules remain TypeScript-owned because they need TypeScript semantic information:
|
|
149
|
+
|
|
150
|
+
- `no-floating-promise`
|
|
151
|
+
- `no-misused-promises`
|
|
152
|
+
- `no-date-equality`
|
|
153
|
+
- `no-optional-chain-on-non-nullable`
|
|
154
|
+
- `no-object-in-template`
|
|
155
|
+
|
|
118
156
|
## Configuration
|
|
119
157
|
|
|
120
158
|
`klint.yaml` lives at your project root alongside tools like `biome.json`, `tsconfig.json`, and `knip.json`.
|
package/cli.ts
CHANGED
|
@@ -4,17 +4,26 @@ import {
|
|
|
4
4
|
cpSync,
|
|
5
5
|
existsSync,
|
|
6
6
|
mkdirSync,
|
|
7
|
+
mkdtempSync,
|
|
7
8
|
readFileSync,
|
|
8
9
|
rmSync,
|
|
9
10
|
symlinkSync,
|
|
11
|
+
writeFileSync,
|
|
10
12
|
} from "node:fs";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
11
14
|
import { dirname, join, relative, resolve } from "node:path";
|
|
12
15
|
import * as clack from "@clack/prompts";
|
|
13
16
|
import { parse as parseYaml } from "yaml";
|
|
14
17
|
import { applyFixes } from "./core/fixer";
|
|
15
18
|
import { resolveNativePackageBinary } from "./core/native-binary";
|
|
16
19
|
import { type KlintDebugEvent, runKlint } from "./core/runner";
|
|
17
|
-
import type {
|
|
20
|
+
import type {
|
|
21
|
+
ArchConfig,
|
|
22
|
+
KlintConfig,
|
|
23
|
+
KlintRule,
|
|
24
|
+
RuleConfigValue,
|
|
25
|
+
Violation,
|
|
26
|
+
} from "./core/types";
|
|
18
27
|
import { BUILT_IN_PLUGINS } from "./plugins/index";
|
|
19
28
|
import { BUILT_IN_RULES } from "./rules/index";
|
|
20
29
|
|
|
@@ -96,12 +105,18 @@ export async function main(opts: CliOptions = {}): Promise<void> {
|
|
|
96
105
|
const root = resolve(configDir, raw.root ?? ".");
|
|
97
106
|
|
|
98
107
|
if (engine === "rust") {
|
|
99
|
-
runRustEngine({ configDir, fix, json, raw, rulesFile });
|
|
108
|
+
runRustEngine({ configDir, fix, json, raw, rulesFile, startedAt });
|
|
100
109
|
return;
|
|
101
110
|
}
|
|
102
|
-
if (
|
|
111
|
+
if (
|
|
112
|
+
engine !== undefined &&
|
|
113
|
+
engine !== "ts" &&
|
|
114
|
+
engine !== "rust" &&
|
|
115
|
+
engine !== "compare" &&
|
|
116
|
+
engine !== "auto"
|
|
117
|
+
) {
|
|
103
118
|
process.stderr.write(
|
|
104
|
-
`klint: unknown engine "${engine}" (expected "ts", "rust", or "
|
|
119
|
+
`klint: unknown engine "${engine}" (expected "ts", "rust", "compare", or "auto")\n`
|
|
105
120
|
);
|
|
106
121
|
process.exit(1);
|
|
107
122
|
}
|
|
@@ -120,6 +135,20 @@ export async function main(opts: CliOptions = {}): Promise<void> {
|
|
|
120
135
|
);
|
|
121
136
|
const allRules: KlintConfig["rules"] = { ...customRulesMap, ...(raw.rules ?? {}) };
|
|
122
137
|
|
|
138
|
+
if (engine === "auto") {
|
|
139
|
+
runAutoEngine({
|
|
140
|
+
fix,
|
|
141
|
+
json,
|
|
142
|
+
raw,
|
|
143
|
+
root,
|
|
144
|
+
rulesFile,
|
|
145
|
+
startedAt,
|
|
146
|
+
customRules,
|
|
147
|
+
customRulesMap,
|
|
148
|
+
});
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
123
152
|
const violations = runKlint(
|
|
124
153
|
{
|
|
125
154
|
root,
|
|
@@ -171,7 +200,19 @@ export async function main(opts: CliOptions = {}): Promise<void> {
|
|
|
171
200
|
process.stdout.write(`${msg} Finished in ${formatDuration(startedAt)}.\n`);
|
|
172
201
|
process.exit(0);
|
|
173
202
|
}
|
|
203
|
+
writeTextOutput(violations, startedAt);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function formatDuration(startedAt: number): string {
|
|
207
|
+
const elapsedMs = performance.now() - startedAt;
|
|
208
|
+
if (elapsedMs < 1000) return `${Math.round(elapsedMs)}ms`;
|
|
209
|
+
return `${(elapsedMs / 1000).toFixed(elapsedMs < 10_000 ? 2 : 1)}s`;
|
|
210
|
+
}
|
|
174
211
|
|
|
212
|
+
function writeTextOutput(
|
|
213
|
+
violations: Array<Omit<Violation, "fix">>,
|
|
214
|
+
startedAt: number
|
|
215
|
+
): never {
|
|
175
216
|
const errors = violations.filter((v) => v.severity === "error");
|
|
176
217
|
const warns = violations.filter((v) => v.severity === "warn");
|
|
177
218
|
|
|
@@ -203,18 +244,13 @@ export async function main(opts: CliOptions = {}): Promise<void> {
|
|
|
203
244
|
process.exit(0);
|
|
204
245
|
}
|
|
205
246
|
|
|
206
|
-
function formatDuration(startedAt: number): string {
|
|
207
|
-
const elapsedMs = performance.now() - startedAt;
|
|
208
|
-
if (elapsedMs < 1000) return `${Math.round(elapsedMs)}ms`;
|
|
209
|
-
return `${(elapsedMs / 1000).toFixed(elapsedMs < 10_000 ? 2 : 1)}s`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
247
|
function runRustEngine({
|
|
213
248
|
configDir,
|
|
214
249
|
fix,
|
|
215
250
|
json,
|
|
216
251
|
raw,
|
|
217
252
|
rulesFile,
|
|
253
|
+
startedAt,
|
|
218
254
|
}: {
|
|
219
255
|
configDir: string;
|
|
220
256
|
fix: boolean;
|
|
@@ -225,10 +261,10 @@ function runRustEngine({
|
|
|
225
261
|
arch?: unknown;
|
|
226
262
|
};
|
|
227
263
|
rulesFile?: string;
|
|
264
|
+
startedAt: number;
|
|
228
265
|
}): void {
|
|
229
266
|
const unsupportedReason = rustEngineUnsupportedReason({
|
|
230
267
|
fix,
|
|
231
|
-
json,
|
|
232
268
|
raw,
|
|
233
269
|
rulesFile,
|
|
234
270
|
});
|
|
@@ -249,9 +285,18 @@ function runRustEngine({
|
|
|
249
285
|
encoding: "utf-8",
|
|
250
286
|
});
|
|
251
287
|
|
|
252
|
-
if (result.stdout) process.stdout.write(result.stdout);
|
|
253
288
|
if (result.stderr) process.stderr.write(result.stderr);
|
|
254
|
-
|
|
289
|
+
if (json) {
|
|
290
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
291
|
+
process.exit(result.status ?? 1);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const payload = parseJsonPayload(result.stdout);
|
|
295
|
+
if (!isJsonPayload(payload)) {
|
|
296
|
+
process.stderr.write("klint: --engine rust failed to parse Rust JSON output\n");
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
writeTextOutput(payload.violations, startedAt);
|
|
255
300
|
}
|
|
256
301
|
|
|
257
302
|
function runCompareEngine({
|
|
@@ -273,9 +318,13 @@ function runCompareEngine({
|
|
|
273
318
|
rulesFile?: string;
|
|
274
319
|
tsViolations: ReturnType<typeof runKlint>;
|
|
275
320
|
}): void {
|
|
321
|
+
if (!json) {
|
|
322
|
+
process.stderr.write("klint: --engine compare currently requires --json\n");
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
|
|
276
326
|
const unsupportedReason = rustEngineUnsupportedReason({
|
|
277
327
|
fix,
|
|
278
|
-
json,
|
|
279
328
|
raw,
|
|
280
329
|
rulesFile,
|
|
281
330
|
});
|
|
@@ -317,17 +366,190 @@ function runCompareEngine({
|
|
|
317
366
|
process.exit(tsResult.status);
|
|
318
367
|
}
|
|
319
368
|
|
|
369
|
+
function runAutoEngine({
|
|
370
|
+
fix,
|
|
371
|
+
json,
|
|
372
|
+
raw,
|
|
373
|
+
root,
|
|
374
|
+
rulesFile,
|
|
375
|
+
startedAt,
|
|
376
|
+
customRules,
|
|
377
|
+
customRulesMap,
|
|
378
|
+
}: {
|
|
379
|
+
fix: boolean;
|
|
380
|
+
json: boolean;
|
|
381
|
+
raw: {
|
|
382
|
+
root?: string;
|
|
383
|
+
include?: string[];
|
|
384
|
+
plugins?: string[];
|
|
385
|
+
rules?: Record<string, RuleConfigValue>;
|
|
386
|
+
arch?: unknown;
|
|
387
|
+
};
|
|
388
|
+
root: string;
|
|
389
|
+
rulesFile?: string;
|
|
390
|
+
startedAt: number;
|
|
391
|
+
customRules: Record<string, KlintRule>;
|
|
392
|
+
customRulesMap: Record<string, RuleConfigValue>;
|
|
393
|
+
}): void {
|
|
394
|
+
if (fix) {
|
|
395
|
+
process.stderr.write("klint: --engine auto does not support --fix\n");
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
398
|
+
if (rulesFile) {
|
|
399
|
+
process.stderr.write("klint: --engine auto does not support --rules\n");
|
|
400
|
+
process.exit(1);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const { rustRules, tsRules } = splitRulesForAuto(raw.rules ?? {});
|
|
404
|
+
const tsViolations = runKlint(
|
|
405
|
+
{
|
|
406
|
+
root,
|
|
407
|
+
include: raw.include ?? ["."],
|
|
408
|
+
plugins: raw.plugins,
|
|
409
|
+
rules: { ...customRulesMap, ...tsRules },
|
|
410
|
+
},
|
|
411
|
+
customRules
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
const rustOutput = runAutoRustSubset({
|
|
415
|
+
raw,
|
|
416
|
+
root,
|
|
417
|
+
rustRules,
|
|
418
|
+
});
|
|
419
|
+
const tsOutput = toJsonPayload(tsViolations);
|
|
420
|
+
const merged = mergeJsonOutputs(rustOutput, tsOutput);
|
|
421
|
+
if (json) {
|
|
422
|
+
process.stdout.write(JSON.stringify(merged));
|
|
423
|
+
process.exit(merged.summary.errors > 0 ? 2 : 0);
|
|
424
|
+
}
|
|
425
|
+
writeTextOutput(merged.violations, startedAt);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function splitRulesForAuto(rules: Record<string, RuleConfigValue>): {
|
|
429
|
+
rustRules: Record<string, RuleConfigValue>;
|
|
430
|
+
tsRules: Record<string, RuleConfigValue>;
|
|
431
|
+
} {
|
|
432
|
+
const rustRules: Record<string, RuleConfigValue> = {};
|
|
433
|
+
const tsRules: Record<string, RuleConfigValue> = {};
|
|
434
|
+
|
|
435
|
+
for (const [name, value] of Object.entries(rules)) {
|
|
436
|
+
if (RUST_SUPPORTED_TYPESCRIPT_RULES.has(name)) rustRules[name] = value;
|
|
437
|
+
else tsRules[name] = value;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return { rustRules, tsRules };
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function runAutoRustSubset({
|
|
444
|
+
raw,
|
|
445
|
+
root,
|
|
446
|
+
rustRules,
|
|
447
|
+
}: {
|
|
448
|
+
raw: {
|
|
449
|
+
include?: string[];
|
|
450
|
+
arch?: unknown;
|
|
451
|
+
};
|
|
452
|
+
root: string;
|
|
453
|
+
rustRules: Record<string, RuleConfigValue>;
|
|
454
|
+
}): JsonPayload {
|
|
455
|
+
const hasRustRules = Object.values(rustRules).some(
|
|
456
|
+
(value) => ruleConfigSeverity(value) !== "off"
|
|
457
|
+
);
|
|
458
|
+
if (!raw.arch && !hasRustRules) {
|
|
459
|
+
return emptyJsonPayload();
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const tempDir = mkdtempSync(join(tmpdir(), "klint-auto-rust-"));
|
|
463
|
+
try {
|
|
464
|
+
writeFileSync(
|
|
465
|
+
join(tempDir, "klint.config.json"),
|
|
466
|
+
JSON.stringify({
|
|
467
|
+
root,
|
|
468
|
+
include: raw.include ?? ["."],
|
|
469
|
+
rules: rustRules,
|
|
470
|
+
arch: raw.arch,
|
|
471
|
+
})
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
const command = resolveRustEngineCommand(tempDir);
|
|
475
|
+
const result = spawnSync(command.bin, command.args, {
|
|
476
|
+
cwd: import.meta.dir,
|
|
477
|
+
encoding: "utf-8",
|
|
478
|
+
});
|
|
479
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
480
|
+
if ((result.status ?? 1) !== 0 && (result.status ?? 1) !== 2) {
|
|
481
|
+
process.stderr.write(result.stdout);
|
|
482
|
+
process.exit(result.status ?? 1);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const payload = parseJsonPayload(result.stdout);
|
|
486
|
+
if (!isJsonPayload(payload)) {
|
|
487
|
+
process.stderr.write("klint: --engine auto failed to parse Rust JSON output\n");
|
|
488
|
+
process.exit(1);
|
|
489
|
+
}
|
|
490
|
+
return payload;
|
|
491
|
+
} finally {
|
|
492
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
interface JsonPayload {
|
|
497
|
+
violations: Array<Omit<Violation, "fix"> & { fix: unknown }>;
|
|
498
|
+
summary: {
|
|
499
|
+
errors: number;
|
|
500
|
+
warnings: number;
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function emptyJsonPayload(): JsonPayload {
|
|
505
|
+
return {
|
|
506
|
+
violations: [],
|
|
507
|
+
summary: { errors: 0, warnings: 0 },
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function toJsonPayload(violations: ReturnType<typeof runKlint>): JsonPayload {
|
|
512
|
+
const errors = violations.filter((v) => v.severity === "error");
|
|
513
|
+
return {
|
|
514
|
+
violations: violations.map((v) => ({ ...v, fix: v.fix ?? null })),
|
|
515
|
+
summary: { errors: errors.length, warnings: violations.length - errors.length },
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function mergeJsonOutputs(...outputs: JsonPayload[]): JsonPayload {
|
|
520
|
+
const violations = outputs
|
|
521
|
+
.flatMap((output) => output.violations)
|
|
522
|
+
.sort(
|
|
523
|
+
(a, b) =>
|
|
524
|
+
a.file.localeCompare(b.file) ||
|
|
525
|
+
a.line - b.line ||
|
|
526
|
+
a.rule.localeCompare(b.rule) ||
|
|
527
|
+
a.message.localeCompare(b.message)
|
|
528
|
+
);
|
|
529
|
+
const errors = violations.filter((violation) => violation.severity === "error").length;
|
|
530
|
+
return {
|
|
531
|
+
violations,
|
|
532
|
+
summary: {
|
|
533
|
+
errors,
|
|
534
|
+
warnings: violations.length - errors,
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function isJsonPayload(value: unknown): value is JsonPayload {
|
|
540
|
+
if (!value || typeof value !== "object") return false;
|
|
541
|
+
const candidate = value as Partial<JsonPayload>;
|
|
542
|
+
return Array.isArray(candidate.violations) && typeof candidate.summary === "object";
|
|
543
|
+
}
|
|
544
|
+
|
|
320
545
|
function toJsonCliResult(violations: ReturnType<typeof runKlint>): {
|
|
321
546
|
stdout: string;
|
|
322
547
|
status: number;
|
|
323
548
|
} {
|
|
324
|
-
const
|
|
549
|
+
const payload = toJsonPayload(violations);
|
|
325
550
|
return {
|
|
326
|
-
stdout: JSON.stringify(
|
|
327
|
-
|
|
328
|
-
summary: { errors: errors.length, warnings: violations.length - errors.length },
|
|
329
|
-
}),
|
|
330
|
-
status: errors.length > 0 ? 2 : 0,
|
|
551
|
+
stdout: JSON.stringify(payload),
|
|
552
|
+
status: payload.summary.errors > 0 ? 2 : 0,
|
|
331
553
|
};
|
|
332
554
|
}
|
|
333
555
|
|
|
@@ -400,12 +622,10 @@ function isSourceCheckout(): boolean {
|
|
|
400
622
|
|
|
401
623
|
function rustEngineUnsupportedReason({
|
|
402
624
|
fix,
|
|
403
|
-
json,
|
|
404
625
|
raw,
|
|
405
626
|
rulesFile,
|
|
406
627
|
}: {
|
|
407
628
|
fix: boolean;
|
|
408
|
-
json: boolean;
|
|
409
629
|
raw: {
|
|
410
630
|
plugins?: string[];
|
|
411
631
|
rules?: Record<string, RuleConfigValue>;
|
|
@@ -413,7 +633,6 @@ function rustEngineUnsupportedReason({
|
|
|
413
633
|
};
|
|
414
634
|
rulesFile?: string;
|
|
415
635
|
}): string | undefined {
|
|
416
|
-
if (!json) return "KLINT_ENGINE=rust currently requires --json";
|
|
417
636
|
if (fix) return "KLINT_ENGINE=rust does not support --fix";
|
|
418
637
|
if (rulesFile) return "KLINT_ENGINE=rust does not support --rules";
|
|
419
638
|
if ((raw.plugins?.length ?? 0) > 0) return "KLINT_ENGINE=rust does not support plugins";
|
|
@@ -576,12 +795,12 @@ function printHelp(): void {
|
|
|
576
795
|
[
|
|
577
796
|
"klint — agent harness for TypeScript architecture rules",
|
|
578
797
|
"",
|
|
579
|
-
"Usage: klint [--config <dir>] [--rules <file>] [--engine ts|rust|compare] [--fix] [--json]",
|
|
798
|
+
"Usage: klint [--config <dir>] [--rules <file>] [--engine ts|rust|compare|auto] [--fix] [--json]",
|
|
580
799
|
" klint install-skill [--agents <list>] [--symlink | --copy]",
|
|
581
800
|
"",
|
|
582
801
|
" --config <dir> directory containing klint.yaml or klint.config.json (default: cwd)",
|
|
583
802
|
" --rules <file> custom rules file (default: <configDir>/klint.rules.ts if present)",
|
|
584
|
-
" --engine <name> engine to use: ts (default), rust, or
|
|
803
|
+
" --engine <name> engine to use: ts (default), rust, compare, or auto (experimental)",
|
|
585
804
|
" --fix apply auto-fixes for fixable violations in-place",
|
|
586
805
|
" --json emit structured JSON to stdout (for agent/CI consumption)",
|
|
587
806
|
" --debug print file resolution and rule progress to stderr",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konvert7/klint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Architecture-as-Code linter for TypeScript. Enforce layer boundaries, import rules, and singleton patterns in YAML.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"type-check": "tsc --noEmit",
|
|
37
37
|
"test": "bun test",
|
|
38
38
|
"test:rust-engine": "bun test tests/rust-engine-cli.test.ts",
|
|
39
|
+
"test:auto-engine": "bun cli.ts --engine auto",
|
|
39
40
|
"pack:check": "bun tests/pack-check.ts",
|
|
40
41
|
"native:stage": "bun tests/stage-native-binary.ts",
|
|
41
42
|
"native:smoke": "bun tests/smoke-native-binary.ts",
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
"check": "biome check",
|
|
44
45
|
"check-write": "biome check --write",
|
|
45
46
|
"knip": "knip-bun",
|
|
46
|
-
"klint": "bun cli.ts",
|
|
47
|
+
"klint": "bun cli.ts --engine auto",
|
|
47
48
|
"jscpd": "jscpd --noTips",
|
|
48
49
|
"schema": "bun tools/generate-schema.ts",
|
|
49
50
|
"lint-staged": "lint-staged",
|