@aurelienbbn/agentlint 0.1.0 → 0.1.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/dist/bin.mjs CHANGED
@@ -2,9 +2,8 @@
2
2
  import { n as wrapNode, r as FlagRecord } from "./node-yh9mLvnE.mjs";
3
3
  import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
4
4
  import * as NodeServices from "@effect/platform-node/NodeServices";
5
- import { Console, Effect, FileSystem, HashMap, HashSet, Layer, Option, Path, Schema } from "effect";
5
+ import { Console, Context, Effect, FileSystem, HashMap, HashSet, Layer, Option, Path, Schema } from "effect";
6
6
  import { Argument, Command, Flag } from "effect/unstable/cli";
7
- import * as ServiceMap from "effect/ServiceMap";
8
7
  import picomatch from "picomatch";
9
8
  import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
10
9
  import { Language, Parser } from "web-tree-sitter";
@@ -30,7 +29,7 @@ import { Language, Parser } from "web-tree-sitter";
30
29
  * @since 0.1.0
31
30
  * @category services
32
31
  */
33
- var Env = class Env extends ServiceMap.Service()("agentreview/Env") {
32
+ var Env = class Env extends Context.Service()("agentlint/Env") {
34
33
  /**
35
34
  * Default layer — reads from `process` globals exactly once.
36
35
  *
@@ -58,7 +57,7 @@ var Env = class Env extends ServiceMap.Service()("agentreview/Env") {
58
57
  * via `jiti` (for TypeScript support without pre-compilation), and
59
58
  * validates the exported shape.
60
59
  *
61
- * **Search order**: `agentreview.config.ts` → `.js` → `.mts` → `.mjs`.
60
+ * **Search order**: `agentlint.config.ts` → `.js` → `.mts` → `.mjs`.
62
61
  * The first match wins.
63
62
  *
64
63
  * @module
@@ -78,10 +77,10 @@ var ConfigError = class extends Schema.TaggedErrorClass()("ConfigError", { messa
78
77
  * @category constants
79
78
  */
80
79
  const CONFIG_NAMES = [
81
- "agentreview.config.ts",
82
- "agentreview.config.js",
83
- "agentreview.config.mts",
84
- "agentreview.config.mjs"
80
+ "agentlint.config.ts",
81
+ "agentlint.config.js",
82
+ "agentlint.config.mts",
83
+ "agentlint.config.mjs"
85
84
  ];
86
85
  /**
87
86
  * Discover the config file path by checking candidates in order.
@@ -94,10 +93,10 @@ const discoverConfig = (fs, path, cwd) => Effect.gen(function* () {
94
93
  const candidate = path.resolve(cwd, name);
95
94
  if (yield* fs.exists(candidate).pipe(Effect.orElseSucceed(() => false))) return candidate;
96
95
  }
97
- return yield* new ConfigError({ message: `No agentreview config found. Create agentreview.config.ts in ${cwd}` });
96
+ return yield* new ConfigError({ message: `No agentlint config found. Create agentlint.config.ts in ${cwd}` });
98
97
  });
99
98
  /**
100
- * Effect service that discovers and loads the agentreview config file.
99
+ * Effect service that discovers and loads the agentlint config file.
101
100
  *
102
101
  * Uses `jiti` under the hood so TypeScript configs work without a
103
102
  * separate compilation step.
@@ -117,7 +116,7 @@ const discoverConfig = (fs, path, cwd) => Effect.gen(function* () {
117
116
  * @since 0.1.0
118
117
  * @category services
119
118
  */
120
- var ConfigLoader = class ConfigLoader extends ServiceMap.Service()("agentreview/ConfigLoader") {
119
+ var ConfigLoader = class ConfigLoader extends Context.Service()("agentlint/ConfigLoader") {
121
120
  static layer = Layer.effect(ConfigLoader, Effect.gen(function* () {
122
121
  const env = yield* Env;
123
122
  const fs = yield* FileSystem.FileSystem;
@@ -142,7 +141,7 @@ var ConfigLoader = class ConfigLoader extends ServiceMap.Service()("agentreview/
142
141
  /**
143
142
  * Local state store for tracking reviewed flags.
144
143
  *
145
- * Manages a `.agentreview-state` file in the project root that stores
144
+ * Manages a `.agentlint-state` file in the project root that stores
146
145
  * hashes of flags that have been reviewed. This file is intended to
147
146
  * be **gitignored** — it is per-developer scratch state for tracking
148
147
  * progress during review sweeps.
@@ -152,7 +151,7 @@ var ConfigLoader = class ConfigLoader extends ServiceMap.Service()("agentreview/
152
151
  * above a reviewed flag shifts its position and invalidates the hash.
153
152
  * This is by design — changed context should be re-reviewed.
154
153
  * - Stale hashes (from flags that no longer exist) accumulate harmlessly.
155
- * Use `agentreview review --reset` to start fresh.
154
+ * Use `agentlint review --reset` to start fresh.
156
155
  *
157
156
  * @module
158
157
  * @since 0.1.0
@@ -163,7 +162,7 @@ var ConfigLoader = class ConfigLoader extends ServiceMap.Service()("agentreview/
163
162
  * @since 0.1.0
164
163
  * @category constants
165
164
  */
166
- const STATE_FILENAME = ".agentreview-state";
165
+ const STATE_FILENAME = ".agentlint-state";
167
166
  /**
168
167
  * Parse the state file into a set of hashes.
169
168
  * Tolerates blank lines and `#`-prefixed comments.
@@ -194,7 +193,7 @@ function serializeHashes(hashes) {
194
193
  * @since 0.1.0
195
194
  * @category services
196
195
  */
197
- var StateStore = class StateStore extends ServiceMap.Service()("agentreview/StateStore") {
196
+ var StateStore = class StateStore extends Context.Service()("agentlint/StateStore") {
198
197
  /**
199
198
  * Default layer — resolves the state file path from `Env.cwd`.
200
199
  *
@@ -345,13 +344,9 @@ var RuleContextImpl = class {
345
344
  /**
346
345
  * File resolution service.
347
346
  *
348
- * Determines which files to lint by applying the 6-layer filter pipeline:
347
+ * Determines which files to lint by applying the filter pipeline:
349
348
  * 1. Candidate files (from git diff or all files)
350
- * 2. Built-in ignores
351
- * 3. .gitignore
352
- * 4. .agentreviewignore
353
- * 5. Config include/ignore
354
- * (Steps 2-4 are handled by IgnoreReader)
349
+ * 2. Config include/ignore
355
350
  *
356
351
  * Per-rule filtering (languages, include, ignore) is done by the check command.
357
352
  *
@@ -410,7 +405,7 @@ function listAllFiles(dir, base, fs, path) {
410
405
  * @since 0.1.0
411
406
  * @category constructors
412
407
  */
413
- function resolveFiles(options, ignoreReader, gitService) {
408
+ function resolveFiles(options, gitService) {
414
409
  return Effect.gen(function* () {
415
410
  const env = yield* Env;
416
411
  const fs = yield* FileSystem.FileSystem;
@@ -422,7 +417,7 @@ function resolveFiles(options, ignoreReader, gitService) {
422
417
  else candidates = [...yield* Effect.mapError(gitService.changedFiles(options.baseRef), (e) => new FileResolverError({ message: `Git error: ${e}` }))];
423
418
  const includeMatcher = options.configInclude?.length ? picomatch(options.configInclude) : void 0;
424
419
  const ignoreMatcher = options.configIgnore?.length ? picomatch(options.configIgnore) : void 0;
425
- return candidates.filter((f) => !ignoreReader.isIgnored(f)).filter((f) => !includeMatcher || includeMatcher(f)).filter((f) => !ignoreMatcher || !ignoreMatcher(f)).filter((f) => path.extname(f).length > 0).toSorted();
420
+ return candidates.filter((f) => !includeMatcher || includeMatcher(f)).filter((f) => !ignoreMatcher || !ignoreMatcher(f)).filter((f) => path.extname(f).length > 0).toSorted();
426
421
  });
427
422
  }
428
423
  //#endregion
@@ -497,7 +492,7 @@ const collectChangedFiles = (cwd, baseRef) => Effect.all([
497
492
  *
498
493
  * @since 0.1.0
499
494
  */
500
- var Git = class Git extends ServiceMap.Service()("agentreview/Git") {
495
+ var Git = class Git extends Context.Service()("agentlint/Git") {
501
496
  static layer = Layer.effect(Git, Effect.gen(function* () {
502
497
  const env = yield* Env;
503
498
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
@@ -509,74 +504,6 @@ var Git = class Git extends ServiceMap.Service()("agentreview/Git") {
509
504
  }));
510
505
  };
511
506
  //#endregion
512
- //#region src/shared/infrastructure/ignore-reader.ts
513
- /**
514
- * Ignore-pattern aggregation service.
515
- *
516
- * Merges built-in ignore patterns (e.g. `node_modules`, `dist`) with
517
- * the project's `.gitignore` to produce a single `isIgnored` predicate.
518
- * Patterns are compiled once via `picomatch` and reused for every file.
519
- *
520
- * @module
521
- * @since 0.1.0
522
- */
523
- /**
524
- * Paths that are always ignored regardless of user configuration.
525
- *
526
- * Covers common build output, package manager artifacts, source maps,
527
- * lockfiles, and cache directories.
528
- *
529
- * @since 0.1.0
530
- * @category constants
531
- */
532
- const BUILTIN_IGNORE_PATTERNS = [
533
- "node_modules/**",
534
- "dist/**",
535
- "build/**",
536
- ".git/**",
537
- ".next/**",
538
- ".cache/**",
539
- "coverage/**",
540
- "**/*.min.js",
541
- "**/*.min.css",
542
- "**/*.map",
543
- "**/*.lock",
544
- "**/*.log",
545
- "**/*.tsbuildinfo",
546
- ".agentreview-state"
547
- ];
548
- /**
549
- * Parse a `.gitignore`-style file into an array of glob patterns.
550
- * Strips blank lines and comments (lines starting with `#`).
551
- *
552
- * @since 0.1.0
553
- * @category internals
554
- */
555
- function parseIgnoreFile(content) {
556
- return content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
557
- }
558
- /**
559
- * Effect service that tests whether a file path should be ignored.
560
- *
561
- * Combines built-in patterns with `.gitignore` into a single
562
- * `picomatch` matcher. Constructed once per run.
563
- *
564
- * @since 0.1.0
565
- * @category services
566
- */
567
- var IgnoreReader = class IgnoreReader extends ServiceMap.Service()("agentreview/IgnoreReader") {
568
- static layer = Layer.unwrap(Effect.gen(function* () {
569
- const env = yield* Env;
570
- const fs = yield* FileSystem.FileSystem;
571
- const path = yield* Path.Path;
572
- const { cwd } = env;
573
- const gitignorePath = path.resolve(cwd, ".gitignore");
574
- const gitignorePatterns = (yield* fs.exists(gitignorePath).pipe(Effect.orElseSucceed(() => false))) ? parseIgnoreFile(yield* fs.readFileString(gitignorePath).pipe(Effect.orElseSucceed(() => ""))) : [];
575
- const matcher = picomatch([...BUILTIN_IGNORE_PATTERNS, ...gitignorePatterns], { dot: true });
576
- return Layer.succeed(IgnoreReader, IgnoreReader.of({ isIgnored: (filepath) => matcher(filepath) }));
577
- }));
578
- };
579
- //#endregion
580
507
  //#region src/shared/infrastructure/parser.ts
581
508
  /**
582
509
  * Tree-sitter WASM parser.
@@ -618,7 +545,7 @@ const GRAMMAR_FILES = HashMap.make(["typescript", "tree-sitter-typescript.wasm"]
618
545
  * @since 0.1.0
619
546
  * @category services
620
547
  */
621
- var Parser$1 = class Parser$1 extends ServiceMap.Service()("agentreview/Parser") {
548
+ var Parser$1 = class Parser$1 extends Context.Service()("agentlint/Parser") {
622
549
  /** Default layer — lazily initializes WASM and caches grammars. */
623
550
  static layer = Layer.effect(Parser$1, Effect.gen(function* () {
624
551
  const env = yield* Env;
@@ -681,16 +608,16 @@ var Parser$1 = class Parser$1 extends ServiceMap.Service()("agentreview/Parser")
681
608
  * @module
682
609
  */
683
610
  /**
684
- * Regex matching `agentreview-ignore` comments.
611
+ * Regex matching `agentlint-ignore` comments.
685
612
  *
686
613
  * Captures an optional rule name after the directive:
687
- * - `// agentreview-ignore` → suppresses all rules on the next line
688
- * - `// agentreview-ignore my-rule` → suppresses only `my-rule`
614
+ * - `// agentlint-ignore` → suppresses all rules on the next line
615
+ * - `// agentlint-ignore my-rule` → suppresses only `my-rule`
689
616
  *
690
617
  * @since 0.1.0
691
618
  * @category constants
692
619
  */
693
- const IGNORE_PATTERN = /agentreview-ignore(?:\s+(\S+))?/;
620
+ const IGNORE_PATTERN = /agentlint-ignore(?:\s+(\S+))?/;
694
621
  /**
695
622
  * Walk files with the given rules, collecting all flags.
696
623
  *
@@ -760,7 +687,7 @@ function walkFile(tree, rules) {
760
687
  *
761
688
  * Maps every supported file extension to the grammar name used by
762
689
  * the parser service. This is the single source of truth for which
763
- * file types agentreview can analyze.
690
+ * file types agentlint can analyze.
764
691
  *
765
692
  * Uses Effect `HashMap` for an immutable, structurally-equal lookup table.
766
693
  *
@@ -804,7 +731,6 @@ const collectFlags = Effect.fn("collectFlags")(function* (options) {
804
731
  const env = yield* Env;
805
732
  const fs = yield* FileSystem.FileSystem;
806
733
  const path = yield* Path.Path;
807
- const ignoreReader = yield* IgnoreReader;
808
734
  const gitService = yield* Git;
809
735
  const parserService = yield* Parser$1;
810
736
  const config = yield* configLoader.load();
@@ -824,7 +750,7 @@ const collectFlags = Effect.fn("collectFlags")(function* (options) {
824
750
  configInclude: includePatterns,
825
751
  configIgnore: ignorePatterns,
826
752
  positionalFiles: options.files.length > 0 ? [...options.files] : void 0
827
- }, ignoreReader, gitService);
753
+ }, gitService);
828
754
  if (files.length === 0) return {
829
755
  flags: [],
830
756
  noMatchingRules: false
@@ -980,19 +906,19 @@ var InitResult = class extends Schema.TaggedClass()("InitResult", {
980
906
  * @since 0.1.0
981
907
  */
982
908
  /**
983
- * Minimal starter config written by `agentreview init`.
909
+ * Minimal starter config written by `agentlint init`.
984
910
  *
985
911
  * @since 0.1.0
986
912
  * @category constants
987
913
  */
988
- const STARTER_CONFIG = `import { defineConfig } from "agentreview"
914
+ const STARTER_CONFIG = `import { defineConfig } from "agentlint"
989
915
 
990
916
  export default defineConfig({
991
917
  include: ["src/**/*.{ts,tsx}"],
992
918
  rules: {},
993
919
  })
994
920
  `;
995
- const SKILLS_ADD_CMD = "npx skills@latest add aurelienbobenrieth/agentreview";
921
+ const SKILLS_ADD_CMD = "npx skills@latest add aurelienbobenrieth/agentlint";
996
922
  const INTENT_INSTALL_CMD = "npx @tanstack/intent install";
997
923
  /**
998
924
  * Detect which skill installation method is most likely appropriate.
@@ -1014,28 +940,28 @@ const initHandler = Effect.fn("initHandler")(function* (_command) {
1014
940
  const env = yield* Env;
1015
941
  const fs = yield* FileSystem.FileSystem;
1016
942
  const path = yield* Path.Path;
1017
- const configPath = path.resolve(env.cwd, "agentreview.config.ts");
943
+ const configPath = path.resolve(env.cwd, "agentlint.config.ts");
1018
944
  const gitignorePath = path.resolve(env.cwd, ".gitignore");
1019
945
  const configCreated = !(yield* fs.exists(configPath));
1020
946
  if (configCreated) yield* fs.writeFileString(configPath, STARTER_CONFIG);
1021
947
  let gitignoreUpdated = false;
1022
948
  if (yield* fs.exists(gitignorePath)) {
1023
949
  const content = yield* fs.readFileString(gitignorePath);
1024
- if (!content.includes(".agentreview-state")) {
950
+ if (!content.includes(".agentlint-state")) {
1025
951
  const separator = content.endsWith("\n") ? "" : "\n";
1026
- yield* fs.writeFileString(gitignorePath, content + separator + "\n# agentreview local state\n.agentreview-state\n");
952
+ yield* fs.writeFileString(gitignorePath, content + separator + "\n# agentlint local state\n.agentlint-state\n");
1027
953
  gitignoreUpdated = true;
1028
954
  }
1029
955
  } else {
1030
- yield* fs.writeFileString(gitignorePath, "# agentreview local state\n.agentreview-state\n");
956
+ yield* fs.writeFileString(gitignorePath, "# agentlint local state\n.agentlint-state\n");
1031
957
  gitignoreUpdated = true;
1032
958
  }
1033
959
  const lines = [];
1034
- if (configCreated) lines.push("✓ Created agentreview.config.ts");
1035
- else lines.push("· agentreview.config.ts already exists — skipped");
1036
- if (gitignoreUpdated) lines.push("✓ Added .agentreview-state to .gitignore");
960
+ if (configCreated) lines.push("✓ Created agentlint.config.ts");
961
+ else lines.push("· agentlint.config.ts already exists — skipped");
962
+ if (gitignoreUpdated) lines.push("✓ Added .agentlint-state to .gitignore");
1037
963
  const skillCmd = (yield* detectSkillMethod(env.cwd)) === "intent" ? INTENT_INSTALL_CMD : SKILLS_ADD_CMD;
1038
- lines.push("", "Next steps:", " 1. Add rules to your config", ` 2. Install the agentreview skill for your AI agents:`, ` ${skillCmd}`, " 3. Run: npx agentreview check --all");
964
+ lines.push("", "Next steps:", " 1. Add rules to your config", ` 2. Install the agentlint skill for your AI agents:`, ` ${skillCmd}`, " 3. Run: npx agentlint check --all");
1039
965
  return new InitResult({
1040
966
  created: configCreated,
1041
967
  message: lines.join("\n")
@@ -1116,7 +1042,7 @@ const reviewHandler = Effect.fn("reviewHandler")(function* (command) {
1116
1042
  const stateStore = yield* StateStore;
1117
1043
  if (command.reset) {
1118
1044
  yield* stateStore.reset();
1119
- return new ReviewResult({ message: "Cleared .agentreview-state" });
1045
+ return new ReviewResult({ message: "Cleared .agentlint-state" });
1120
1046
  }
1121
1047
  if (command.all) {
1122
1048
  const allFlags = (yield* collectFlags({
@@ -1136,9 +1062,9 @@ const reviewHandler = Effect.fn("reviewHandler")(function* (command) {
1136
1062
  }
1137
1063
  return new ReviewResult({ message: [
1138
1064
  "Usage:",
1139
- " agentreview review <hash...> Mark specific flags as reviewed",
1140
- " agentreview review --all Mark all current flags as reviewed",
1141
- " agentreview review --reset Wipe the state file"
1065
+ " agentlint review <hash...> Mark specific flags as reviewed",
1066
+ " agentlint review --all Mark all current flags as reviewed",
1067
+ " agentlint review --reset Wipe the state file"
1142
1068
  ].join("\n") });
1143
1069
  });
1144
1070
  //#endregion
@@ -1206,7 +1132,7 @@ const formatReport = Effect.fn("formatReport")(function* (flags, rulesMeta, opti
1206
1132
  const env = yield* Env;
1207
1133
  const path = yield* Path.Path;
1208
1134
  const ansi = makeAnsi(env.noColor);
1209
- if (flags.length === 0) return `${ansi.bold("agentreview")} ${ansi.dim(`v${options.version}`)} ${ansi.dim("-")} no rules triggered.`;
1135
+ if (flags.length === 0) return `${ansi.bold("agentlint")} ${ansi.dim(`v${options.version}`)} ${ansi.dim("-")} no rules triggered.`;
1210
1136
  const { cwd } = env;
1211
1137
  const lines = [];
1212
1138
  const grouped = groupBy(flags, (f) => f.ruleName);
@@ -1251,7 +1177,7 @@ const formatReport = Effect.fn("formatReport")(function* (flags, rulesMeta, opti
1251
1177
  //#endregion
1252
1178
  //#region src/bin.ts
1253
1179
  /**
1254
- * CLI entry point for `agentreview`.
1180
+ * CLI entry point for `agentlint`.
1255
1181
  *
1256
1182
  * Thin adapter that translates CLI arguments into feature commands,
1257
1183
  * dispatches to the appropriate handler, and formats the result
@@ -1290,17 +1216,17 @@ const check = Command.make("check", {
1290
1216
  return;
1291
1217
  }
1292
1218
  if (result.totalFlags === 0) {
1293
- yield* Console.log(`agentreview v0.1.0 - no rules triggered.`);
1219
+ yield* Console.log(`agentlint v0.1.2 - no rules triggered.`);
1294
1220
  return;
1295
1221
  }
1296
1222
  const cfg = yield* (yield* ConfigLoader).load();
1297
1223
  const rulesMeta = HashMap.fromIterable(Object.entries(cfg.rules).map(([name, rule]) => [name, rule.meta]));
1298
1224
  const output = yield* formatReport(result.flags, rulesMeta, {
1299
1225
  dryRun: config.dryRun,
1300
- version: "0.1.0"
1226
+ version: "0.1.2"
1301
1227
  });
1302
1228
  yield* Console.log(output);
1303
- if (result.filteredCount > 0) yield* Console.log(` (${result.filteredCount} reviewed flag(s) hidden — run agentreview review --reset to clear)`);
1229
+ if (result.filteredCount > 0) yield* Console.log(` (${result.filteredCount} reviewed flag(s) hidden — run agentlint review --reset to clear)`);
1304
1230
  if (result.flags.length > 0) env.setExitCode(1);
1305
1231
  });
1306
1232
  }).pipe(Command.withDescription("Scan files and output report for AI agents"));
@@ -1326,7 +1252,7 @@ const list = Command.make("list", {}, () => Effect.gen(function* () {
1326
1252
  const init = Command.make("init", {}, () => Effect.gen(function* () {
1327
1253
  const result = yield* initHandler(new InitCommand({}));
1328
1254
  yield* Console.log(result.message);
1329
- })).pipe(Command.withDescription("Create agentreview.config.ts and set up agent skill discovery"));
1255
+ })).pipe(Command.withDescription("Create agentlint.config.ts and set up agent skill discovery"));
1330
1256
  /** The `review` subcommand — manage reviewed-flag state. */
1331
1257
  const review = Command.make("review", {
1332
1258
  hashes: Argument.string("hashes").pipe(Argument.withDescription("Flag hashes to mark as reviewed"), Argument.variadic()),
@@ -1340,14 +1266,14 @@ const review = Command.make("review", {
1340
1266
  }));
1341
1267
  yield* Console.log(result.message);
1342
1268
  })).pipe(Command.withDescription("Mark flags as reviewed (filters them from check output)"));
1343
- const agentreview = Command.make("agentreview").pipe(Command.withDescription("Deterministic linting for AI agents"), Command.withSubcommands([
1269
+ const agentlint = Command.make("agentlint").pipe(Command.withDescription("Deterministic linting for AI agents"), Command.withSubcommands([
1344
1270
  check,
1345
1271
  list,
1346
1272
  init,
1347
1273
  review
1348
1274
  ]));
1349
- const AppLayer = Layer.mergeAll(ConfigLoader.layer, Parser$1.layer, Git.layer, IgnoreReader.layer, StateStore.layer).pipe(Layer.provideMerge(NodeServices.layer), Layer.provideMerge(Env.layer));
1350
- const program = Command.run(agentreview, { version: "0.1.0" }).pipe(Effect.provide(AppLayer));
1275
+ const AppLayer = Layer.mergeAll(ConfigLoader.layer, Parser$1.layer, Git.layer, StateStore.layer).pipe(Layer.provideMerge(NodeServices.layer), Layer.provideMerge(Env.layer));
1276
+ const program = Command.run(agentlint, { version: "0.1.2" }).pipe(Effect.provide(AppLayer));
1351
1277
  NodeRuntime.runMain(program);
1352
1278
  //#endregion
1353
1279
  export {};
package/dist/bin.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.mjs","names":["#filename","#source","Parser","TSParser","Parser","Parser"],"sources":["../src/config/env.ts","../src/shared/infrastructure/config-loader.ts","../src/shared/infrastructure/state-store.ts","../src/domain/hash.ts","../src/domain/rule-context.ts","../src/shared/pipeline/file-resolver.ts","../src/shared/infrastructure/git.ts","../src/shared/infrastructure/ignore-reader.ts","../src/shared/infrastructure/parser.ts","../src/shared/pipeline/tree-walker.ts","../src/shared/pipeline/language-map.ts","../src/shared/pipeline/collect-flags.ts","../src/features/check/request.ts","../src/features/check/handler.ts","../src/features/init/request.ts","../src/features/init/handler.ts","../src/features/list/request.ts","../src/features/list/handler.ts","../src/features/review/request.ts","../src/features/review/handler.ts","../src/cli/reporter.ts","../src/bin.ts"],"sourcesContent":["/**\n * Centralised process / environment access.\n *\n * **This is the only module in the codebase that may touch `process.*`.**\n *\n * Every other module that needs the working directory, TTY state, colour\n * preference, or exit-code control must depend on the `Env` service\n * instead of reaching into `process` directly.\n *\n * The layer is built once at startup with `Layer.sync` (no external\n * dependencies), so it can be provided before every other service layer.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Layer } from \"effect\";\nimport * as ServiceMap from \"effect/ServiceMap\";\n\n/**\n * Read-only snapshot of the runtime environment.\n *\n * @since 0.1.0\n * @category services\n */\nexport class Env extends ServiceMap.Service<\n Env,\n {\n /** Current working directory, captured at startup. */\n readonly cwd: string;\n /** `true` when ANSI colour codes should be suppressed (`NO_COLOR` or non-TTY). */\n readonly noColor: boolean;\n /** `true` when stdout is an interactive terminal. */\n readonly isTTY: boolean;\n /** Set the process exit code (non-zero signals failure to the shell). */\n setExitCode(code: number): void;\n }\n>()(\"agentreview/Env\") {\n /**\n * Default layer — reads from `process` globals exactly once.\n *\n * @since 0.1.0\n * @category layers\n */\n static readonly layer: Layer.Layer<Env> = Layer.sync(Env, () => {\n /* eslint-disable n/no-process-env -- single authorised access point */\n const isTTY = process.stdout.isTTY ?? false;\n return Env.of({\n cwd: process.cwd(),\n noColor: !!process.env[\"NO_COLOR\"] || !isTTY,\n isTTY,\n setExitCode: (code) => {\n process.exitCode = code;\n },\n });\n /* eslint-enable n/no-process-env */\n });\n}\n","/**\n * Configuration file discovery and loading.\n *\n * Searches the current working directory for a config file, imports it\n * via `jiti` (for TypeScript support without pre-compilation), and\n * validates the exported shape.\n *\n * **Search order**: `agentreview.config.ts` → `.js` → `.mts` → `.mjs`.\n * The first match wins.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, Layer, Path, Schema } from \"effect\";\nimport * as ServiceMap from \"effect/ServiceMap\";\nimport { Env } from \"../../config/env.js\";\nimport type { AgentReviewConfig } from \"../../domain/config.js\";\n\n/**\n * Raised when the config file is missing, malformed, or fails to import.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class ConfigError extends Schema.TaggedErrorClass<ConfigError>()(\"ConfigError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Candidate config file names, checked in order.\n *\n * @since 0.1.0\n * @category constants\n */\nconst CONFIG_NAMES = [\n \"agentreview.config.ts\",\n \"agentreview.config.js\",\n \"agentreview.config.mts\",\n \"agentreview.config.mjs\",\n];\n\n/**\n * Discover the config file path by checking candidates in order.\n *\n * @since 0.1.0\n * @category internals\n */\nconst discoverConfig = (fs: FileSystem.FileSystem, path: Path.Path, cwd: string): Effect.Effect<string, ConfigError> =>\n Effect.gen(function* () {\n for (const name of CONFIG_NAMES) {\n const candidate = path.resolve(cwd, name);\n if (yield* fs.exists(candidate).pipe(Effect.orElseSucceed(() => false))) {\n return candidate;\n }\n }\n return yield* new ConfigError({\n message: `No agentreview config found. Create agentreview.config.ts in ${cwd}`,\n });\n });\n\n/**\n * Effect service that discovers and loads the agentreview config file.\n *\n * Uses `jiti` under the hood so TypeScript configs work without a\n * separate compilation step.\n *\n * @example\n * ```ts\n * import { Console, Effect } from \"effect\"\n * import { ConfigLoader } from \"./infrastructure/config-loader.js\"\n *\n * const program = Effect.gen(function* () {\n * const loader = yield* ConfigLoader\n * const config = yield* loader.load()\n * yield* Console.log(Object.keys(config.rules))\n * })\n * ```\n *\n * @since 0.1.0\n * @category services\n */\nexport class ConfigLoader extends ServiceMap.Service<\n ConfigLoader,\n {\n /** Discover and import the config file from the working directory. */\n load(): Effect.Effect<AgentReviewConfig, ConfigError>;\n }\n>()(\"agentreview/ConfigLoader\") {\n static readonly layer: Layer.Layer<ConfigLoader, never, FileSystem.FileSystem | Path.Path | Env> = Layer.effect(\n ConfigLoader,\n Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n return ConfigLoader.of({\n load: () =>\n Effect.gen(function* () {\n const configPath = yield* discoverConfig(fs, path, env.cwd);\n\n const config = yield* Effect.tryPromise({\n try: async () => {\n const { createJiti } = await import(\"jiti\");\n const jiti = createJiti(import.meta.url, {\n interopDefault: true,\n });\n const loaded = await jiti.import(configPath);\n return (loaded as { default?: AgentReviewConfig }).default ?? (loaded as AgentReviewConfig);\n },\n catch: (error) =>\n new ConfigError({\n message: error instanceof Error ? error.message : String(error),\n }),\n });\n\n if (!config || typeof config !== \"object\" || !(\"rules\" in config)) {\n return yield* new ConfigError({\n message: `Invalid config at ${configPath}: must export an object with a \"rules\" field`,\n });\n }\n\n return config;\n }),\n });\n }),\n );\n}\n","/**\n * Local state store for tracking reviewed flags.\n *\n * Manages a `.agentreview-state` file in the project root that stores\n * hashes of flags that have been reviewed. This file is intended to\n * be **gitignored** — it is per-developer scratch state for tracking\n * progress during review sweeps.\n *\n * **Caveats**:\n * - Hashes encode file path, line, column, and message. Editing code\n * above a reviewed flag shifts its position and invalidates the hash.\n * This is by design — changed context should be re-reviewed.\n * - Stale hashes (from flags that no longer exist) accumulate harmlessly.\n * Use `agentreview review --reset` to start fresh.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, HashSet, Layer, Path } from \"effect\";\nimport * as ServiceMap from \"effect/ServiceMap\";\nimport { Env } from \"../../config/env.js\";\n\n/**\n * The filename used for local review state.\n *\n * @since 0.1.0\n * @category constants\n */\nconst STATE_FILENAME = \".agentreview-state\";\n\n/**\n * Parse the state file into a set of hashes.\n * Tolerates blank lines and `#`-prefixed comments.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction parseStateFile(content: string): HashSet.HashSet<string> {\n let hashes: HashSet.HashSet<string> = HashSet.empty();\n for (const raw of content.split(\"\\n\")) {\n const line = raw.trim();\n if (line.length > 0 && !line.startsWith(\"#\")) {\n hashes = HashSet.add(hashes, line);\n }\n }\n return hashes;\n}\n\n/**\n * Serialize a set of hashes into file content.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction serializeHashes(hashes: HashSet.HashSet<string>): string {\n return [...hashes].join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Effect service for loading and persisting reviewed-flag state.\n *\n * @since 0.1.0\n * @category services\n */\nexport class StateStore extends ServiceMap.Service<\n StateStore,\n {\n /** Load reviewed hashes from `.agentreview-state`. Returns an empty set if the file is missing. */\n load(): Effect.Effect<HashSet.HashSet<string>>;\n /** Append one or more hashes to `.agentreview-state`, deduplicating against existing entries. */\n append(hashes: ReadonlyArray<string>): Effect.Effect<void>;\n /** Delete the `.agentreview-state` file entirely. */\n reset(): Effect.Effect<void>;\n }\n>()(\"agentreview/StateStore\") {\n /**\n * Default layer — resolves the state file path from `Env.cwd`.\n *\n * @since 0.1.0\n * @category layers\n */\n static readonly layer: Layer.Layer<StateStore, never, FileSystem.FileSystem | Path.Path | Env> = Layer.unwrap(\n Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const statePath = path.resolve(env.cwd, STATE_FILENAME);\n\n return Layer.succeed(\n StateStore,\n StateStore.of({\n load: () =>\n fs.exists(statePath).pipe(\n Effect.orElseSucceed(() => false),\n Effect.flatMap((exists) =>\n exists\n ? fs.readFileString(statePath).pipe(\n Effect.map(parseStateFile),\n Effect.orElseSucceed(() => HashSet.empty<string>()),\n )\n : Effect.succeed(HashSet.empty<string>()),\n ),\n ),\n\n append: (hashes) =>\n fs.exists(statePath).pipe(\n Effect.orElseSucceed(() => false),\n Effect.flatMap((exists) =>\n exists\n ? fs.readFileString(statePath).pipe(\n Effect.map(parseStateFile),\n Effect.orElseSucceed(() => HashSet.empty<string>()),\n )\n : Effect.succeed(HashSet.empty<string>()),\n ),\n Effect.map((existing) => hashes.reduce((acc, h) => HashSet.add(acc, h), existing)),\n Effect.flatMap((merged) =>\n fs.writeFileString(statePath, serializeHashes(merged)).pipe(Effect.orElseSucceed(() => {})),\n ),\n ),\n\n reset: () =>\n fs.exists(statePath).pipe(\n Effect.orElseSucceed(() => false),\n Effect.flatMap((exists) =>\n exists ? fs.remove(statePath).pipe(Effect.orElseSucceed(() => {})) : Effect.void,\n ),\n ),\n }),\n );\n }),\n );\n}\n","/**\n * FNV-1a hashing utility.\n *\n * Produces a 7-character hex digest used for stable, deterministic\n * flag identification. The hash encodes rule name, file path, position,\n * and message so that identical matches across runs share the same id.\n *\n * @see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function\n *\n * @module\n * @since 0.1.0\n */\n\n/**\n * FNV-1a 32-bit offset basis.\n *\n * @since 0.1.0\n * @category constants\n */\nconst FNV_OFFSET_BASIS = 0x811c9dc5;\n\n/**\n * FNV-1a 32-bit prime multiplier.\n *\n * @since 0.1.0\n * @category constants\n */\nconst FNV_PRIME = 0x01000193;\n\n/**\n * Compute a 7-character hex FNV-1a hash of `input`.\n *\n * The result is the first 7 hex characters of the unsigned 32-bit\n * FNV-1a digest — short enough for display, long enough to avoid\n * collisions in typical lint runs.\n *\n * @example\n * ```ts\n * import { fnv1a7 } from \"./utils/hash.js\"\n *\n * fnv1a7(\"my-rule:src/index.ts:10:1:message\") // => \"a3f4b2c\"\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function fnv1a7(input: string): string {\n let hash = FNV_OFFSET_BASIS;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = Math.imul(hash, FNV_PRIME);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\").slice(0, 7);\n}\n","/**\n * Rule context — the interface rules use to interact with the runner.\n *\n * Provides file metadata, source access, and the {@link RuleContext.flag}\n * method for recording matches.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { fnv1a7 } from \"./hash.js\";\nimport { type FlagOptions, FlagRecord } from \"./flag.js\";\n\n/**\n * Context object passed to `createOnce`. Available throughout the rule's lifecycle.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface RuleContext {\n /** Absolute path of the current file being analyzed. */\n getFilename(): string;\n /** Full source content of the current file. */\n getSourceCode(): string;\n /**\n * Lines around the given 1-based line number, formatted with line numbers.\n * @param line 1-based line number\n * @param radius number of lines above/below to include (default 10)\n */\n getLinesAround(line: number, radius?: number): string;\n /** Record a match for the output report. */\n flag(options: FlagOptions): void;\n}\n\n/**\n * Internal implementation of {@link RuleContext}.\n *\n * Tracks the current file, accumulates flags, and provides source\n * access helpers. The check command calls {@link setFile} before each\n * file and {@link drainFlags} after the tree walk to collect results.\n *\n * @since 0.1.0\n * @category internals\n */\nexport class RuleContextImpl implements RuleContext {\n readonly ruleName: string;\n readonly flags: FlagRecord[] = [];\n\n #filename = \"\";\n #source = \"\";\n\n constructor(ruleName: string) {\n this.ruleName = ruleName;\n }\n\n /**\n * Set the current file context. Called by the check command before\n * each file is walked.\n */\n setFile(filename: string, source: string): void {\n this.#filename = filename;\n this.#source = source;\n }\n\n /**\n * Remove and return all accumulated flags. Called after the tree\n * walk for each file to collect results.\n */\n drainFlags(): FlagRecord[] {\n return this.flags.splice(0);\n }\n\n getFilename(): string {\n return this.#filename;\n }\n\n getSourceCode(): string {\n return this.#source;\n }\n\n getLinesAround(line: number, radius = 10): string {\n const lines = this.#source.split(\"\\n\");\n const start = Math.max(0, line - 1 - radius);\n const end = Math.min(lines.length, line + radius);\n return lines\n .slice(start, end)\n .map((l, i) => `${String(start + i + 1).padStart(4)} | ${l}`)\n .join(\"\\n\");\n }\n\n flag(options: FlagOptions): void {\n const line = options.node.startPosition.row + 1;\n const col = options.node.startPosition.column + 1;\n const sourceLines = this.#source.split(\"\\n\");\n const rawLine = sourceLines[line - 1] ?? \"\";\n const trimmed = rawLine.trim();\n const sourceSnippet = trimmed.length > 100 ? trimmed.slice(0, 97) + \"...\" : trimmed;\n\n const hash = fnv1a7(`${this.ruleName}:${this.#filename}:${line}:${col}:${options.message}`);\n\n this.flags.push(\n new FlagRecord({\n ruleName: this.ruleName,\n filename: this.#filename,\n line,\n col,\n message: options.message,\n sourceSnippet,\n hash,\n instruction: options.instruction,\n suggest: options.suggest,\n }),\n );\n }\n}\n","/**\n * File resolution service.\n *\n * Determines which files to lint by applying the 6-layer filter pipeline:\n * 1. Candidate files (from git diff or all files)\n * 2. Built-in ignores\n * 3. .gitignore\n * 4. .agentreviewignore\n * 5. Config include/ignore\n * (Steps 2-4 are handled by IgnoreReader)\n *\n * Per-rule filtering (languages, include, ignore) is done by the check command.\n *\n * @module\n */\n\nimport { Effect, FileSystem, HashSet, Path, Schema } from \"effect\";\nimport { Env } from \"../../config/env.js\";\nimport picomatch from \"picomatch\";\n\n/**\n * Raised when file resolution fails — e.g. a git error bubbling up\n * from the changed-files query.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class FileResolverError extends Schema.TaggedErrorClass<FileResolverError>()(\"FileResolverError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Options controlling which files enter the lint pipeline.\n *\n * @since 0.1.0\n * @category models\n */\nexport const ResolveOptions = Schema.Struct({\n /** When `true`, scan all files instead of only git-changed files. */\n all: Schema.Boolean,\n /** Git ref to diff against. Defaults to the detected default branch. */\n baseRef: Schema.optional(Schema.String),\n /** Global include globs from the config file. */\n configInclude: Schema.optional(Schema.Array(Schema.String)),\n /** Global ignore globs from the config file. */\n configIgnore: Schema.optional(Schema.Array(Schema.String)),\n /** Explicit file paths passed as CLI positional arguments. */\n positionalFiles: Schema.optional(Schema.Array(Schema.String)),\n});\n\n/** @since 0.1.0 */\nexport type ResolveOptions = Schema.Schema.Type<typeof ResolveOptions>;\n\n/** Directories that are always skipped during recursive listing. */\nconst SKIP_DIRS: HashSet.HashSet<string> = HashSet.make(\"node_modules\", \".git\", \"dist\");\n\n/**\n * Recursively list all files under `dir`, returning paths relative to `base`.\n *\n * Skips `node_modules`, `.git`, and `dist` directories. Errors (e.g.\n * permission denied) are silently swallowed.\n *\n * Uses the Effect `FileSystem` and `Path` services for cross-platform\n * file system access.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction listAllFiles(dir: string, base: string, fs: FileSystem.FileSystem, path: Path.Path): Effect.Effect<string[]> {\n return Effect.gen(function* () {\n const entries = yield* fs.readDirectory(dir);\n const results: string[] = [];\n\n for (const name of entries) {\n if (HashSet.has(SKIP_DIRS, name)) continue;\n\n const fullPath = path.resolve(dir, name);\n const info = yield* fs.stat(fullPath);\n const relPath = path.relative(base, fullPath).replace(/\\\\/g, \"/\");\n\n if (info.type === \"Directory\") {\n results.push(...(yield* listAllFiles(fullPath, base, fs, path)));\n } else {\n results.push(relPath);\n }\n }\n\n return results;\n }).pipe(Effect.catch(() => Effect.succeed([] as string[])));\n}\n\n/**\n * Determine the final set of files to lint.\n *\n * Applies the multi-layer filter pipeline described in the module header,\n * then sorts the result alphabetically for deterministic output.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function resolveFiles(\n options: ResolveOptions,\n ignoreReader: { isIgnored(path: string): boolean },\n gitService: {\n changedFiles(baseRef?: string): Effect.Effect<ReadonlyArray<string>, any>;\n },\n): Effect.Effect<ReadonlyArray<string>, FileResolverError, FileSystem.FileSystem | Path.Path | Env> {\n return Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const { cwd } = env;\n let candidates: string[];\n\n if (options.positionalFiles && options.positionalFiles.length > 0) {\n candidates = [...options.positionalFiles];\n } else if (options.all) {\n candidates = yield* listAllFiles(cwd, cwd, fs, path);\n } else {\n const changed = yield* Effect.mapError(\n gitService.changedFiles(options.baseRef),\n (e) => new FileResolverError({ message: `Git error: ${e}` }),\n );\n candidates = [...changed];\n }\n\n const includeMatcher = options.configInclude?.length ? picomatch(options.configInclude as string[]) : undefined;\n const ignoreMatcher = options.configIgnore?.length ? picomatch(options.configIgnore as string[]) : undefined;\n\n return candidates\n .filter((f) => !ignoreReader.isIgnored(f))\n .filter((f) => !includeMatcher || includeMatcher(f))\n .filter((f) => !ignoreMatcher || !ignoreMatcher(f))\n .filter((f) => path.extname(f).length > 0)\n .toSorted();\n });\n}\n","/**\n * Git integration — default branch detection and changed file collection.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, HashSet, Layer, Schema } from \"effect\";\nimport * as ServiceMap from \"effect/ServiceMap\";\nimport { Env } from \"../../config/env.js\";\nimport { ChildProcess, ChildProcessSpawner } from \"effect/unstable/process\";\n\n/**\n * Raised when a git operation fails — e.g. not a git repo,\n * invalid ref, or `git` binary not found.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class GitError extends Schema.TaggedErrorClass<GitError>()(\"GitError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Execute a git command and return trimmed stdout.\n *\n * Uses the array form of `ChildProcess.make` so that dynamic arguments\n * are properly tokenized.\n *\n * @since 0.1.0\n * @category internals\n */\nconst gitCmd = (args: string, cwd: string) =>\n Effect.gen(function* () {\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n return (yield* spawner.string(ChildProcess.make(\"git\", args.split(/\\s+/), { cwd }))).trim();\n });\n\n/**\n * Detect the default branch by checking whether `main` or `master` exists.\n * Falls back to `\"main\"` when neither can be verified.\n *\n * @since 0.1.0\n * @category internals\n */\nconst detectDefault = (cwd: string) =>\n gitCmd(\"rev-parse --verify main\", cwd).pipe(\n Effect.map(() => \"main\" as string),\n Effect.catch(() =>\n gitCmd(\"rev-parse --verify master\", cwd).pipe(\n Effect.map(() => \"master\" as string),\n Effect.catch(() => Effect.succeed(\"main\" as string)),\n ),\n ),\n );\n\n/**\n * Collect all files that differ from `baseRef`.\n *\n * Gathers the union of committed diffs, uncommitted changes, and\n * untracked files. Each source is caught so partial failures\n * (e.g. empty repo, no merge-base) are silently skipped.\n *\n * @since 0.1.0\n * @category internals\n */\nconst parseLines = (output: string): ReadonlyArray<string> =>\n output\n .split(\"\\n\")\n .map((f) => f.trim())\n .filter((f) => f.length > 0);\n\nconst collectChangedFiles = (cwd: string, baseRef: string) =>\n Effect.all([\n // Committed changes since merge-base\n gitCmd(`merge-base HEAD ${baseRef}`, cwd).pipe(\n Effect.flatMap((mergeBase) => gitCmd(`diff --name-only ${mergeBase}...HEAD`, cwd)),\n Effect.catch(() => Effect.succeed(\"\")),\n ),\n // Uncommitted changes\n gitCmd(\"diff --name-only HEAD\", cwd).pipe(Effect.catch(() => Effect.succeed(\"\"))),\n // Untracked files\n gitCmd(\"ls-files --others --exclude-standard\", cwd).pipe(Effect.catch(() => Effect.succeed(\"\"))),\n ]).pipe(\n Effect.map(([committed, uncommitted, untracked]) =>\n [\n ...HashSet.fromIterable([...parseLines(committed), ...parseLines(uncommitted), ...parseLines(untracked)]),\n ].toSorted(),\n ),\n );\n\n/**\n * @example\n * ```ts\n * import { Console, Effect } from \"effect\"\n * import { Git } from \"./infrastructure/git.js\"\n *\n * const program = Effect.gen(function* () {\n * const git = yield* Git\n * const branch = yield* git.detectDefaultBranch()\n * const changed = yield* git.changedFiles(branch)\n * yield* Console.log(`${changed.length} files changed since ${branch}`)\n * })\n * ```\n *\n * @since 0.1.0\n */\nexport class Git extends ServiceMap.Service<\n Git,\n {\n /** Detect whether the default branch is `main` or `master`. */\n detectDefaultBranch(): Effect.Effect<string, GitError>;\n /** Return sorted list of files changed relative to `baseRef` (defaults to the detected default branch). */\n changedFiles(baseRef?: string): Effect.Effect<ReadonlyArray<string>, GitError>;\n }\n>()(\"agentreview/Git\") {\n static readonly layer: Layer.Layer<Git, never, ChildProcessSpawner.ChildProcessSpawner | Env> = Layer.effect(\n Git,\n Effect.gen(function* () {\n const env = yield* Env;\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const provide = <A, E>(effect: Effect.Effect<A, E, ChildProcessSpawner.ChildProcessSpawner>) =>\n Effect.provideService(effect, ChildProcessSpawner.ChildProcessSpawner, spawner);\n\n return Git.of({\n detectDefaultBranch: () =>\n provide(detectDefault(env.cwd)).pipe(Effect.mapError((e) => new GitError({ message: String(e) }))),\n\n changedFiles: (baseRef) =>\n (baseRef ? Effect.succeed(baseRef) : provide(detectDefault(env.cwd))).pipe(\n Effect.flatMap((base) => provide(collectChangedFiles(env.cwd, base))),\n Effect.mapError((e) => new GitError({ message: String(e) })),\n ),\n });\n }),\n );\n}\n","/**\n * Ignore-pattern aggregation service.\n *\n * Merges built-in ignore patterns (e.g. `node_modules`, `dist`) with\n * the project's `.gitignore` to produce a single `isIgnored` predicate.\n * Patterns are compiled once via `picomatch` and reused for every file.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, Layer, Path } from \"effect\";\nimport * as ServiceMap from \"effect/ServiceMap\";\nimport { Env } from \"../../config/env.js\";\nimport picomatch from \"picomatch\";\n\n/**\n * Paths that are always ignored regardless of user configuration.\n *\n * Covers common build output, package manager artifacts, source maps,\n * lockfiles, and cache directories.\n *\n * @since 0.1.0\n * @category constants\n */\nconst BUILTIN_IGNORE_PATTERNS = [\n \"node_modules/**\",\n \"dist/**\",\n \"build/**\",\n \".git/**\",\n \".next/**\",\n \".cache/**\",\n \"coverage/**\",\n \"**/*.min.js\",\n \"**/*.min.css\",\n \"**/*.map\",\n \"**/*.lock\",\n \"**/*.log\",\n \"**/*.tsbuildinfo\",\n \".agentreview-state\",\n];\n\n/**\n * Parse a `.gitignore`-style file into an array of glob patterns.\n * Strips blank lines and comments (lines starting with `#`).\n *\n * @since 0.1.0\n * @category internals\n */\nfunction parseIgnoreFile(content: string): ReadonlyArray<string> {\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && !line.startsWith(\"#\"));\n}\n\n/**\n * Effect service that tests whether a file path should be ignored.\n *\n * Combines built-in patterns with `.gitignore` into a single\n * `picomatch` matcher. Constructed once per run.\n *\n * @since 0.1.0\n * @category services\n */\nexport class IgnoreReader extends ServiceMap.Service<\n IgnoreReader,\n {\n /** Returns `true` if `filepath` matches any built-in or `.gitignore` pattern. */\n isIgnored(filepath: string): boolean;\n }\n>()(\"agentreview/IgnoreReader\") {\n static readonly layer: Layer.Layer<IgnoreReader, never, FileSystem.FileSystem | Path.Path | Env> = Layer.unwrap(\n Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const { cwd } = env;\n const gitignorePath = path.resolve(cwd, \".gitignore\");\n\n const gitignoreExists = yield* fs.exists(gitignorePath).pipe(Effect.orElseSucceed(() => false));\n const gitignorePatterns: ReadonlyArray<string> = gitignoreExists\n ? parseIgnoreFile(yield* fs.readFileString(gitignorePath).pipe(Effect.orElseSucceed(() => \"\")))\n : [];\n\n const allPatterns = [...BUILTIN_IGNORE_PATTERNS, ...gitignorePatterns];\n const matcher = picomatch(allPatterns, { dot: true });\n\n return Layer.succeed(\n IgnoreReader,\n IgnoreReader.of({\n isIgnored: (filepath) => matcher(filepath),\n }),\n );\n }),\n );\n}\n","/**\n * Tree-sitter WASM parser.\n *\n * WASM init is lazy — the first `parse` call triggers initialization.\n * Grammars are cached after first load.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, HashMap, Layer, Option, Path, Schema } from \"effect\";\nimport * as ServiceMap from \"effect/ServiceMap\";\nimport { Env } from \"../../config/env.js\";\nimport { Language, Parser as TSParser, type Tree } from \"web-tree-sitter\";\n\n/**\n * Raised when parsing fails — e.g. missing grammar, corrupt WASM, or\n * tree-sitter returning a null tree.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class ParserError extends Schema.TaggedErrorClass<ParserError>()(\"ParserError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Maps grammar names to their corresponding `.wasm` filenames.\n *\n * @since 0.1.0\n * @category constants\n */\nconst GRAMMAR_FILES: HashMap.HashMap<string, string> = HashMap.make(\n [\"typescript\", \"tree-sitter-typescript.wasm\"],\n [\"tsx\", \"tree-sitter-tsx.wasm\"],\n [\"javascript\", \"tree-sitter-javascript.wasm\"],\n);\n\n/**\n * @example\n * ```ts\n * import { Console, Effect } from \"effect\"\n * import { Parser } from \"./infrastructure/parser.js\"\n *\n * const program = Effect.gen(function* () {\n * const parser = yield* Parser\n * const tree = yield* parser.parse(\"const x = 1\", \"typescript\")\n * yield* Console.log(tree.rootNode.type) // \"program\"\n * })\n * ```\n *\n * @since 0.1.0\n * @category services\n */\nexport class Parser extends ServiceMap.Service<\n Parser,\n {\n parse(source: string, grammar: string): Effect.Effect<Tree, ParserError>;\n }\n>()(\"agentreview/Parser\") {\n /** Default layer — lazily initializes WASM and caches grammars. */\n static readonly layer: Layer.Layer<Parser, never, FileSystem.FileSystem | Path.Path | Env> = Layer.effect(\n Parser,\n Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n const resolveWasmPath = (filename: string): Effect.Effect<string, ParserError> =>\n Effect.gen(function* () {\n const thisDir = path.dirname(path.resolve(import.meta.dirname ?? \".\", \"\"));\n const distPath = path.resolve(thisDir, \"wasm\", filename);\n if (yield* fs.exists(distPath).pipe(Effect.orElseSucceed(() => false))) return distPath;\n\n const nmBase = path.resolve(env.cwd, \"node_modules\");\n if (filename === \"tree-sitter.wasm\") {\n const p = path.resolve(nmBase, \"web-tree-sitter\", filename);\n if (yield* fs.exists(p).pipe(Effect.orElseSucceed(() => false))) return p;\n } else {\n const p = path.resolve(nmBase, \"tree-sitter-wasms\", \"out\", filename);\n if (yield* fs.exists(p).pipe(Effect.orElseSucceed(() => false))) return p;\n }\n\n return yield* new ParserError({ message: `WASM file not found: ${filename}` });\n });\n\n let parserInstance: TSParser | undefined;\n let languageCache: HashMap.HashMap<string, Language> = HashMap.empty();\n\n return Parser.of({\n parse: (source, grammar) =>\n Effect.gen(function* () {\n if (!parserInstance) {\n const initPath = yield* resolveWasmPath(\"tree-sitter.wasm\");\n yield* Effect.tryPromise({\n try: async () => {\n await TSParser.init({ locateFile: () => initPath });\n parserInstance = new TSParser();\n },\n catch: (error) => new ParserError({ message: error instanceof Error ? error.message : String(error) }),\n });\n }\n\n let lang = Option.getOrUndefined(HashMap.get(languageCache, grammar));\n if (!lang) {\n const file = Option.getOrUndefined(HashMap.get(GRAMMAR_FILES, grammar));\n if (!file) return yield* new ParserError({ message: `Unknown grammar: ${grammar}` });\n\n const wasmPath = yield* resolveWasmPath(file);\n lang = yield* Effect.tryPromise({\n try: () => Language.load(wasmPath),\n catch: (error) => new ParserError({ message: error instanceof Error ? error.message : String(error) }),\n });\n languageCache = HashMap.set(languageCache, grammar, lang);\n }\n\n parserInstance!.setLanguage(lang);\n const tree = parserInstance!.parse(source);\n if (!tree) return yield* new ParserError({ message: \"Parser returned null tree\" });\n return tree;\n }),\n });\n }),\n );\n}\n","/**\n * Single-pass multi-rule tree walker.\n *\n * Builds a dispatch table from all active rules' visitor methods,\n * walks the tree once using tree-sitter's cursor API, and calls\n * all matching handlers per node.\n *\n * @module\n */\n\nimport { Effect, HashMap, Option } from \"effect\";\nimport type { Tree, TreeCursor } from \"web-tree-sitter\";\nimport { type AgentReviewNode, wrapNode } from \"../../domain/node.js\";\nimport type { FlagRecord } from \"../../domain/flag.js\";\nimport type { VisitorHandler, Visitors } from \"../../domain/rule.js\";\nimport type { RuleContextImpl } from \"../../domain/rule-context.js\";\n\n/**\n * Regex matching `agentreview-ignore` comments.\n *\n * Captures an optional rule name after the directive:\n * - `// agentreview-ignore` → suppresses all rules on the next line\n * - `// agentreview-ignore my-rule` → suppresses only `my-rule`\n *\n * @since 0.1.0\n * @category constants\n */\nconst IGNORE_PATTERN = /agentreview-ignore(?:\\s+(\\S+))?/;\n\n/**\n * Internal binding of a rule to its context and visitors for a walk pass.\n *\n * @since 0.1.0\n * @category models\n */\ninterface RuleEntry {\n readonly ruleName: string;\n readonly context: RuleContextImpl;\n readonly visitors: Visitors;\n}\n\n/**\n * A single handler entry in the dispatch table, keyed by node type.\n *\n * @since 0.1.0\n * @category models\n */\ninterface DispatchHandler {\n readonly ruleName: string;\n readonly handler: VisitorHandler;\n}\n\n/**\n * Records an `agentreview-ignore` comment that suppresses a specific\n * rule (or all rules) on the immediately following line.\n *\n * @since 0.1.0\n * @category models\n */\ninterface Suppression {\n /** Rule name, or `\"*\"` for all rules. */\n readonly ruleName: string;\n /** 0-indexed line number of the *comment* (the suppressed line is `line + 1`). */\n readonly line: number;\n}\n\n/**\n * Walk files with the given rules, collecting all flags.\n *\n * Call this once per file. The caller is responsible for:\n * - Calling `context.setFile()` before this function\n * - Calling `before()` and filtering out skipped rules\n * - Calling `after()` after all files are processed\n *\n * @internal\n */\nexport function walkFile(tree: Tree, rules: ReadonlyArray<RuleEntry>): ReadonlyArray<FlagRecord> {\n const dispatchTable: HashMap.HashMap<string, DispatchHandler[]> = HashMap.mutate(\n HashMap.empty<string, DispatchHandler[]>(),\n (m) => {\n for (const entry of rules) {\n for (const key of Object.keys(entry.visitors)) {\n if (key === \"before\" || key === \"after\") continue;\n const handler = entry.visitors[key];\n if (typeof handler !== \"function\") continue;\n\n const existing = Option.getOrUndefined(HashMap.get(m, key));\n if (existing) {\n existing.push({ ruleName: entry.ruleName, handler: handler as VisitorHandler });\n } else {\n HashMap.set(m, key, [{ ruleName: entry.ruleName, handler: handler as VisitorHandler }]);\n }\n }\n }\n },\n );\n\n const suppressions: Suppression[] = [];\n\n const cursor: TreeCursor = tree.walk();\n let reachedEnd = false;\n\n while (!reachedEnd) {\n const nodeType = cursor.nodeType;\n\n if (nodeType === \"comment\") {\n const node = cursor.currentNode;\n const match = IGNORE_PATTERN.exec(node.text);\n if (match) {\n const ruleNameArg = match[1];\n const ruleName = ruleNameArg?.split(\"--\")[0]?.trim() ?? \"*\";\n suppressions.push({\n ruleName,\n line: node.startPosition.row + 1,\n });\n }\n }\n\n const handlers = Option.getOrUndefined(HashMap.get(dispatchTable, nodeType));\n if (handlers) {\n const wrapped: AgentReviewNode = wrapNode(cursor.currentNode);\n for (const { handler } of handlers) {\n handler(wrapped);\n }\n }\n\n if (cursor.gotoFirstChild()) continue;\n while (!cursor.gotoNextSibling()) {\n if (!cursor.gotoParent()) {\n reachedEnd = true;\n break;\n }\n }\n }\n\n const allFlags: FlagRecord[] = [];\n for (const entry of rules) {\n allFlags.push(...entry.context.drainFlags());\n }\n\n if (suppressions.length === 0) return allFlags;\n\n return allFlags.filter((flag) => {\n const flagLine0 = flag.line - 1;\n return !suppressions.some((s) => (s.ruleName === \"*\" || s.ruleName === flag.ruleName) && s.line === flagLine0);\n });\n}\n\n/**\n * Effect wrapper around {@link walkFile}.\n *\n * Runs the tree walk synchronously inside `Effect.sync`, making it\n * composable with the rest of the Effect pipeline.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function walkFileEffect(tree: Tree, rules: ReadonlyArray<RuleEntry>): Effect.Effect<ReadonlyArray<FlagRecord>> {\n return Effect.sync(() => walkFile(tree, rules));\n}\n","/**\n * File extension → tree-sitter grammar mapping.\n *\n * Maps every supported file extension to the grammar name used by\n * the parser service. This is the single source of truth for which\n * file types agentreview can analyze.\n *\n * Uses Effect `HashMap` for an immutable, structurally-equal lookup table.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { HashMap, Option } from \"effect\";\n\n/**\n * Maps file extensions (without leading dot) to their tree-sitter\n * grammar name.\n *\n * @since 0.1.0\n * @category constants\n */\nconst EXTENSION_TO_GRAMMAR: HashMap.HashMap<string, string> = HashMap.make(\n [\"ts\", \"typescript\"],\n [\"tsx\", \"tsx\"],\n [\"js\", \"javascript\"],\n [\"jsx\", \"javascript\"],\n [\"mts\", \"typescript\"],\n [\"cts\", \"typescript\"],\n [\"mjs\", \"javascript\"],\n [\"cjs\", \"javascript\"],\n);\n\n/**\n * Look up the tree-sitter grammar name for a file extension.\n *\n * Returns `undefined` for unsupported extensions — callers should\n * skip those files.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function grammarForExtension(ext: string): string | undefined {\n return Option.getOrUndefined(HashMap.get(EXTENSION_TO_GRAMMAR, ext));\n}\n\n/**\n * Return all file extensions that agentreview can parse.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function supportedExtensions(): ReadonlyArray<string> {\n return [...HashMap.keys(EXTENSION_TO_GRAMMAR)];\n}\n","/**\n * Flag collection pipeline — shared between `check` and `review`.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, Path, Schema } from \"effect\";\nimport picomatch from \"picomatch\";\nimport { Env } from \"../../config/env.js\";\nimport { FlagRecord } from \"../../domain/flag.js\";\nimport type { AgentReviewRule, Visitors } from \"../../domain/rule.js\";\nimport { RuleContextImpl } from \"../../domain/rule-context.js\";\nimport { ConfigLoader } from \"../infrastructure/config-loader.js\";\nimport { resolveFiles } from \"./file-resolver.js\";\nimport { Git } from \"../infrastructure/git.js\";\nimport { IgnoreReader } from \"../infrastructure/ignore-reader.js\";\nimport { Parser } from \"../infrastructure/parser.js\";\nimport { walkFile } from \"./tree-walker.js\";\nimport { grammarForExtension } from \"./language-map.js\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport const CollectResult = Schema.Struct({\n /** Collected flags. */\n flags: Schema.Array(FlagRecord),\n /** `true` when the `--rule` filter matched no registered rules. */\n noMatchingRules: Schema.Boolean,\n});\n\n/** @since 0.1.0 */\nexport type CollectResult = Schema.Schema.Type<typeof CollectResult>;\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport const CollectOptions = Schema.Struct({\n /** When `true`, scan all files instead of only git-changed files. */\n all: Schema.Boolean,\n /** Rule name filter. Empty array means \"run all rules\". */\n rules: Schema.Array(Schema.String),\n /** When `true`, suppress instruction and hint blocks in output. */\n dryRun: Schema.Boolean,\n /** Git ref to diff against. `undefined` means auto-detect. */\n base: Schema.UndefinedOr(Schema.String),\n /** Explicit file paths from positional CLI arguments. */\n files: Schema.Array(Schema.String),\n});\n\n/** @since 0.1.0 */\nexport type CollectOptions = Schema.Schema.Type<typeof CollectOptions>;\n\n/** @since 0.1.0 */\nexport const collectFlags = Effect.fn(\"collectFlags\")(function* (\n options: CollectOptions,\n): Generator<any, CollectResult> {\n const configLoader = yield* ConfigLoader;\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const ignoreReader = yield* IgnoreReader;\n const gitService = yield* Git;\n const parserService = yield* Parser;\n\n const config = yield* configLoader.load();\n\n let activeRules: Array<[string, AgentReviewRule]> = Object.entries(config.rules);\n if (options.rules.length > 0) {\n activeRules = activeRules.filter(([name]) => options.rules.includes(name));\n if (activeRules.length === 0) return { flags: [], noMatchingRules: true };\n }\n\n const includePatterns = config.include ? [...config.include] : undefined;\n const ignorePatterns = config.ignore ? [...config.ignore] : undefined;\n\n const files = yield* resolveFiles(\n {\n all: options.all,\n baseRef: options.base,\n configInclude: includePatterns,\n configIgnore: ignorePatterns,\n positionalFiles: options.files.length > 0 ? [...options.files] : undefined,\n },\n ignoreReader,\n gitService,\n );\n\n if (files.length === 0) return { flags: [], noMatchingRules: false };\n\n const ruleEntries: Array<{\n name: string;\n rule: AgentReviewRule;\n context: RuleContextImpl;\n visitors: Visitors;\n }> = [];\n\n for (const [name, rule] of activeRules) {\n const context = new RuleContextImpl(name);\n const visitors = rule.createOnce(context);\n ruleEntries.push({ name, rule, context, visitors });\n }\n\n const allFlags: FlagRecord[] = [];\n\n for (const file of files) {\n const ext = path.extname(file).slice(1);\n const absPath = path.resolve(env.cwd, file);\n\n const applicableRules = ruleEntries.filter((entry) => {\n if (!entry.rule.meta.languages.includes(ext)) return false;\n\n if (entry.rule.meta.include && entry.rule.meta.include.length > 0) {\n const matcher = picomatch([...entry.rule.meta.include]);\n if (!matcher(file)) return false;\n }\n\n if (entry.rule.meta.ignore && entry.rule.meta.ignore.length > 0) {\n const matcher = picomatch([...entry.rule.meta.ignore]);\n if (matcher(file)) return false;\n }\n\n return true;\n });\n\n if (applicableRules.length === 0) continue;\n\n const sourceResult = yield* fs.readFileString(absPath).pipe(Effect.result);\n if (sourceResult._tag === \"Failure\") continue;\n const source = sourceResult.success;\n\n const grammar = grammarForExtension(ext);\n if (!grammar) continue;\n\n const tree = yield* parserService.parse(source, grammar);\n\n const rulesForFile: Array<{\n ruleName: string;\n context: RuleContextImpl;\n visitors: Visitors;\n }> = [];\n\n for (const entry of applicableRules) {\n entry.context.setFile(absPath, source);\n const beforeResult = entry.visitors.before?.(absPath);\n if (beforeResult === false) continue;\n rulesForFile.push({\n ruleName: entry.name,\n context: entry.context,\n visitors: entry.visitors,\n });\n }\n\n if (rulesForFile.length === 0) continue;\n\n const fileFlags = walkFile(tree, rulesForFile);\n allFlags.push(...fileFlags);\n }\n\n for (const entry of ruleEntries) {\n entry.visitors.after?.();\n }\n\n return { flags: allFlags, noMatchingRules: false };\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport { FlagRecord } from \"../../domain/flag.js\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class CheckCommand extends Schema.TaggedClass<CheckCommand>()(\"CheckCommand\", {\n /** When `true`, scan all files instead of only git-changed files. */\n all: Schema.Boolean,\n /** Rule name filter. Empty array means \"run all rules\". */\n rules: Schema.Array(Schema.String),\n /** When `true`, suppress instruction and hint blocks in output. */\n dryRun: Schema.Boolean,\n /** Git ref to diff against. `undefined` means auto-detect. */\n base: Schema.UndefinedOr(Schema.String),\n /** Explicit file paths from positional CLI arguments. */\n files: Schema.Array(Schema.String),\n}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class CheckResult extends Schema.TaggedClass<CheckResult>()(\"CheckResult\", {\n /** Unreviewed flags to display. */\n flags: Schema.Array(FlagRecord),\n /** Total flags before filtering out reviewed ones. */\n totalFlags: Schema.Number,\n /** Number of flags filtered out because they were previously reviewed. */\n filteredCount: Schema.Number,\n /** `true` when the `--rule` filter matched no registered rules. */\n noMatchingRules: Schema.Boolean,\n /** Available rule names (for error messages when no match). */\n availableRules: Schema.Array(Schema.String),\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, HashSet } from \"effect\";\nimport { ConfigLoader } from \"../../shared/infrastructure/config-loader.js\";\nimport { StateStore } from \"../../shared/infrastructure/state-store.js\";\nimport { collectFlags } from \"../../shared/pipeline/collect-flags.js\";\nimport { CheckCommand, CheckResult } from \"./request.js\";\n\n/** @since 0.1.0 */\nexport const checkHandler = Effect.fn(\"checkHandler\")(function* (command: CheckCommand) {\n const configLoader = yield* ConfigLoader;\n const stateStore = yield* StateStore;\n\n const config = yield* configLoader.load();\n const availableRules = Object.keys(config.rules);\n\n const result = yield* collectFlags({\n all: command.all,\n rules: command.rules,\n dryRun: command.dryRun,\n base: command.base,\n files: command.files,\n });\n\n if (result.noMatchingRules) {\n return new CheckResult({\n flags: [],\n totalFlags: 0,\n filteredCount: 0,\n noMatchingRules: true,\n availableRules,\n });\n }\n\n const allFlags = result.flags;\n\n if (allFlags.length === 0) {\n return new CheckResult({\n flags: [],\n totalFlags: 0,\n filteredCount: 0,\n noMatchingRules: false,\n availableRules,\n });\n }\n\n const reviewed = yield* stateStore.load();\n const reviewedSize = HashSet.size(reviewed);\n const filteredCount = reviewedSize > 0 ? allFlags.filter((f) => HashSet.has(reviewed, f.hash)).length : 0;\n const unreviewedFlags = reviewedSize > 0 ? allFlags.filter((f) => !HashSet.has(reviewed, f.hash)) : allFlags;\n\n return new CheckResult({\n flags: unreviewedFlags,\n totalFlags: allFlags.length,\n filteredCount,\n noMatchingRules: false,\n availableRules,\n });\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class InitCommand extends Schema.TaggedClass<InitCommand>()(\"InitCommand\", {}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class InitResult extends Schema.TaggedClass<InitResult>()(\"InitResult\", {\n /** Whether a new config file was created. */\n created: Schema.Boolean,\n /** Human-readable message describing what happened. */\n message: Schema.String,\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, Path } from \"effect\";\nimport { Env } from \"../../config/env.js\";\nimport { InitCommand, InitResult } from \"./request.js\";\n\n/**\n * Minimal starter config written by `agentreview init`.\n *\n * @since 0.1.0\n * @category constants\n */\nconst STARTER_CONFIG = `import { defineConfig } from \"agentreview\"\n\nexport default defineConfig({\n include: [\"src/**/*.{ts,tsx}\"],\n rules: {},\n})\n`;\n\nconst SKILLS_ADD_CMD = \"npx skills@latest add aurelienbobenrieth/agentreview\";\nconst INTENT_INSTALL_CMD = \"npx @tanstack/intent install\";\n\n/**\n * Detect which skill installation method is most likely appropriate.\n *\n * Checks for TanStack Intent or existing AGENTS.md with intent block.\n */\nconst detectSkillMethod = Effect.fn(\"detectSkillMethod\")(function* (cwd: string) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n // Check if TanStack Intent is installed\n const hasIntent = yield* fs\n .exists(path.resolve(cwd, \"node_modules/@tanstack/intent\"))\n .pipe(Effect.orElseSucceed(() => false));\n\n if (hasIntent) return \"intent\" as const;\n\n // Check if AGENTS.md has an intent-skills block (installed by intent previously)\n const agentsPath = path.resolve(cwd, \"AGENTS.md\");\n if (yield* fs.exists(agentsPath)) {\n const content = yield* fs.readFileString(agentsPath);\n if (content.includes(\"intent-skills:start\")) return \"intent\" as const;\n }\n\n return \"skills\" as const;\n});\n\n/** @since 0.1.0 */\nexport const initHandler = Effect.fn(\"initHandler\")(function* (_command: InitCommand) {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const configPath = path.resolve(env.cwd, \"agentreview.config.ts\");\n\n const gitignorePath = path.resolve(env.cwd, \".gitignore\");\n\n // --- Step 1: Create config ---\n const configCreated = !(yield* fs.exists(configPath));\n if (configCreated) {\n yield* fs.writeFileString(configPath, STARTER_CONFIG);\n }\n\n // --- Step 2: Ensure .agentreview-state is gitignored ---\n let gitignoreUpdated = false;\n const gitignoreExists = yield* fs.exists(gitignorePath);\n if (gitignoreExists) {\n const content = yield* fs.readFileString(gitignorePath);\n if (!content.includes(\".agentreview-state\")) {\n const separator = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n yield* fs.writeFileString(\n gitignorePath,\n content + separator + \"\\n# agentreview local state\\n.agentreview-state\\n\",\n );\n gitignoreUpdated = true;\n }\n } else {\n yield* fs.writeFileString(gitignorePath, \"# agentreview local state\\n.agentreview-state\\n\");\n gitignoreUpdated = true;\n }\n\n const lines: Array<string> = [];\n\n if (configCreated) {\n lines.push(\"✓ Created agentreview.config.ts\");\n } else {\n lines.push(\"· agentreview.config.ts already exists — skipped\");\n }\n\n if (gitignoreUpdated) {\n lines.push(\"✓ Added .agentreview-state to .gitignore\");\n }\n\n // --- Step 2: Next steps ---\n const method = yield* detectSkillMethod(env.cwd);\n const skillCmd = method === \"intent\" ? INTENT_INSTALL_CMD : SKILLS_ADD_CMD;\n\n lines.push(\n \"\",\n \"Next steps:\",\n \" 1. Add rules to your config\",\n ` 2. Install the agentreview skill for your AI agents:`,\n ` ${skillCmd}`,\n \" 3. Run: npx agentreview check --all\",\n );\n\n return new InitResult({\n created: configCreated,\n message: lines.join(\"\\n\"),\n });\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport const RuleSummary = Schema.Struct({\n name: Schema.String,\n description: Schema.String,\n languages: Schema.Array(Schema.String),\n include: Schema.UndefinedOr(Schema.Array(Schema.String)),\n ignore: Schema.UndefinedOr(Schema.Array(Schema.String)),\n});\n\n/** @since 0.1.0 */\nexport type RuleSummary = Schema.Schema.Type<typeof RuleSummary>;\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ListCommand extends Schema.TaggedClass<ListCommand>()(\"ListCommand\", {}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ListResult extends Schema.TaggedClass<ListResult>()(\"ListResult\", {\n /** All registered rules with their metadata. */\n rules: Schema.Array(RuleSummary),\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect } from \"effect\";\nimport { ConfigLoader } from \"../../shared/infrastructure/config-loader.js\";\nimport { ListCommand, ListResult } from \"./request.js\";\n\n/** @since 0.1.0 */\nexport const listHandler = Effect.fn(\"listHandler\")(function* (_command: ListCommand) {\n const configLoader = yield* ConfigLoader;\n const config = yield* configLoader.load();\n\n const rules = Object.entries(config.rules).map(([name, rule]) => ({\n name,\n description: rule.meta.description,\n languages: rule.meta.languages,\n include: rule.meta.include,\n ignore: rule.meta.ignore,\n }));\n\n return new ListResult({ rules });\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ReviewCommand extends Schema.TaggedClass<ReviewCommand>()(\"ReviewCommand\", {\n /** Specific hashes to mark as reviewed. */\n hashes: Schema.Array(Schema.String),\n /** When `true`, mark all current flags as reviewed. */\n all: Schema.Boolean,\n /** When `true`, wipe the state file. */\n reset: Schema.Boolean,\n}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ReviewResult extends Schema.TaggedClass<ReviewResult>()(\"ReviewResult\", {\n /** Human-readable message describing what happened. */\n message: Schema.String,\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect } from \"effect\";\nimport { StateStore } from \"../../shared/infrastructure/state-store.js\";\nimport { collectFlags } from \"../../shared/pipeline/collect-flags.js\";\nimport { ReviewCommand, ReviewResult } from \"./request.js\";\n\n/** @since 0.1.0 */\nexport const reviewHandler = Effect.fn(\"reviewHandler\")(function* (command: ReviewCommand) {\n const stateStore = yield* StateStore;\n\n if (command.reset) {\n yield* stateStore.reset();\n return new ReviewResult({ message: \"Cleared .agentreview-state\" });\n }\n\n if (command.all) {\n const result = yield* collectFlags({\n all: true,\n rules: [],\n dryRun: false,\n base: undefined,\n files: [],\n });\n const allFlags = result.flags;\n if (allFlags.length === 0) {\n return new ReviewResult({ message: \"No flags to review.\" });\n }\n yield* stateStore.append(allFlags.map((f) => f.hash));\n return new ReviewResult({ message: `Marked ${allFlags.length} flag(s) as reviewed.` });\n }\n\n if (command.hashes.length > 0) {\n yield* stateStore.append([...command.hashes]);\n return new ReviewResult({ message: `Marked ${command.hashes.length} hash(es) as reviewed.` });\n }\n\n return new ReviewResult({\n message: [\n \"Usage:\",\n \" agentreview review <hash...> Mark specific flags as reviewed\",\n \" agentreview review --all Mark all current flags as reviewed\",\n \" agentreview review --reset Wipe the state file\",\n ].join(\"\\n\"),\n });\n});\n","/**\n * Terminal reporter — formats flag results into human-readable output.\n *\n * Respects `NO_COLOR` and non-TTY environments. Groups flags by rule,\n * then by file, and appends instruction/hint blocks when available.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, HashMap, Option, Path, Schema } from \"effect\";\nimport { Env } from \"../config/env.js\";\nimport type { FlagRecord } from \"../domain/flag.js\";\nimport type { RuleMeta } from \"../domain/rule.js\";\n\n/**\n * Group an array by a key function, returning a HashMap of arrays.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction groupBy<A>(items: ReadonlyArray<A>, key: (a: A) => string): HashMap.HashMap<string, A[]> {\n return items.reduce((acc, item) => {\n const k = key(item);\n const existing = Option.getOrUndefined(HashMap.get(acc, k));\n return existing ? (existing.push(item), acc) : HashMap.set(acc, k, [item]);\n }, HashMap.empty<string, A[]>());\n}\n\n/**\n * Build the minimal ANSI escape helpers. Each function is a no-op when\n * `noColor` is `true`.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction makeAnsi(noColor: boolean) {\n return {\n bold: (s: string) => (noColor ? s : `\\x1b[1m${s}\\x1b[22m`),\n dim: (s: string) => (noColor ? s : `\\x1b[2m${s}\\x1b[22m`),\n yellow: (s: string) => (noColor ? s : `\\x1b[33m${s}\\x1b[39m`),\n cyan: (s: string) => (noColor ? s : `\\x1b[36m${s}\\x1b[39m`),\n magenta: (s: string) => (noColor ? s : `\\x1b[35m${s}\\x1b[39m`),\n gray: (s: string) => (noColor ? s : `\\x1b[90m${s}\\x1b[39m`),\n underline: (s: string) => (noColor ? s : `\\x1b[4m${s}\\x1b[24m`),\n reset: noColor ? \"\" : \"\\x1b[0m\",\n };\n}\n\n/**\n * Options that control the reporter's output format.\n *\n * @since 0.1.0\n * @category models\n */\nexport const ReporterOptions = Schema.Struct({\n /** When `true`, instruction and hint blocks are suppressed. */\n dryRun: Schema.Boolean,\n /** Version string displayed in the header line. */\n version: Schema.String,\n});\n\n/** @since 0.1.0 */\nexport type ReporterOptions = Schema.Schema.Type<typeof ReporterOptions>;\n\n/**\n * Format flag results into a terminal-friendly report string.\n *\n * Groups flags by rule name, then by file path. Includes source\n * snippets, per-match instructions/hints, and a summary line.\n * Returns a single \"no rules triggered\" line when the flag list\n * is empty.\n *\n * Uses the `Env` service for colour/cwd detection and the Effect\n * `Path` service for cross-platform path resolution.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const formatReport = Effect.fn(\"formatReport\")(function* (\n flags: ReadonlyArray<FlagRecord>,\n rulesMeta: HashMap.HashMap<string, RuleMeta>,\n options: ReporterOptions,\n) {\n const env = yield* Env;\n const path = yield* Path.Path;\n const ansi = makeAnsi(env.noColor);\n\n if (flags.length === 0) {\n return `${ansi.bold(\"agentreview\")} ${ansi.dim(`v${options.version}`)} ${ansi.dim(\"-\")} no rules triggered.`;\n }\n\n const { cwd } = env;\n const lines: string[] = [];\n\n const grouped = groupBy(flags, (f) => f.ruleName);\n\n const groupedSize = HashMap.size(grouped);\n\n if (flags.length > 50) {\n lines.push(\n ansi.yellow(\"⚠\") +\n ` ${flags.length} matches across ${groupedSize} rules. ` +\n ansi.dim(\"Consider narrowing scope with --rule or targeting specific files.\"),\n );\n lines.push(\"\");\n }\n\n for (const [ruleName, ruleFlags] of grouped) {\n const meta = Option.getOrUndefined(HashMap.get(rulesMeta, ruleName));\n\n lines.push(ansi.yellow(` x ${ruleName}`) + ansi.dim(meta ? `: ${meta.description}` : \"\"));\n lines.push(\"\");\n\n const byFile = groupBy(ruleFlags, (f) => path.relative(cwd, f.filename).replace(/\\\\/g, \"/\"));\n\n for (const [_filePath, fileFlags] of byFile) {\n for (const flag of fileFlags) {\n const relPath = path.relative(cwd, flag.filename).replace(/\\\\/g, \"/\");\n const loc = `${relPath}:${flag.line}:${flag.col}`;\n const snippet = flag.sourceSnippet.length > 80 ? flag.sourceSnippet.slice(0, 77) + \"...\" : flag.sourceSnippet;\n\n lines.push(` ${ansi.cyan(loc)} ${ansi.dim(`[${flag.hash}]`)} ${flag.message}`);\n if (snippet && snippet !== flag.message) {\n lines.push(` ${ansi.dim(snippet)}`);\n }\n lines.push(\"\");\n }\n }\n\n if (!options.dryRun && meta?.instruction) {\n lines.push(ansi.dim(\" ┌─ Instruction ─────────────────────────────────\"));\n for (const instrLine of meta.instruction.split(\"\\n\")) {\n lines.push(ansi.dim(` │ ${instrLine}`));\n }\n lines.push(ansi.dim(\" └───────────────────────────────────────────────\"));\n lines.push(\"\");\n }\n\n const matchNotes = ruleFlags.filter((f) => f.instruction || f.suggest);\n if (!options.dryRun && matchNotes.length > 0) {\n for (const flag of matchNotes) {\n const relPath = path.relative(cwd, flag.filename).replace(/\\\\/g, \"/\");\n if (flag.instruction) {\n lines.push(` ${ansi.magenta(\"note\")} ${ansi.dim(`${relPath}:${flag.line}`)} ${flag.instruction}`);\n }\n if (flag.suggest) {\n lines.push(` ${ansi.magenta(\"hint\")} ${ansi.dim(`${relPath}:${flag.line}`)} ${flag.suggest}`);\n }\n }\n lines.push(\"\");\n }\n }\n\n const ruleWord = groupedSize === 1 ? \"rule\" : \"rules\";\n const matchWord = flags.length === 1 ? \"match\" : \"matches\";\n lines.push(ansi.bold(ansi.yellow(`Found ${flags.length} ${matchWord}`)) + ansi.dim(` (${groupedSize} ${ruleWord})`));\n\n return lines.join(\"\\n\");\n});\n","#!/usr/bin/env node\n/**\n * CLI entry point for `agentreview`.\n *\n * Thin adapter that translates CLI arguments into feature commands,\n * dispatches to the appropriate handler, and formats the result\n * for terminal output.\n *\n * @module\n * @since 0.1.0\n */\n\nimport * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as NodeServices from \"@effect/platform-node/NodeServices\";\nimport { Console, Effect, HashMap, Layer, Option } from \"effect\";\nimport { Argument, Command, Flag } from \"effect/unstable/cli\";\nimport { checkHandler } from \"./features/check/handler.js\";\nimport { CheckCommand } from \"./features/check/request.js\";\nimport { initHandler } from \"./features/init/handler.js\";\nimport { InitCommand } from \"./features/init/request.js\";\nimport { listHandler } from \"./features/list/handler.js\";\nimport { ListCommand } from \"./features/list/request.js\";\nimport { reviewHandler } from \"./features/review/handler.js\";\nimport { ReviewCommand } from \"./features/review/request.js\";\nimport { Env } from \"./config/env.js\";\nimport { ConfigLoader } from \"./shared/infrastructure/config-loader.js\";\nimport { Git } from \"./shared/infrastructure/git.js\";\nimport { IgnoreReader } from \"./shared/infrastructure/ignore-reader.js\";\nimport { Parser } from \"./shared/infrastructure/parser.js\";\nimport { StateStore } from \"./shared/infrastructure/state-store.js\";\nimport { formatReport } from \"./cli/reporter.js\";\nimport type { RuleMeta } from \"./domain/rule.js\";\n\ndeclare const __AGENTREVIEW_VERSION__: string;\n\n/** The `check` subcommand — scans files and outputs a report. */\nconst check = Command.make(\n \"check\",\n {\n files: Argument.string(\"files\").pipe(\n Argument.withDescription(\"Specific files or globs to scan\"),\n Argument.variadic(),\n ),\n all: Flag.boolean(\"all\").pipe(Flag.withAlias(\"a\"), Flag.withDescription(\"Scan all files (not just git diff)\")),\n rule: Flag.string(\"rule\").pipe(\n Flag.withAlias(\"r\"),\n Flag.withDescription(\"Run only this rule (comma-separated for multiple)\"),\n Flag.optional,\n ),\n dryRun: Flag.boolean(\"dry-run\").pipe(\n Flag.withAlias(\"d\"),\n Flag.withDescription(\"Show counts only, no instruction blocks\"),\n ),\n base: Flag.string(\"base\").pipe(Flag.withDescription(\"Git ref to diff against\"), Flag.optional),\n },\n (config) => {\n const ruleFilter = Option.match(config.rule, {\n onNone: () => [] as ReadonlyArray<string>,\n onSome: (r: string) => r.split(\",\").map((s) => s.trim()),\n });\n const baseRef = Option.match(config.base, {\n onNone: () => undefined,\n onSome: (b: string) => b,\n });\n\n return Effect.gen(function* () {\n const env = yield* Env;\n const result = yield* checkHandler(\n new CheckCommand({\n all: config.all,\n rules: ruleFilter,\n dryRun: config.dryRun,\n base: baseRef,\n files: config.files,\n }),\n );\n\n if (result.noMatchingRules) {\n yield* Console.log(`No matching rules found. Available: ${result.availableRules.join(\", \")}`);\n return;\n }\n\n if (result.totalFlags === 0) {\n yield* Console.log(`agentreview v${__AGENTREVIEW_VERSION__} - no rules triggered.`);\n return;\n }\n\n const configLoader = yield* ConfigLoader;\n const cfg = yield* configLoader.load();\n const rulesMeta: HashMap.HashMap<string, RuleMeta> = HashMap.fromIterable(\n Object.entries(cfg.rules).map(([name, rule]) => [name, rule.meta] as const),\n );\n\n const output = yield* formatReport(result.flags, rulesMeta, {\n dryRun: config.dryRun,\n version: __AGENTREVIEW_VERSION__,\n });\n\n yield* Console.log(output);\n\n if (result.filteredCount > 0) {\n yield* Console.log(\n ` (${result.filteredCount} reviewed flag(s) hidden — run agentreview review --reset to clear)`,\n );\n }\n\n if (result.flags.length > 0) {\n env.setExitCode(1);\n }\n });\n },\n).pipe(Command.withDescription(\"Scan files and output report for AI agents\"));\n\n/** The `list` subcommand — prints all registered rules. */\nconst list = Command.make(\"list\", {}, () =>\n Effect.gen(function* () {\n const result = yield* listHandler(new ListCommand({}));\n\n if (result.rules.length === 0) {\n yield* Console.log(\"No rules registered.\");\n return;\n }\n\n yield* Console.log(`${result.rules.length} rule(s) registered:\\n`);\n\n for (const rule of result.rules) {\n const langs = rule.languages.join(\", \");\n yield* Console.log(` ${rule.name}`);\n yield* Console.log(` ${rule.description}`);\n yield* Console.log(` Languages: ${langs}`);\n if (rule.include) {\n yield* Console.log(` Include: ${rule.include.join(\", \")}`);\n }\n if (rule.ignore) {\n yield* Console.log(` Ignore: ${rule.ignore.join(\", \")}`);\n }\n yield* Console.log();\n }\n }),\n).pipe(Command.withDescription(\"List all registered rules\"));\n\n/** The `init` subcommand — scaffolds a starter config file. */\nconst init = Command.make(\"init\", {}, () =>\n Effect.gen(function* () {\n const result = yield* initHandler(new InitCommand({}));\n yield* Console.log(result.message);\n }),\n).pipe(Command.withDescription(\"Create agentreview.config.ts and set up agent skill discovery\"));\n\n/** The `review` subcommand — manage reviewed-flag state. */\nconst review = Command.make(\n \"review\",\n {\n hashes: Argument.string(\"hashes\").pipe(\n Argument.withDescription(\"Flag hashes to mark as reviewed\"),\n Argument.variadic(),\n ),\n all: Flag.boolean(\"all\").pipe(Flag.withAlias(\"a\"), Flag.withDescription(\"Mark all current flags as reviewed\")),\n reset: Flag.boolean(\"reset\").pipe(Flag.withDescription(\"Wipe the state file\")),\n },\n (config) =>\n Effect.gen(function* () {\n const result = yield* reviewHandler(\n new ReviewCommand({\n hashes: config.hashes,\n all: config.all,\n reset: config.reset,\n }),\n );\n yield* Console.log(result.message);\n }),\n).pipe(Command.withDescription(\"Mark flags as reviewed (filters them from check output)\"));\n\nconst agentreview = Command.make(\"agentreview\").pipe(\n Command.withDescription(\"Deterministic linting for AI agents\"),\n Command.withSubcommands([check, list, init, review]),\n);\n\nconst AppLayer = Layer.mergeAll(ConfigLoader.layer, Parser.layer, Git.layer, IgnoreReader.layer, StateStore.layer).pipe(\n Layer.provideMerge(NodeServices.layer),\n Layer.provideMerge(Env.layer),\n);\n\n// The CLI framework uses `unknown` for aggregated service requirements,\n// which doesn't fully resolve via `Effect.provide`. Cast to satisfy\n// `NodeRuntime.runMain`'s `never` requirement constraint.\nconst program = Command.run(agentreview, { version: __AGENTREVIEW_VERSION__ }).pipe(\n Effect.provide(AppLayer),\n) as Effect.Effect<void>;\n\nNodeRuntime.runMain(program);\n"],"mappings":"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"}
1
+ {"version":3,"file":"bin.mjs","names":["#filename","#source","Parser","TSParser","Parser","Parser"],"sources":["../src/config/env.ts","../src/shared/infrastructure/config-loader.ts","../src/shared/infrastructure/state-store.ts","../src/domain/hash.ts","../src/domain/rule-context.ts","../src/shared/pipeline/file-resolver.ts","../src/shared/infrastructure/git.ts","../src/shared/infrastructure/parser.ts","../src/shared/pipeline/tree-walker.ts","../src/shared/pipeline/language-map.ts","../src/shared/pipeline/collect-flags.ts","../src/features/check/request.ts","../src/features/check/handler.ts","../src/features/init/request.ts","../src/features/init/handler.ts","../src/features/list/request.ts","../src/features/list/handler.ts","../src/features/review/request.ts","../src/features/review/handler.ts","../src/cli/reporter.ts","../src/bin.ts"],"sourcesContent":["/**\n * Centralised process / environment access.\n *\n * **This is the only module in the codebase that may touch `process.*`.**\n *\n * Every other module that needs the working directory, TTY state, colour\n * preference, or exit-code control must depend on the `Env` service\n * instead of reaching into `process` directly.\n *\n * The layer is built once at startup with `Layer.sync` (no external\n * dependencies), so it can be provided before every other service layer.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Context, Layer } from \"effect\";\n\n/**\n * Read-only snapshot of the runtime environment.\n *\n * @since 0.1.0\n * @category services\n */\nexport class Env extends Context.Service<\n Env,\n {\n /** Current working directory, captured at startup. */\n readonly cwd: string;\n /** `true` when ANSI colour codes should be suppressed (`NO_COLOR` or non-TTY). */\n readonly noColor: boolean;\n /** `true` when stdout is an interactive terminal. */\n readonly isTTY: boolean;\n /** Set the process exit code (non-zero signals failure to the shell). */\n setExitCode(code: number): void;\n }\n>()(\"agentlint/Env\") {\n /**\n * Default layer — reads from `process` globals exactly once.\n *\n * @since 0.1.0\n * @category layers\n */\n static readonly layer: Layer.Layer<Env> = Layer.sync(Env, () => {\n /* eslint-disable n/no-process-env -- single authorised access point */\n const isTTY = process.stdout.isTTY ?? false;\n return Env.of({\n cwd: process.cwd(),\n noColor: !!process.env[\"NO_COLOR\"] || !isTTY,\n isTTY,\n setExitCode: (code) => {\n process.exitCode = code;\n },\n });\n /* eslint-enable n/no-process-env */\n });\n}\n","/**\n * Configuration file discovery and loading.\n *\n * Searches the current working directory for a config file, imports it\n * via `jiti` (for TypeScript support without pre-compilation), and\n * validates the exported shape.\n *\n * **Search order**: `agentlint.config.ts` → `.js` → `.mts` → `.mjs`.\n * The first match wins.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Context, Effect, FileSystem, Layer, Path, Schema } from \"effect\";\nimport { Env } from \"../../config/env.js\";\nimport type { AgentReviewConfig } from \"../../domain/config.js\";\n\n/**\n * Raised when the config file is missing, malformed, or fails to import.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class ConfigError extends Schema.TaggedErrorClass<ConfigError>()(\"ConfigError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Candidate config file names, checked in order.\n *\n * @since 0.1.0\n * @category constants\n */\nconst CONFIG_NAMES = [\"agentlint.config.ts\", \"agentlint.config.js\", \"agentlint.config.mts\", \"agentlint.config.mjs\"];\n\n/**\n * Discover the config file path by checking candidates in order.\n *\n * @since 0.1.0\n * @category internals\n */\nconst discoverConfig = (fs: FileSystem.FileSystem, path: Path.Path, cwd: string): Effect.Effect<string, ConfigError> =>\n Effect.gen(function* () {\n for (const name of CONFIG_NAMES) {\n const candidate = path.resolve(cwd, name);\n if (yield* fs.exists(candidate).pipe(Effect.orElseSucceed(() => false))) {\n return candidate;\n }\n }\n return yield* new ConfigError({\n message: `No agentlint config found. Create agentlint.config.ts in ${cwd}`,\n });\n });\n\n/**\n * Effect service that discovers and loads the agentlint config file.\n *\n * Uses `jiti` under the hood so TypeScript configs work without a\n * separate compilation step.\n *\n * @example\n * ```ts\n * import { Console, Effect } from \"effect\"\n * import { ConfigLoader } from \"./infrastructure/config-loader.js\"\n *\n * const program = Effect.gen(function* () {\n * const loader = yield* ConfigLoader\n * const config = yield* loader.load()\n * yield* Console.log(Object.keys(config.rules))\n * })\n * ```\n *\n * @since 0.1.0\n * @category services\n */\nexport class ConfigLoader extends Context.Service<\n ConfigLoader,\n {\n /** Discover and import the config file from the working directory. */\n load(): Effect.Effect<AgentReviewConfig, ConfigError>;\n }\n>()(\"agentlint/ConfigLoader\") {\n static readonly layer: Layer.Layer<ConfigLoader, never, FileSystem.FileSystem | Path.Path | Env> = Layer.effect(\n ConfigLoader,\n Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n return ConfigLoader.of({\n load: () =>\n Effect.gen(function* () {\n const configPath = yield* discoverConfig(fs, path, env.cwd);\n\n const config = yield* Effect.tryPromise({\n try: async () => {\n const { createJiti } = await import(\"jiti\");\n const jiti = createJiti(import.meta.url, {\n interopDefault: true,\n });\n const loaded = await jiti.import(configPath);\n return (loaded as { default?: AgentReviewConfig }).default ?? (loaded as AgentReviewConfig);\n },\n catch: (error) =>\n new ConfigError({\n message: error instanceof Error ? error.message : String(error),\n }),\n });\n\n if (!config || typeof config !== \"object\" || !(\"rules\" in config)) {\n return yield* new ConfigError({\n message: `Invalid config at ${configPath}: must export an object with a \"rules\" field`,\n });\n }\n\n return config;\n }),\n });\n }),\n );\n}\n","/**\n * Local state store for tracking reviewed flags.\n *\n * Manages a `.agentlint-state` file in the project root that stores\n * hashes of flags that have been reviewed. This file is intended to\n * be **gitignored** — it is per-developer scratch state for tracking\n * progress during review sweeps.\n *\n * **Caveats**:\n * - Hashes encode file path, line, column, and message. Editing code\n * above a reviewed flag shifts its position and invalidates the hash.\n * This is by design — changed context should be re-reviewed.\n * - Stale hashes (from flags that no longer exist) accumulate harmlessly.\n * Use `agentlint review --reset` to start fresh.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Context, Effect, FileSystem, HashSet, Layer, Path } from \"effect\";\nimport { Env } from \"../../config/env.js\";\n\n/**\n * The filename used for local review state.\n *\n * @since 0.1.0\n * @category constants\n */\nconst STATE_FILENAME = \".agentlint-state\";\n\n/**\n * Parse the state file into a set of hashes.\n * Tolerates blank lines and `#`-prefixed comments.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction parseStateFile(content: string): HashSet.HashSet<string> {\n let hashes: HashSet.HashSet<string> = HashSet.empty();\n for (const raw of content.split(\"\\n\")) {\n const line = raw.trim();\n if (line.length > 0 && !line.startsWith(\"#\")) {\n hashes = HashSet.add(hashes, line);\n }\n }\n return hashes;\n}\n\n/**\n * Serialize a set of hashes into file content.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction serializeHashes(hashes: HashSet.HashSet<string>): string {\n return [...hashes].join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Effect service for loading and persisting reviewed-flag state.\n *\n * @since 0.1.0\n * @category services\n */\nexport class StateStore extends Context.Service<\n StateStore,\n {\n /** Load reviewed hashes from `.agentlint-state`. Returns an empty set if the file is missing. */\n load(): Effect.Effect<HashSet.HashSet<string>>;\n /** Append one or more hashes to `.agentlint-state`, deduplicating against existing entries. */\n append(hashes: ReadonlyArray<string>): Effect.Effect<void>;\n /** Delete the `.agentlint-state` file entirely. */\n reset(): Effect.Effect<void>;\n }\n>()(\"agentlint/StateStore\") {\n /**\n * Default layer — resolves the state file path from `Env.cwd`.\n *\n * @since 0.1.0\n * @category layers\n */\n static readonly layer: Layer.Layer<StateStore, never, FileSystem.FileSystem | Path.Path | Env> = Layer.unwrap(\n Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const statePath = path.resolve(env.cwd, STATE_FILENAME);\n\n return Layer.succeed(\n StateStore,\n StateStore.of({\n load: () =>\n fs.exists(statePath).pipe(\n Effect.orElseSucceed(() => false),\n Effect.flatMap((exists) =>\n exists\n ? fs.readFileString(statePath).pipe(\n Effect.map(parseStateFile),\n Effect.orElseSucceed(() => HashSet.empty<string>()),\n )\n : Effect.succeed(HashSet.empty<string>()),\n ),\n ),\n\n append: (hashes) =>\n fs.exists(statePath).pipe(\n Effect.orElseSucceed(() => false),\n Effect.flatMap((exists) =>\n exists\n ? fs.readFileString(statePath).pipe(\n Effect.map(parseStateFile),\n Effect.orElseSucceed(() => HashSet.empty<string>()),\n )\n : Effect.succeed(HashSet.empty<string>()),\n ),\n Effect.map((existing) => hashes.reduce((acc, h) => HashSet.add(acc, h), existing)),\n Effect.flatMap((merged) =>\n fs.writeFileString(statePath, serializeHashes(merged)).pipe(Effect.orElseSucceed(() => {})),\n ),\n ),\n\n reset: () =>\n fs.exists(statePath).pipe(\n Effect.orElseSucceed(() => false),\n Effect.flatMap((exists) =>\n exists ? fs.remove(statePath).pipe(Effect.orElseSucceed(() => {})) : Effect.void,\n ),\n ),\n }),\n );\n }),\n );\n}\n","/**\n * FNV-1a hashing utility.\n *\n * Produces a 7-character hex digest used for stable, deterministic\n * flag identification. The hash encodes rule name, file path, position,\n * and message so that identical matches across runs share the same id.\n *\n * @see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function\n *\n * @module\n * @since 0.1.0\n */\n\n/**\n * FNV-1a 32-bit offset basis.\n *\n * @since 0.1.0\n * @category constants\n */\nconst FNV_OFFSET_BASIS = 0x811c9dc5;\n\n/**\n * FNV-1a 32-bit prime multiplier.\n *\n * @since 0.1.0\n * @category constants\n */\nconst FNV_PRIME = 0x01000193;\n\n/**\n * Compute a 7-character hex FNV-1a hash of `input`.\n *\n * The result is the first 7 hex characters of the unsigned 32-bit\n * FNV-1a digest — short enough for display, long enough to avoid\n * collisions in typical lint runs.\n *\n * @example\n * ```ts\n * import { fnv1a7 } from \"./utils/hash.js\"\n *\n * fnv1a7(\"my-rule:src/index.ts:10:1:message\") // => \"a3f4b2c\"\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function fnv1a7(input: string): string {\n let hash = FNV_OFFSET_BASIS;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = Math.imul(hash, FNV_PRIME);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\").slice(0, 7);\n}\n","/**\n * Rule context — the interface rules use to interact with the runner.\n *\n * Provides file metadata, source access, and the {@link RuleContext.flag}\n * method for recording matches.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { fnv1a7 } from \"./hash.js\";\nimport { type FlagOptions, FlagRecord } from \"./flag.js\";\n\n/**\n * Context object passed to `createOnce`. Available throughout the rule's lifecycle.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface RuleContext {\n /** Absolute path of the current file being analyzed. */\n getFilename(): string;\n /** Full source content of the current file. */\n getSourceCode(): string;\n /**\n * Lines around the given 1-based line number, formatted with line numbers.\n * @param line 1-based line number\n * @param radius number of lines above/below to include (default 10)\n */\n getLinesAround(line: number, radius?: number): string;\n /** Record a match for the output report. */\n flag(options: FlagOptions): void;\n}\n\n/**\n * Internal implementation of {@link RuleContext}.\n *\n * Tracks the current file, accumulates flags, and provides source\n * access helpers. The check command calls {@link setFile} before each\n * file and {@link drainFlags} after the tree walk to collect results.\n *\n * @since 0.1.0\n * @category internals\n */\nexport class RuleContextImpl implements RuleContext {\n readonly ruleName: string;\n readonly flags: FlagRecord[] = [];\n\n #filename = \"\";\n #source = \"\";\n\n constructor(ruleName: string) {\n this.ruleName = ruleName;\n }\n\n /**\n * Set the current file context. Called by the check command before\n * each file is walked.\n */\n setFile(filename: string, source: string): void {\n this.#filename = filename;\n this.#source = source;\n }\n\n /**\n * Remove and return all accumulated flags. Called after the tree\n * walk for each file to collect results.\n */\n drainFlags(): FlagRecord[] {\n return this.flags.splice(0);\n }\n\n getFilename(): string {\n return this.#filename;\n }\n\n getSourceCode(): string {\n return this.#source;\n }\n\n getLinesAround(line: number, radius = 10): string {\n const lines = this.#source.split(\"\\n\");\n const start = Math.max(0, line - 1 - radius);\n const end = Math.min(lines.length, line + radius);\n return lines\n .slice(start, end)\n .map((l, i) => `${String(start + i + 1).padStart(4)} | ${l}`)\n .join(\"\\n\");\n }\n\n flag(options: FlagOptions): void {\n const line = options.node.startPosition.row + 1;\n const col = options.node.startPosition.column + 1;\n const sourceLines = this.#source.split(\"\\n\");\n const rawLine = sourceLines[line - 1] ?? \"\";\n const trimmed = rawLine.trim();\n const sourceSnippet = trimmed.length > 100 ? trimmed.slice(0, 97) + \"...\" : trimmed;\n\n const hash = fnv1a7(`${this.ruleName}:${this.#filename}:${line}:${col}:${options.message}`);\n\n this.flags.push(\n new FlagRecord({\n ruleName: this.ruleName,\n filename: this.#filename,\n line,\n col,\n message: options.message,\n sourceSnippet,\n hash,\n instruction: options.instruction,\n suggest: options.suggest,\n }),\n );\n }\n}\n","/**\n * File resolution service.\n *\n * Determines which files to lint by applying the filter pipeline:\n * 1. Candidate files (from git diff or all files)\n * 2. Config include/ignore\n *\n * Per-rule filtering (languages, include, ignore) is done by the check command.\n *\n * @module\n */\n\nimport { Effect, FileSystem, HashSet, Path, Schema } from \"effect\";\nimport { Env } from \"../../config/env.js\";\nimport picomatch from \"picomatch\";\n\n/**\n * Raised when file resolution fails — e.g. a git error bubbling up\n * from the changed-files query.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class FileResolverError extends Schema.TaggedErrorClass<FileResolverError>()(\"FileResolverError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Options controlling which files enter the lint pipeline.\n *\n * @since 0.1.0\n * @category models\n */\nexport const ResolveOptions = Schema.Struct({\n /** When `true`, scan all files instead of only git-changed files. */\n all: Schema.Boolean,\n /** Git ref to diff against. Defaults to the detected default branch. */\n baseRef: Schema.optional(Schema.String),\n /** Global include globs from the config file. */\n configInclude: Schema.optional(Schema.Array(Schema.String)),\n /** Global ignore globs from the config file. */\n configIgnore: Schema.optional(Schema.Array(Schema.String)),\n /** Explicit file paths passed as CLI positional arguments. */\n positionalFiles: Schema.optional(Schema.Array(Schema.String)),\n});\n\n/** @since 0.1.0 */\nexport type ResolveOptions = Schema.Schema.Type<typeof ResolveOptions>;\n\n/** Directories that are always skipped during recursive listing. */\nconst SKIP_DIRS: HashSet.HashSet<string> = HashSet.make(\"node_modules\", \".git\", \"dist\");\n\n/**\n * Recursively list all files under `dir`, returning paths relative to `base`.\n *\n * Skips `node_modules`, `.git`, and `dist` directories. Errors (e.g.\n * permission denied) are silently swallowed.\n *\n * Uses the Effect `FileSystem` and `Path` services for cross-platform\n * file system access.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction listAllFiles(dir: string, base: string, fs: FileSystem.FileSystem, path: Path.Path): Effect.Effect<string[]> {\n return Effect.gen(function* () {\n const entries = yield* fs.readDirectory(dir);\n const results: string[] = [];\n\n for (const name of entries) {\n if (HashSet.has(SKIP_DIRS, name)) continue;\n\n const fullPath = path.resolve(dir, name);\n const info = yield* fs.stat(fullPath);\n const relPath = path.relative(base, fullPath).replace(/\\\\/g, \"/\");\n\n if (info.type === \"Directory\") {\n results.push(...(yield* listAllFiles(fullPath, base, fs, path)));\n } else {\n results.push(relPath);\n }\n }\n\n return results;\n }).pipe(Effect.catch(() => Effect.succeed([] as string[])));\n}\n\n/**\n * Determine the final set of files to lint.\n *\n * Applies the multi-layer filter pipeline described in the module header,\n * then sorts the result alphabetically for deterministic output.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function resolveFiles(\n options: ResolveOptions,\n gitService: {\n changedFiles(baseRef?: string): Effect.Effect<ReadonlyArray<string>, any>;\n },\n): Effect.Effect<ReadonlyArray<string>, FileResolverError, FileSystem.FileSystem | Path.Path | Env> {\n return Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const { cwd } = env;\n let candidates: string[];\n\n if (options.positionalFiles && options.positionalFiles.length > 0) {\n candidates = [...options.positionalFiles];\n } else if (options.all) {\n candidates = yield* listAllFiles(cwd, cwd, fs, path);\n } else {\n const changed = yield* Effect.mapError(\n gitService.changedFiles(options.baseRef),\n (e) => new FileResolverError({ message: `Git error: ${e}` }),\n );\n candidates = [...changed];\n }\n\n const includeMatcher = options.configInclude?.length ? picomatch(options.configInclude as string[]) : undefined;\n const ignoreMatcher = options.configIgnore?.length ? picomatch(options.configIgnore as string[]) : undefined;\n\n return candidates\n .filter((f) => !includeMatcher || includeMatcher(f))\n .filter((f) => !ignoreMatcher || !ignoreMatcher(f))\n .filter((f) => path.extname(f).length > 0)\n .toSorted();\n });\n}\n","/**\n * Git integration — default branch detection and changed file collection.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Context, Effect, HashSet, Layer, Schema } from \"effect\";\nimport { Env } from \"../../config/env.js\";\nimport { ChildProcess, ChildProcessSpawner } from \"effect/unstable/process\";\n\n/**\n * Raised when a git operation fails — e.g. not a git repo,\n * invalid ref, or `git` binary not found.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class GitError extends Schema.TaggedErrorClass<GitError>()(\"GitError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Execute a git command and return trimmed stdout.\n *\n * Uses the array form of `ChildProcess.make` so that dynamic arguments\n * are properly tokenized.\n *\n * @since 0.1.0\n * @category internals\n */\nconst gitCmd = (args: string, cwd: string) =>\n Effect.gen(function* () {\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n return (yield* spawner.string(ChildProcess.make(\"git\", args.split(/\\s+/), { cwd }))).trim();\n });\n\n/**\n * Detect the default branch by checking whether `main` or `master` exists.\n * Falls back to `\"main\"` when neither can be verified.\n *\n * @since 0.1.0\n * @category internals\n */\nconst detectDefault = (cwd: string) =>\n gitCmd(\"rev-parse --verify main\", cwd).pipe(\n Effect.map(() => \"main\" as string),\n Effect.catch(() =>\n gitCmd(\"rev-parse --verify master\", cwd).pipe(\n Effect.map(() => \"master\" as string),\n Effect.catch(() => Effect.succeed(\"main\" as string)),\n ),\n ),\n );\n\n/**\n * Collect all files that differ from `baseRef`.\n *\n * Gathers the union of committed diffs, uncommitted changes, and\n * untracked files. Each source is caught so partial failures\n * (e.g. empty repo, no merge-base) are silently skipped.\n *\n * @since 0.1.0\n * @category internals\n */\nconst parseLines = (output: string): ReadonlyArray<string> =>\n output\n .split(\"\\n\")\n .map((f) => f.trim())\n .filter((f) => f.length > 0);\n\nconst collectChangedFiles = (cwd: string, baseRef: string) =>\n Effect.all([\n // Committed changes since merge-base\n gitCmd(`merge-base HEAD ${baseRef}`, cwd).pipe(\n Effect.flatMap((mergeBase) => gitCmd(`diff --name-only ${mergeBase}...HEAD`, cwd)),\n Effect.catch(() => Effect.succeed(\"\")),\n ),\n // Uncommitted changes\n gitCmd(\"diff --name-only HEAD\", cwd).pipe(Effect.catch(() => Effect.succeed(\"\"))),\n // Untracked files\n gitCmd(\"ls-files --others --exclude-standard\", cwd).pipe(Effect.catch(() => Effect.succeed(\"\"))),\n ]).pipe(\n Effect.map(([committed, uncommitted, untracked]) =>\n [\n ...HashSet.fromIterable([...parseLines(committed), ...parseLines(uncommitted), ...parseLines(untracked)]),\n ].toSorted(),\n ),\n );\n\n/**\n * @example\n * ```ts\n * import { Console, Effect } from \"effect\"\n * import { Git } from \"./infrastructure/git.js\"\n *\n * const program = Effect.gen(function* () {\n * const git = yield* Git\n * const branch = yield* git.detectDefaultBranch()\n * const changed = yield* git.changedFiles(branch)\n * yield* Console.log(`${changed.length} files changed since ${branch}`)\n * })\n * ```\n *\n * @since 0.1.0\n */\nexport class Git extends Context.Service<\n Git,\n {\n /** Detect whether the default branch is `main` or `master`. */\n detectDefaultBranch(): Effect.Effect<string, GitError>;\n /** Return sorted list of files changed relative to `baseRef` (defaults to the detected default branch). */\n changedFiles(baseRef?: string): Effect.Effect<ReadonlyArray<string>, GitError>;\n }\n>()(\"agentlint/Git\") {\n static readonly layer: Layer.Layer<Git, never, ChildProcessSpawner.ChildProcessSpawner | Env> = Layer.effect(\n Git,\n Effect.gen(function* () {\n const env = yield* Env;\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const provide = <A, E>(effect: Effect.Effect<A, E, ChildProcessSpawner.ChildProcessSpawner>) =>\n Effect.provideService(effect, ChildProcessSpawner.ChildProcessSpawner, spawner);\n\n return Git.of({\n detectDefaultBranch: () =>\n provide(detectDefault(env.cwd)).pipe(Effect.mapError((e) => new GitError({ message: String(e) }))),\n\n changedFiles: (baseRef) =>\n (baseRef ? Effect.succeed(baseRef) : provide(detectDefault(env.cwd))).pipe(\n Effect.flatMap((base) => provide(collectChangedFiles(env.cwd, base))),\n Effect.mapError((e) => new GitError({ message: String(e) })),\n ),\n });\n }),\n );\n}\n","/**\n * Tree-sitter WASM parser.\n *\n * WASM init is lazy — the first `parse` call triggers initialization.\n * Grammars are cached after first load.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Context, Effect, FileSystem, HashMap, Layer, Option, Path, Schema } from \"effect\";\nimport { Env } from \"../../config/env.js\";\nimport { Language, Parser as TSParser, type Tree } from \"web-tree-sitter\";\n\n/**\n * Raised when parsing fails — e.g. missing grammar, corrupt WASM, or\n * tree-sitter returning a null tree.\n *\n * @since 0.1.0\n * @category errors\n */\nexport class ParserError extends Schema.TaggedErrorClass<ParserError>()(\"ParserError\", {\n message: Schema.String,\n}) {}\n\n/**\n * Maps grammar names to their corresponding `.wasm` filenames.\n *\n * @since 0.1.0\n * @category constants\n */\nconst GRAMMAR_FILES: HashMap.HashMap<string, string> = HashMap.make(\n [\"typescript\", \"tree-sitter-typescript.wasm\"],\n [\"tsx\", \"tree-sitter-tsx.wasm\"],\n [\"javascript\", \"tree-sitter-javascript.wasm\"],\n);\n\n/**\n * @example\n * ```ts\n * import { Console, Effect } from \"effect\"\n * import { Parser } from \"./infrastructure/parser.js\"\n *\n * const program = Effect.gen(function* () {\n * const parser = yield* Parser\n * const tree = yield* parser.parse(\"const x = 1\", \"typescript\")\n * yield* Console.log(tree.rootNode.type) // \"program\"\n * })\n * ```\n *\n * @since 0.1.0\n * @category services\n */\nexport class Parser extends Context.Service<\n Parser,\n {\n parse(source: string, grammar: string): Effect.Effect<Tree, ParserError>;\n }\n>()(\"agentlint/Parser\") {\n /** Default layer — lazily initializes WASM and caches grammars. */\n static readonly layer: Layer.Layer<Parser, never, FileSystem.FileSystem | Path.Path | Env> = Layer.effect(\n Parser,\n Effect.gen(function* () {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n const resolveWasmPath = (filename: string): Effect.Effect<string, ParserError> =>\n Effect.gen(function* () {\n const thisDir = path.dirname(path.resolve(import.meta.dirname ?? \".\", \"\"));\n const distPath = path.resolve(thisDir, \"wasm\", filename);\n if (yield* fs.exists(distPath).pipe(Effect.orElseSucceed(() => false))) return distPath;\n\n const nmBase = path.resolve(env.cwd, \"node_modules\");\n if (filename === \"tree-sitter.wasm\") {\n const p = path.resolve(nmBase, \"web-tree-sitter\", filename);\n if (yield* fs.exists(p).pipe(Effect.orElseSucceed(() => false))) return p;\n } else {\n const p = path.resolve(nmBase, \"tree-sitter-wasms\", \"out\", filename);\n if (yield* fs.exists(p).pipe(Effect.orElseSucceed(() => false))) return p;\n }\n\n return yield* new ParserError({ message: `WASM file not found: ${filename}` });\n });\n\n let parserInstance: TSParser | undefined;\n let languageCache: HashMap.HashMap<string, Language> = HashMap.empty();\n\n return Parser.of({\n parse: (source, grammar) =>\n Effect.gen(function* () {\n if (!parserInstance) {\n const initPath = yield* resolveWasmPath(\"tree-sitter.wasm\");\n yield* Effect.tryPromise({\n try: async () => {\n await TSParser.init({ locateFile: () => initPath });\n parserInstance = new TSParser();\n },\n catch: (error) => new ParserError({ message: error instanceof Error ? error.message : String(error) }),\n });\n }\n\n let lang = Option.getOrUndefined(HashMap.get(languageCache, grammar));\n if (!lang) {\n const file = Option.getOrUndefined(HashMap.get(GRAMMAR_FILES, grammar));\n if (!file) return yield* new ParserError({ message: `Unknown grammar: ${grammar}` });\n\n const wasmPath = yield* resolveWasmPath(file);\n lang = yield* Effect.tryPromise({\n try: () => Language.load(wasmPath),\n catch: (error) => new ParserError({ message: error instanceof Error ? error.message : String(error) }),\n });\n languageCache = HashMap.set(languageCache, grammar, lang);\n }\n\n parserInstance!.setLanguage(lang);\n const tree = parserInstance!.parse(source);\n if (!tree) return yield* new ParserError({ message: \"Parser returned null tree\" });\n return tree;\n }),\n });\n }),\n );\n}\n","/**\n * Single-pass multi-rule tree walker.\n *\n * Builds a dispatch table from all active rules' visitor methods,\n * walks the tree once using tree-sitter's cursor API, and calls\n * all matching handlers per node.\n *\n * @module\n */\n\nimport { Effect, HashMap, Option } from \"effect\";\nimport type { Tree, TreeCursor } from \"web-tree-sitter\";\nimport { type AgentReviewNode, wrapNode } from \"../../domain/node.js\";\nimport type { FlagRecord } from \"../../domain/flag.js\";\nimport type { VisitorHandler, Visitors } from \"../../domain/rule.js\";\nimport type { RuleContextImpl } from \"../../domain/rule-context.js\";\n\n/**\n * Regex matching `agentlint-ignore` comments.\n *\n * Captures an optional rule name after the directive:\n * - `// agentlint-ignore` → suppresses all rules on the next line\n * - `// agentlint-ignore my-rule` → suppresses only `my-rule`\n *\n * @since 0.1.0\n * @category constants\n */\nconst IGNORE_PATTERN = /agentlint-ignore(?:\\s+(\\S+))?/;\n\n/**\n * Internal binding of a rule to its context and visitors for a walk pass.\n *\n * @since 0.1.0\n * @category models\n */\ninterface RuleEntry {\n readonly ruleName: string;\n readonly context: RuleContextImpl;\n readonly visitors: Visitors;\n}\n\n/**\n * A single handler entry in the dispatch table, keyed by node type.\n *\n * @since 0.1.0\n * @category models\n */\ninterface DispatchHandler {\n readonly ruleName: string;\n readonly handler: VisitorHandler;\n}\n\n/**\n * Records an `agentlint-ignore` comment that suppresses a specific\n * rule (or all rules) on the immediately following line.\n *\n * @since 0.1.0\n * @category models\n */\ninterface Suppression {\n /** Rule name, or `\"*\"` for all rules. */\n readonly ruleName: string;\n /** 0-indexed line number of the *comment* (the suppressed line is `line + 1`). */\n readonly line: number;\n}\n\n/**\n * Walk files with the given rules, collecting all flags.\n *\n * Call this once per file. The caller is responsible for:\n * - Calling `context.setFile()` before this function\n * - Calling `before()` and filtering out skipped rules\n * - Calling `after()` after all files are processed\n *\n * @internal\n */\nexport function walkFile(tree: Tree, rules: ReadonlyArray<RuleEntry>): ReadonlyArray<FlagRecord> {\n const dispatchTable: HashMap.HashMap<string, DispatchHandler[]> = HashMap.mutate(\n HashMap.empty<string, DispatchHandler[]>(),\n (m) => {\n for (const entry of rules) {\n for (const key of Object.keys(entry.visitors)) {\n if (key === \"before\" || key === \"after\") continue;\n const handler = entry.visitors[key];\n if (typeof handler !== \"function\") continue;\n\n const existing = Option.getOrUndefined(HashMap.get(m, key));\n if (existing) {\n existing.push({ ruleName: entry.ruleName, handler: handler as VisitorHandler });\n } else {\n HashMap.set(m, key, [{ ruleName: entry.ruleName, handler: handler as VisitorHandler }]);\n }\n }\n }\n },\n );\n\n const suppressions: Suppression[] = [];\n\n const cursor: TreeCursor = tree.walk();\n let reachedEnd = false;\n\n while (!reachedEnd) {\n const nodeType = cursor.nodeType;\n\n if (nodeType === \"comment\") {\n const node = cursor.currentNode;\n const match = IGNORE_PATTERN.exec(node.text);\n if (match) {\n const ruleNameArg = match[1];\n const ruleName = ruleNameArg?.split(\"--\")[0]?.trim() ?? \"*\";\n suppressions.push({\n ruleName,\n line: node.startPosition.row + 1,\n });\n }\n }\n\n const handlers = Option.getOrUndefined(HashMap.get(dispatchTable, nodeType));\n if (handlers) {\n const wrapped: AgentReviewNode = wrapNode(cursor.currentNode);\n for (const { handler } of handlers) {\n handler(wrapped);\n }\n }\n\n if (cursor.gotoFirstChild()) continue;\n while (!cursor.gotoNextSibling()) {\n if (!cursor.gotoParent()) {\n reachedEnd = true;\n break;\n }\n }\n }\n\n const allFlags: FlagRecord[] = [];\n for (const entry of rules) {\n allFlags.push(...entry.context.drainFlags());\n }\n\n if (suppressions.length === 0) return allFlags;\n\n return allFlags.filter((flag) => {\n const flagLine0 = flag.line - 1;\n return !suppressions.some((s) => (s.ruleName === \"*\" || s.ruleName === flag.ruleName) && s.line === flagLine0);\n });\n}\n\n/**\n * Effect wrapper around {@link walkFile}.\n *\n * Runs the tree walk synchronously inside `Effect.sync`, making it\n * composable with the rest of the Effect pipeline.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function walkFileEffect(tree: Tree, rules: ReadonlyArray<RuleEntry>): Effect.Effect<ReadonlyArray<FlagRecord>> {\n return Effect.sync(() => walkFile(tree, rules));\n}\n","/**\n * File extension → tree-sitter grammar mapping.\n *\n * Maps every supported file extension to the grammar name used by\n * the parser service. This is the single source of truth for which\n * file types agentlint can analyze.\n *\n * Uses Effect `HashMap` for an immutable, structurally-equal lookup table.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { HashMap, Option } from \"effect\";\n\n/**\n * Maps file extensions (without leading dot) to their tree-sitter\n * grammar name.\n *\n * @since 0.1.0\n * @category constants\n */\nconst EXTENSION_TO_GRAMMAR: HashMap.HashMap<string, string> = HashMap.make(\n [\"ts\", \"typescript\"],\n [\"tsx\", \"tsx\"],\n [\"js\", \"javascript\"],\n [\"jsx\", \"javascript\"],\n [\"mts\", \"typescript\"],\n [\"cts\", \"typescript\"],\n [\"mjs\", \"javascript\"],\n [\"cjs\", \"javascript\"],\n);\n\n/**\n * Look up the tree-sitter grammar name for a file extension.\n *\n * Returns `undefined` for unsupported extensions — callers should\n * skip those files.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function grammarForExtension(ext: string): string | undefined {\n return Option.getOrUndefined(HashMap.get(EXTENSION_TO_GRAMMAR, ext));\n}\n\n/**\n * Return all file extensions that agentlint can parse.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function supportedExtensions(): ReadonlyArray<string> {\n return [...HashMap.keys(EXTENSION_TO_GRAMMAR)];\n}\n","/**\n * Flag collection pipeline — shared between `check` and `review`.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, Path, Schema } from \"effect\";\nimport picomatch from \"picomatch\";\nimport { Env } from \"../../config/env.js\";\nimport { FlagRecord } from \"../../domain/flag.js\";\nimport type { AgentReviewRule, Visitors } from \"../../domain/rule.js\";\nimport { RuleContextImpl } from \"../../domain/rule-context.js\";\nimport { ConfigLoader } from \"../infrastructure/config-loader.js\";\nimport { resolveFiles } from \"./file-resolver.js\";\nimport { Git } from \"../infrastructure/git.js\";\nimport { Parser } from \"../infrastructure/parser.js\";\nimport { walkFile } from \"./tree-walker.js\";\nimport { grammarForExtension } from \"./language-map.js\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport const CollectResult = Schema.Struct({\n /** Collected flags. */\n flags: Schema.Array(FlagRecord),\n /** `true` when the `--rule` filter matched no registered rules. */\n noMatchingRules: Schema.Boolean,\n});\n\n/** @since 0.1.0 */\nexport type CollectResult = Schema.Schema.Type<typeof CollectResult>;\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport const CollectOptions = Schema.Struct({\n /** When `true`, scan all files instead of only git-changed files. */\n all: Schema.Boolean,\n /** Rule name filter. Empty array means \"run all rules\". */\n rules: Schema.Array(Schema.String),\n /** When `true`, suppress instruction and hint blocks in output. */\n dryRun: Schema.Boolean,\n /** Git ref to diff against. `undefined` means auto-detect. */\n base: Schema.UndefinedOr(Schema.String),\n /** Explicit file paths from positional CLI arguments. */\n files: Schema.Array(Schema.String),\n});\n\n/** @since 0.1.0 */\nexport type CollectOptions = Schema.Schema.Type<typeof CollectOptions>;\n\n/** @since 0.1.0 */\nexport const collectFlags = Effect.fn(\"collectFlags\")(function* (\n options: CollectOptions,\n): Generator<any, CollectResult> {\n const configLoader = yield* ConfigLoader;\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const gitService = yield* Git;\n const parserService = yield* Parser;\n\n const config = yield* configLoader.load();\n\n let activeRules: Array<[string, AgentReviewRule]> = Object.entries(config.rules);\n if (options.rules.length > 0) {\n activeRules = activeRules.filter(([name]) => options.rules.includes(name));\n if (activeRules.length === 0) return { flags: [], noMatchingRules: true };\n }\n\n const includePatterns = config.include ? [...config.include] : undefined;\n const ignorePatterns = config.ignore ? [...config.ignore] : undefined;\n\n const files = yield* resolveFiles(\n {\n all: options.all,\n baseRef: options.base,\n configInclude: includePatterns,\n configIgnore: ignorePatterns,\n positionalFiles: options.files.length > 0 ? [...options.files] : undefined,\n },\n gitService,\n );\n\n if (files.length === 0) return { flags: [], noMatchingRules: false };\n\n const ruleEntries: Array<{\n name: string;\n rule: AgentReviewRule;\n context: RuleContextImpl;\n visitors: Visitors;\n }> = [];\n\n for (const [name, rule] of activeRules) {\n const context = new RuleContextImpl(name);\n const visitors = rule.createOnce(context);\n ruleEntries.push({ name, rule, context, visitors });\n }\n\n const allFlags: FlagRecord[] = [];\n\n for (const file of files) {\n const ext = path.extname(file).slice(1);\n const absPath = path.resolve(env.cwd, file);\n\n const applicableRules = ruleEntries.filter((entry) => {\n if (!entry.rule.meta.languages.includes(ext)) return false;\n\n if (entry.rule.meta.include && entry.rule.meta.include.length > 0) {\n const matcher = picomatch([...entry.rule.meta.include]);\n if (!matcher(file)) return false;\n }\n\n if (entry.rule.meta.ignore && entry.rule.meta.ignore.length > 0) {\n const matcher = picomatch([...entry.rule.meta.ignore]);\n if (matcher(file)) return false;\n }\n\n return true;\n });\n\n if (applicableRules.length === 0) continue;\n\n const sourceResult = yield* fs.readFileString(absPath).pipe(Effect.result);\n if (sourceResult._tag === \"Failure\") continue;\n const source = sourceResult.success;\n\n const grammar = grammarForExtension(ext);\n if (!grammar) continue;\n\n const tree = yield* parserService.parse(source, grammar);\n\n const rulesForFile: Array<{\n ruleName: string;\n context: RuleContextImpl;\n visitors: Visitors;\n }> = [];\n\n for (const entry of applicableRules) {\n entry.context.setFile(absPath, source);\n const beforeResult = entry.visitors.before?.(absPath);\n if (beforeResult === false) continue;\n rulesForFile.push({\n ruleName: entry.name,\n context: entry.context,\n visitors: entry.visitors,\n });\n }\n\n if (rulesForFile.length === 0) continue;\n\n const fileFlags = walkFile(tree, rulesForFile);\n allFlags.push(...fileFlags);\n }\n\n for (const entry of ruleEntries) {\n entry.visitors.after?.();\n }\n\n return { flags: allFlags, noMatchingRules: false };\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport { FlagRecord } from \"../../domain/flag.js\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class CheckCommand extends Schema.TaggedClass<CheckCommand>()(\"CheckCommand\", {\n /** When `true`, scan all files instead of only git-changed files. */\n all: Schema.Boolean,\n /** Rule name filter. Empty array means \"run all rules\". */\n rules: Schema.Array(Schema.String),\n /** When `true`, suppress instruction and hint blocks in output. */\n dryRun: Schema.Boolean,\n /** Git ref to diff against. `undefined` means auto-detect. */\n base: Schema.UndefinedOr(Schema.String),\n /** Explicit file paths from positional CLI arguments. */\n files: Schema.Array(Schema.String),\n}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class CheckResult extends Schema.TaggedClass<CheckResult>()(\"CheckResult\", {\n /** Unreviewed flags to display. */\n flags: Schema.Array(FlagRecord),\n /** Total flags before filtering out reviewed ones. */\n totalFlags: Schema.Number,\n /** Number of flags filtered out because they were previously reviewed. */\n filteredCount: Schema.Number,\n /** `true` when the `--rule` filter matched no registered rules. */\n noMatchingRules: Schema.Boolean,\n /** Available rule names (for error messages when no match). */\n availableRules: Schema.Array(Schema.String),\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, HashSet } from \"effect\";\nimport { ConfigLoader } from \"../../shared/infrastructure/config-loader.js\";\nimport { StateStore } from \"../../shared/infrastructure/state-store.js\";\nimport { collectFlags } from \"../../shared/pipeline/collect-flags.js\";\nimport { CheckCommand, CheckResult } from \"./request.js\";\n\n/** @since 0.1.0 */\nexport const checkHandler = Effect.fn(\"checkHandler\")(function* (command: CheckCommand) {\n const configLoader = yield* ConfigLoader;\n const stateStore = yield* StateStore;\n\n const config = yield* configLoader.load();\n const availableRules = Object.keys(config.rules);\n\n const result = yield* collectFlags({\n all: command.all,\n rules: command.rules,\n dryRun: command.dryRun,\n base: command.base,\n files: command.files,\n });\n\n if (result.noMatchingRules) {\n return new CheckResult({\n flags: [],\n totalFlags: 0,\n filteredCount: 0,\n noMatchingRules: true,\n availableRules,\n });\n }\n\n const allFlags = result.flags;\n\n if (allFlags.length === 0) {\n return new CheckResult({\n flags: [],\n totalFlags: 0,\n filteredCount: 0,\n noMatchingRules: false,\n availableRules,\n });\n }\n\n const reviewed = yield* stateStore.load();\n const reviewedSize = HashSet.size(reviewed);\n const filteredCount = reviewedSize > 0 ? allFlags.filter((f) => HashSet.has(reviewed, f.hash)).length : 0;\n const unreviewedFlags = reviewedSize > 0 ? allFlags.filter((f) => !HashSet.has(reviewed, f.hash)) : allFlags;\n\n return new CheckResult({\n flags: unreviewedFlags,\n totalFlags: allFlags.length,\n filteredCount,\n noMatchingRules: false,\n availableRules,\n });\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class InitCommand extends Schema.TaggedClass<InitCommand>()(\"InitCommand\", {}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class InitResult extends Schema.TaggedClass<InitResult>()(\"InitResult\", {\n /** Whether a new config file was created. */\n created: Schema.Boolean,\n /** Human-readable message describing what happened. */\n message: Schema.String,\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, FileSystem, Path } from \"effect\";\nimport { Env } from \"../../config/env.js\";\nimport { InitCommand, InitResult } from \"./request.js\";\n\n/**\n * Minimal starter config written by `agentlint init`.\n *\n * @since 0.1.0\n * @category constants\n */\nconst STARTER_CONFIG = `import { defineConfig } from \"agentlint\"\n\nexport default defineConfig({\n include: [\"src/**/*.{ts,tsx}\"],\n rules: {},\n})\n`;\n\nconst SKILLS_ADD_CMD = \"npx skills@latest add aurelienbobenrieth/agentlint\";\nconst INTENT_INSTALL_CMD = \"npx @tanstack/intent install\";\n\n/**\n * Detect which skill installation method is most likely appropriate.\n *\n * Checks for TanStack Intent or existing AGENTS.md with intent block.\n */\nconst detectSkillMethod = Effect.fn(\"detectSkillMethod\")(function* (cwd: string) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n // Check if TanStack Intent is installed\n const hasIntent = yield* fs\n .exists(path.resolve(cwd, \"node_modules/@tanstack/intent\"))\n .pipe(Effect.orElseSucceed(() => false));\n\n if (hasIntent) return \"intent\" as const;\n\n // Check if AGENTS.md has an intent-skills block (installed by intent previously)\n const agentsPath = path.resolve(cwd, \"AGENTS.md\");\n if (yield* fs.exists(agentsPath)) {\n const content = yield* fs.readFileString(agentsPath);\n if (content.includes(\"intent-skills:start\")) return \"intent\" as const;\n }\n\n return \"skills\" as const;\n});\n\n/** @since 0.1.0 */\nexport const initHandler = Effect.fn(\"initHandler\")(function* (_command: InitCommand) {\n const env = yield* Env;\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const configPath = path.resolve(env.cwd, \"agentlint.config.ts\");\n\n const gitignorePath = path.resolve(env.cwd, \".gitignore\");\n\n // --- Step 1: Create config ---\n const configCreated = !(yield* fs.exists(configPath));\n if (configCreated) {\n yield* fs.writeFileString(configPath, STARTER_CONFIG);\n }\n\n // --- Step 2: Ensure .agentlint-state is gitignored ---\n let gitignoreUpdated = false;\n const gitignoreExists = yield* fs.exists(gitignorePath);\n if (gitignoreExists) {\n const content = yield* fs.readFileString(gitignorePath);\n if (!content.includes(\".agentlint-state\")) {\n const separator = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n yield* fs.writeFileString(gitignorePath, content + separator + \"\\n# agentlint local state\\n.agentlint-state\\n\");\n gitignoreUpdated = true;\n }\n } else {\n yield* fs.writeFileString(gitignorePath, \"# agentlint local state\\n.agentlint-state\\n\");\n gitignoreUpdated = true;\n }\n\n const lines: Array<string> = [];\n\n if (configCreated) {\n lines.push(\"✓ Created agentlint.config.ts\");\n } else {\n lines.push(\"· agentlint.config.ts already exists — skipped\");\n }\n\n if (gitignoreUpdated) {\n lines.push(\"✓ Added .agentlint-state to .gitignore\");\n }\n\n // --- Step 2: Next steps ---\n const method = yield* detectSkillMethod(env.cwd);\n const skillCmd = method === \"intent\" ? INTENT_INSTALL_CMD : SKILLS_ADD_CMD;\n\n lines.push(\n \"\",\n \"Next steps:\",\n \" 1. Add rules to your config\",\n ` 2. Install the agentlint skill for your AI agents:`,\n ` ${skillCmd}`,\n \" 3. Run: npx agentlint check --all\",\n );\n\n return new InitResult({\n created: configCreated,\n message: lines.join(\"\\n\"),\n });\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport const RuleSummary = Schema.Struct({\n name: Schema.String,\n description: Schema.String,\n languages: Schema.Array(Schema.String),\n include: Schema.UndefinedOr(Schema.Array(Schema.String)),\n ignore: Schema.UndefinedOr(Schema.Array(Schema.String)),\n});\n\n/** @since 0.1.0 */\nexport type RuleSummary = Schema.Schema.Type<typeof RuleSummary>;\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ListCommand extends Schema.TaggedClass<ListCommand>()(\"ListCommand\", {}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ListResult extends Schema.TaggedClass<ListResult>()(\"ListResult\", {\n /** All registered rules with their metadata. */\n rules: Schema.Array(RuleSummary),\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect } from \"effect\";\nimport { ConfigLoader } from \"../../shared/infrastructure/config-loader.js\";\nimport { ListCommand, ListResult } from \"./request.js\";\n\n/** @since 0.1.0 */\nexport const listHandler = Effect.fn(\"listHandler\")(function* (_command: ListCommand) {\n const configLoader = yield* ConfigLoader;\n const config = yield* configLoader.load();\n\n const rules = Object.entries(config.rules).map(([name, rule]) => ({\n name,\n description: rule.meta.description,\n languages: rule.meta.languages,\n include: rule.meta.include,\n ignore: rule.meta.ignore,\n }));\n\n return new ListResult({ rules });\n});\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ReviewCommand extends Schema.TaggedClass<ReviewCommand>()(\"ReviewCommand\", {\n /** Specific hashes to mark as reviewed. */\n hashes: Schema.Array(Schema.String),\n /** When `true`, mark all current flags as reviewed. */\n all: Schema.Boolean,\n /** When `true`, wipe the state file. */\n reset: Schema.Boolean,\n}) {}\n\n/**\n * @since 0.1.0\n * @category models\n */\nexport class ReviewResult extends Schema.TaggedClass<ReviewResult>()(\"ReviewResult\", {\n /** Human-readable message describing what happened. */\n message: Schema.String,\n}) {}\n","/**\n * @module\n * @since 0.1.0\n */\n\nimport { Effect } from \"effect\";\nimport { StateStore } from \"../../shared/infrastructure/state-store.js\";\nimport { collectFlags } from \"../../shared/pipeline/collect-flags.js\";\nimport { ReviewCommand, ReviewResult } from \"./request.js\";\n\n/** @since 0.1.0 */\nexport const reviewHandler = Effect.fn(\"reviewHandler\")(function* (command: ReviewCommand) {\n const stateStore = yield* StateStore;\n\n if (command.reset) {\n yield* stateStore.reset();\n return new ReviewResult({ message: \"Cleared .agentlint-state\" });\n }\n\n if (command.all) {\n const result = yield* collectFlags({\n all: true,\n rules: [],\n dryRun: false,\n base: undefined,\n files: [],\n });\n const allFlags = result.flags;\n if (allFlags.length === 0) {\n return new ReviewResult({ message: \"No flags to review.\" });\n }\n yield* stateStore.append(allFlags.map((f) => f.hash));\n return new ReviewResult({ message: `Marked ${allFlags.length} flag(s) as reviewed.` });\n }\n\n if (command.hashes.length > 0) {\n yield* stateStore.append([...command.hashes]);\n return new ReviewResult({ message: `Marked ${command.hashes.length} hash(es) as reviewed.` });\n }\n\n return new ReviewResult({\n message: [\n \"Usage:\",\n \" agentlint review <hash...> Mark specific flags as reviewed\",\n \" agentlint review --all Mark all current flags as reviewed\",\n \" agentlint review --reset Wipe the state file\",\n ].join(\"\\n\"),\n });\n});\n","/**\n * Terminal reporter — formats flag results into human-readable output.\n *\n * Respects `NO_COLOR` and non-TTY environments. Groups flags by rule,\n * then by file, and appends instruction/hint blocks when available.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Effect, HashMap, Option, Path, Schema } from \"effect\";\nimport { Env } from \"../config/env.js\";\nimport type { FlagRecord } from \"../domain/flag.js\";\nimport type { RuleMeta } from \"../domain/rule.js\";\n\n/**\n * Group an array by a key function, returning a HashMap of arrays.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction groupBy<A>(items: ReadonlyArray<A>, key: (a: A) => string): HashMap.HashMap<string, A[]> {\n return items.reduce((acc, item) => {\n const k = key(item);\n const existing = Option.getOrUndefined(HashMap.get(acc, k));\n return existing ? (existing.push(item), acc) : HashMap.set(acc, k, [item]);\n }, HashMap.empty<string, A[]>());\n}\n\n/**\n * Build the minimal ANSI escape helpers. Each function is a no-op when\n * `noColor` is `true`.\n *\n * @since 0.1.0\n * @category internals\n */\nfunction makeAnsi(noColor: boolean) {\n return {\n bold: (s: string) => (noColor ? s : `\\x1b[1m${s}\\x1b[22m`),\n dim: (s: string) => (noColor ? s : `\\x1b[2m${s}\\x1b[22m`),\n yellow: (s: string) => (noColor ? s : `\\x1b[33m${s}\\x1b[39m`),\n cyan: (s: string) => (noColor ? s : `\\x1b[36m${s}\\x1b[39m`),\n magenta: (s: string) => (noColor ? s : `\\x1b[35m${s}\\x1b[39m`),\n gray: (s: string) => (noColor ? s : `\\x1b[90m${s}\\x1b[39m`),\n underline: (s: string) => (noColor ? s : `\\x1b[4m${s}\\x1b[24m`),\n reset: noColor ? \"\" : \"\\x1b[0m\",\n };\n}\n\n/**\n * Options that control the reporter's output format.\n *\n * @since 0.1.0\n * @category models\n */\nexport const ReporterOptions = Schema.Struct({\n /** When `true`, instruction and hint blocks are suppressed. */\n dryRun: Schema.Boolean,\n /** Version string displayed in the header line. */\n version: Schema.String,\n});\n\n/** @since 0.1.0 */\nexport type ReporterOptions = Schema.Schema.Type<typeof ReporterOptions>;\n\n/**\n * Format flag results into a terminal-friendly report string.\n *\n * Groups flags by rule name, then by file path. Includes source\n * snippets, per-match instructions/hints, and a summary line.\n * Returns a single \"no rules triggered\" line when the flag list\n * is empty.\n *\n * Uses the `Env` service for colour/cwd detection and the Effect\n * `Path` service for cross-platform path resolution.\n *\n * @since 0.1.0\n * @category constructors\n */\nexport const formatReport = Effect.fn(\"formatReport\")(function* (\n flags: ReadonlyArray<FlagRecord>,\n rulesMeta: HashMap.HashMap<string, RuleMeta>,\n options: ReporterOptions,\n) {\n const env = yield* Env;\n const path = yield* Path.Path;\n const ansi = makeAnsi(env.noColor);\n\n if (flags.length === 0) {\n return `${ansi.bold(\"agentlint\")} ${ansi.dim(`v${options.version}`)} ${ansi.dim(\"-\")} no rules triggered.`;\n }\n\n const { cwd } = env;\n const lines: string[] = [];\n\n const grouped = groupBy(flags, (f) => f.ruleName);\n\n const groupedSize = HashMap.size(grouped);\n\n if (flags.length > 50) {\n lines.push(\n ansi.yellow(\"⚠\") +\n ` ${flags.length} matches across ${groupedSize} rules. ` +\n ansi.dim(\"Consider narrowing scope with --rule or targeting specific files.\"),\n );\n lines.push(\"\");\n }\n\n for (const [ruleName, ruleFlags] of grouped) {\n const meta = Option.getOrUndefined(HashMap.get(rulesMeta, ruleName));\n\n lines.push(ansi.yellow(` x ${ruleName}`) + ansi.dim(meta ? `: ${meta.description}` : \"\"));\n lines.push(\"\");\n\n const byFile = groupBy(ruleFlags, (f) => path.relative(cwd, f.filename).replace(/\\\\/g, \"/\"));\n\n for (const [_filePath, fileFlags] of byFile) {\n for (const flag of fileFlags) {\n const relPath = path.relative(cwd, flag.filename).replace(/\\\\/g, \"/\");\n const loc = `${relPath}:${flag.line}:${flag.col}`;\n const snippet = flag.sourceSnippet.length > 80 ? flag.sourceSnippet.slice(0, 77) + \"...\" : flag.sourceSnippet;\n\n lines.push(` ${ansi.cyan(loc)} ${ansi.dim(`[${flag.hash}]`)} ${flag.message}`);\n if (snippet && snippet !== flag.message) {\n lines.push(` ${ansi.dim(snippet)}`);\n }\n lines.push(\"\");\n }\n }\n\n if (!options.dryRun && meta?.instruction) {\n lines.push(ansi.dim(\" ┌─ Instruction ─────────────────────────────────\"));\n for (const instrLine of meta.instruction.split(\"\\n\")) {\n lines.push(ansi.dim(` │ ${instrLine}`));\n }\n lines.push(ansi.dim(\" └───────────────────────────────────────────────\"));\n lines.push(\"\");\n }\n\n const matchNotes = ruleFlags.filter((f) => f.instruction || f.suggest);\n if (!options.dryRun && matchNotes.length > 0) {\n for (const flag of matchNotes) {\n const relPath = path.relative(cwd, flag.filename).replace(/\\\\/g, \"/\");\n if (flag.instruction) {\n lines.push(` ${ansi.magenta(\"note\")} ${ansi.dim(`${relPath}:${flag.line}`)} ${flag.instruction}`);\n }\n if (flag.suggest) {\n lines.push(` ${ansi.magenta(\"hint\")} ${ansi.dim(`${relPath}:${flag.line}`)} ${flag.suggest}`);\n }\n }\n lines.push(\"\");\n }\n }\n\n const ruleWord = groupedSize === 1 ? \"rule\" : \"rules\";\n const matchWord = flags.length === 1 ? \"match\" : \"matches\";\n lines.push(ansi.bold(ansi.yellow(`Found ${flags.length} ${matchWord}`)) + ansi.dim(` (${groupedSize} ${ruleWord})`));\n\n return lines.join(\"\\n\");\n});\n","#!/usr/bin/env node\n/**\n * CLI entry point for `agentlint`.\n *\n * Thin adapter that translates CLI arguments into feature commands,\n * dispatches to the appropriate handler, and formats the result\n * for terminal output.\n *\n * @module\n * @since 0.1.0\n */\n\nimport * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as NodeServices from \"@effect/platform-node/NodeServices\";\nimport { Console, Effect, HashMap, Layer, Option } from \"effect\";\nimport { Argument, Command, Flag } from \"effect/unstable/cli\";\nimport { checkHandler } from \"./features/check/handler.js\";\nimport { CheckCommand } from \"./features/check/request.js\";\nimport { initHandler } from \"./features/init/handler.js\";\nimport { InitCommand } from \"./features/init/request.js\";\nimport { listHandler } from \"./features/list/handler.js\";\nimport { ListCommand } from \"./features/list/request.js\";\nimport { reviewHandler } from \"./features/review/handler.js\";\nimport { ReviewCommand } from \"./features/review/request.js\";\nimport { Env } from \"./config/env.js\";\nimport { ConfigLoader } from \"./shared/infrastructure/config-loader.js\";\nimport { Git } from \"./shared/infrastructure/git.js\";\nimport { Parser } from \"./shared/infrastructure/parser.js\";\nimport { StateStore } from \"./shared/infrastructure/state-store.js\";\nimport { formatReport } from \"./cli/reporter.js\";\nimport type { RuleMeta } from \"./domain/rule.js\";\n\ndeclare const __AGENTLINT_VERSION__: string;\n\n/** The `check` subcommand — scans files and outputs a report. */\nconst check = Command.make(\n \"check\",\n {\n files: Argument.string(\"files\").pipe(\n Argument.withDescription(\"Specific files or globs to scan\"),\n Argument.variadic(),\n ),\n all: Flag.boolean(\"all\").pipe(Flag.withAlias(\"a\"), Flag.withDescription(\"Scan all files (not just git diff)\")),\n rule: Flag.string(\"rule\").pipe(\n Flag.withAlias(\"r\"),\n Flag.withDescription(\"Run only this rule (comma-separated for multiple)\"),\n Flag.optional,\n ),\n dryRun: Flag.boolean(\"dry-run\").pipe(\n Flag.withAlias(\"d\"),\n Flag.withDescription(\"Show counts only, no instruction blocks\"),\n ),\n base: Flag.string(\"base\").pipe(Flag.withDescription(\"Git ref to diff against\"), Flag.optional),\n },\n (config) => {\n const ruleFilter = Option.match(config.rule, {\n onNone: () => [] as ReadonlyArray<string>,\n onSome: (r: string) => r.split(\",\").map((s) => s.trim()),\n });\n const baseRef = Option.match(config.base, {\n onNone: () => undefined,\n onSome: (b: string) => b,\n });\n\n return Effect.gen(function* () {\n const env = yield* Env;\n const result = yield* checkHandler(\n new CheckCommand({\n all: config.all,\n rules: ruleFilter,\n dryRun: config.dryRun,\n base: baseRef,\n files: config.files,\n }),\n );\n\n if (result.noMatchingRules) {\n yield* Console.log(`No matching rules found. Available: ${result.availableRules.join(\", \")}`);\n return;\n }\n\n if (result.totalFlags === 0) {\n yield* Console.log(`agentlint v${__AGENTLINT_VERSION__} - no rules triggered.`);\n return;\n }\n\n const configLoader = yield* ConfigLoader;\n const cfg = yield* configLoader.load();\n const rulesMeta: HashMap.HashMap<string, RuleMeta> = HashMap.fromIterable(\n Object.entries(cfg.rules).map(([name, rule]) => [name, rule.meta] as const),\n );\n\n const output = yield* formatReport(result.flags, rulesMeta, {\n dryRun: config.dryRun,\n version: __AGENTLINT_VERSION__,\n });\n\n yield* Console.log(output);\n\n if (result.filteredCount > 0) {\n yield* Console.log(\n ` (${result.filteredCount} reviewed flag(s) hidden — run agentlint review --reset to clear)`,\n );\n }\n\n if (result.flags.length > 0) {\n env.setExitCode(1);\n }\n });\n },\n).pipe(Command.withDescription(\"Scan files and output report for AI agents\"));\n\n/** The `list` subcommand — prints all registered rules. */\nconst list = Command.make(\"list\", {}, () =>\n Effect.gen(function* () {\n const result = yield* listHandler(new ListCommand({}));\n\n if (result.rules.length === 0) {\n yield* Console.log(\"No rules registered.\");\n return;\n }\n\n yield* Console.log(`${result.rules.length} rule(s) registered:\\n`);\n\n for (const rule of result.rules) {\n const langs = rule.languages.join(\", \");\n yield* Console.log(` ${rule.name}`);\n yield* Console.log(` ${rule.description}`);\n yield* Console.log(` Languages: ${langs}`);\n if (rule.include) {\n yield* Console.log(` Include: ${rule.include.join(\", \")}`);\n }\n if (rule.ignore) {\n yield* Console.log(` Ignore: ${rule.ignore.join(\", \")}`);\n }\n yield* Console.log();\n }\n }),\n).pipe(Command.withDescription(\"List all registered rules\"));\n\n/** The `init` subcommand — scaffolds a starter config file. */\nconst init = Command.make(\"init\", {}, () =>\n Effect.gen(function* () {\n const result = yield* initHandler(new InitCommand({}));\n yield* Console.log(result.message);\n }),\n).pipe(Command.withDescription(\"Create agentlint.config.ts and set up agent skill discovery\"));\n\n/** The `review` subcommand — manage reviewed-flag state. */\nconst review = Command.make(\n \"review\",\n {\n hashes: Argument.string(\"hashes\").pipe(\n Argument.withDescription(\"Flag hashes to mark as reviewed\"),\n Argument.variadic(),\n ),\n all: Flag.boolean(\"all\").pipe(Flag.withAlias(\"a\"), Flag.withDescription(\"Mark all current flags as reviewed\")),\n reset: Flag.boolean(\"reset\").pipe(Flag.withDescription(\"Wipe the state file\")),\n },\n (config) =>\n Effect.gen(function* () {\n const result = yield* reviewHandler(\n new ReviewCommand({\n hashes: config.hashes,\n all: config.all,\n reset: config.reset,\n }),\n );\n yield* Console.log(result.message);\n }),\n).pipe(Command.withDescription(\"Mark flags as reviewed (filters them from check output)\"));\n\nconst agentlint = Command.make(\"agentlint\").pipe(\n Command.withDescription(\"Deterministic linting for AI agents\"),\n Command.withSubcommands([check, list, init, review]),\n);\n\nconst AppLayer = Layer.mergeAll(ConfigLoader.layer, Parser.layer, Git.layer, StateStore.layer).pipe(\n Layer.provideMerge(NodeServices.layer),\n Layer.provideMerge(Env.layer),\n);\n\n// The CLI framework uses `unknown` for aggregated service requirements,\n// which doesn't fully resolve via `Effect.provide`. Cast to satisfy\n// `NodeRuntime.runMain`'s `never` requirement constraint.\nconst program = Command.run(agentlint, { version: __AGENTLINT_VERSION__ }).pipe(\n Effect.provide(AppLayer),\n) as Effect.Effect<void>;\n\nNodeRuntime.runMain(program);\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -85,7 +85,7 @@ interface FlagOptions {
85
85
  /** Hint toward the fix. Not a command - just a nudge. */
86
86
  readonly suggest?: string | undefined;
87
87
  }
88
- declare const FlagRecord_base: Schema.ExtendableClass<FlagRecord, Schema.Struct<{
88
+ declare const FlagRecord_base: Schema.Class<FlagRecord, Schema.Struct<{
89
89
  readonly ruleName: Schema.String;
90
90
  readonly filename: Schema.String; /** 1-based line number. */
91
91
  readonly line: Schema.Number; /** 1-based column number. */
@@ -141,7 +141,7 @@ interface RuleContext {
141
141
  * @category models
142
142
  */
143
143
  declare const RuleMeta: Schema.Struct<{
144
- /** Unique identifier. kebab-case. Used in output, --rule filtering, agentreview-ignore. */readonly name: Schema.String; /** One-liner explaining what the rule checks. */
144
+ /** Unique identifier. kebab-case. Used in output, --rule filtering, agentlint-ignore. */readonly name: Schema.String; /** One-liner explaining what the rule checks. */
145
145
  readonly description: Schema.String; /** File extensions this rule applies to, without the dot. e.g. `["ts", "tsx"]` */
146
146
  readonly languages: Schema.$Array<Schema.String>;
147
147
  /**
@@ -193,7 +193,7 @@ type Visitors = {
193
193
  interface AgentReviewRule {
194
194
  readonly meta: RuleMeta;
195
195
  /**
196
- * Called once per agentreview run (not per file).
196
+ * Called once per agentlint run (not per file).
197
197
  * The returned visitor object is reused across files.
198
198
  * Per-file state must be reset in `before()`.
199
199
  */
@@ -204,7 +204,7 @@ interface AgentReviewRule {
204
204
  *
205
205
  * @example
206
206
  * ```ts
207
- * import { defineRule } from "agentreview"
207
+ * import { defineRule } from "agentlint"
208
208
  *
209
209
  * export const myRule = defineRule({
210
210
  * meta: {
@@ -230,7 +230,7 @@ declare function defineRule(rule: AgentReviewRule): AgentReviewRule;
230
230
  //#endregion
231
231
  //#region src/domain/config.d.ts
232
232
  /**
233
- * Top-level configuration schema for `agentreview.config.ts`.
233
+ * Top-level configuration schema for `agentlint.config.ts`.
234
234
  *
235
235
  * @since 0.1.0
236
236
  * @category models
@@ -248,7 +248,7 @@ interface AgentReviewConfig {
248
248
  *
249
249
  * @example
250
250
  * ```ts
251
- * import { defineConfig } from "agentreview"
251
+ * import { defineConfig } from "agentlint"
252
252
  *
253
253
  * export default defineConfig({
254
254
  * include: ["src/**\/*.ts"],
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/domain/node.ts","../src/domain/node-types.ts","../src/domain/flag.ts","../src/domain/rule-context.ts","../src/domain/rule.ts","../src/domain/config.ts"],"mappings":";;;;;;;;;;;cAuBa,QAAA,EAAQ,MAAA,CAAA,MAAA;EAAA;;;;KAMT,QAAA,GAAW,MAAA,CAAO,MAAA,CAAO,IAAA,QAAY,QAAA;;;;;;AAWjD;;;;UAAiB,eAAA;EAYkB;EAAA,SAVxB,IAAA;EAYQ;EAAA,SAVR,IAAA;EAiBmC;EAAA,SAfnC,aAAA,EAAe,QAAA;EAiBuB;EAAA,SAftC,WAAA,EAAa,QAAA;EAewB;EAAA,SAbrC,OAAA;EARA;EAAA,SAUA,QAAA,EAAU,aAAA,CAAc,eAAA;EANxB;EAAA,SAQA,MAAA,EAAQ,eAAA;EANR;EAAA,SAQA,UAAA;EANA;EAST,gBAAA,CAAiB,IAAA,WAAe,eAAA;EAPb;EASnB,cAAA,CAAe,IAAA,WAAe,aAAA,CAAc,eAAA;EAPnC;EAST,iBAAA,CAAkB,IAAA,WAAe,aAAA,CAAc,eAAA;AAAA;;;;;;;AAxCjD;;;;;;;;;KCTY,kBAAA;;;;;;;;;UCKK,WAAA;;WAEN,IAAA,EAAM,eAAA;;WAEN,OAAA;EFMC;;;;EAAA,SEDD,WAAA;EFCmB;EAAA,SECnB,OAAA;AAAA;AAAA,cACV,eAAA;;oCFS+B;EAAA,8BAMN;EAAA;;yCAQP;EAAA;;;;;;;;;;;;;cEZN,UAAA,SAAmB,eAAA;;;;;;;;;UCvBf,WAAA;;EAEf,WAAA;;EAEA,aAAA;;AHMF;;;;EGAE,cAAA,CAAe,IAAA,UAAc,MAAA;EHAD;EGE5B,IAAA,CAAK,OAAA,EAAS,WAAA;AAAA;;;;;;;;;;;AHFhB;;cIHa,QAAA,EAAQ,MAAA,CAAA,MAAA;EJGoB,yHAAX;EAAA,qCAAmB;EAAA;EAAQ;AAWzD;;;EAXyD,qCAmBjC;EAAA,iEAIH;EAAA;;;KIPT,QAAA,GAAW,MAAA,CAAO,MAAA,CAAO,IAAA,QAAY,QAAA;;;;;;;KAQrC,cAAA,IAAkB,IAAA,EAAM,eAAA;;;;;;;;;;KAWxB,QAAA;EJLV;;;;EIUA,MAAA,KAAW,QAAA;EJRmB;;;;EIa9B,KAAA;AAAA,YACU,kBAAA,IAAsB,cAAA;EAAA,CAC/B,QAAA,WAAmB,cAAA,KAAmB,QAAA;AAAA;;AH9DzC;;;;;UGuEiB,eAAA;EAAA,SACN,IAAA,EAAM,QAAA;;AFnEjB;;;;WEyEW,UAAA,GAAa,OAAA,EAAS,WAAA,KAAgB,QAAA;AAAA;;;;;;AF7DhD;;;;;;;;;;;;;;;;;;;;;;iBE2Fe,UAAA,CAAW,IAAA,EAAM,eAAA,GAAkB,eAAA;;;;;;;;;UCrGlC,iBAAA;;WAEN,KAAA,EAAO,MAAA,SAAe,eAAA;;WAEtB,OAAA,GAAU,aAAA;ELIT;EAAA,SKFD,MAAA,GAAS,aAAA;AAAA;;;;;;;;ALapB;;;;;;;;;iBKMgB,YAAA,CAAa,MAAA,EAAQ,iBAAA,GAAoB,iBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/domain/node.ts","../src/domain/node-types.ts","../src/domain/flag.ts","../src/domain/rule-context.ts","../src/domain/rule.ts","../src/domain/config.ts"],"mappings":";;;;;;;;;;;cAuBa,QAAA,EAAQ,MAAA,CAAA,MAAA;EAAA;;;;KAMT,QAAA,GAAW,MAAA,CAAO,MAAA,CAAO,IAAA,QAAY,QAAA;;;;;;AAWjD;;;;UAAiB,eAAA;EAYkB;EAAA,SAVxB,IAAA;EAYQ;EAAA,SAVR,IAAA;EAiBmC;EAAA,SAfnC,aAAA,EAAe,QAAA;EAiBuB;EAAA,SAftC,WAAA,EAAa,QAAA;EAewB;EAAA,SAbrC,OAAA;EARA;EAAA,SAUA,QAAA,EAAU,aAAA,CAAc,eAAA;EANxB;EAAA,SAQA,MAAA,EAAQ,eAAA;EANR;EAAA,SAQA,UAAA;EANA;EAST,gBAAA,CAAiB,IAAA,WAAe,eAAA;EAPb;EASnB,cAAA,CAAe,IAAA,WAAe,aAAA,CAAc,eAAA;EAPnC;EAST,iBAAA,CAAkB,IAAA,WAAe,aAAA,CAAc,eAAA;AAAA;;;;;;;AAxCjD;;;;;;;;;KCTY,kBAAA;;;;;;;;;UCKK,WAAA;;WAEN,IAAA,EAAM,eAAA;;WAEN,OAAA;EFMC;;;;EAAA,SEDD,WAAA;EFCmB;EAAA,SECnB,OAAA;AAAA;AAAA,cACV,eAAA;;oCFS+B;EAAA,8BAMN;EAAA;;yCAQP;EAAA;;;;;;;;;;;;;cEZN,UAAA,SAAmB,eAAA;;;;;;;;;UCvBf,WAAA;;EAEf,WAAA;;EAEA,aAAA;;AHMF;;;;EGAE,cAAA,CAAe,IAAA,UAAc,MAAA;EHAD;EGE5B,IAAA,CAAK,OAAA,EAAS,WAAA;AAAA;;;;;;;;;;;AHFhB;;cIHa,QAAA,EAAQ,MAAA,CAAA,MAAA;EJGoB,uHAAX;EAAA,qCAAmB;EAAA;EAAQ;AAWzD;;;EAXyD,qCAmBjC;EAAA,iEAIH;EAAA;;;KIPT,QAAA,GAAW,MAAA,CAAO,MAAA,CAAO,IAAA,QAAY,QAAA;;;;;;;KAQrC,cAAA,IAAkB,IAAA,EAAM,eAAA;;;;;;;;;;KAWxB,QAAA;EJLV;;;;EIUA,MAAA,KAAW,QAAA;EJRmB;;;;EIa9B,KAAA;AAAA,YACU,kBAAA,IAAsB,cAAA;EAAA,CAC/B,QAAA,WAAmB,cAAA,KAAmB,QAAA;AAAA;;AH9DzC;;;;;UGuEiB,eAAA;EAAA,SACN,IAAA,EAAM,QAAA;;AFnEjB;;;;WEyEW,UAAA,GAAa,OAAA,EAAS,WAAA,KAAgB,QAAA;AAAA;;;;;;AF7DhD;;;;;;;;;;;;;;;;;;;;;;iBE2Fe,UAAA,CAAW,IAAA,EAAM,eAAA,GAAkB,eAAA;;;;;;;;;UCrGlC,iBAAA;;WAEN,KAAA,EAAO,MAAA,SAAe,eAAA;;WAEtB,OAAA,GAAU,aAAA;ELIT;EAAA,SKFD,MAAA,GAAS,aAAA;AAAA;;;;;;;;ALapB;;;;;;;;;iBKMgB,YAAA,CAAa,MAAA,EAAQ,iBAAA,GAAoB,iBAAA"}
package/dist/index.mjs CHANGED
@@ -34,7 +34,7 @@ const RuleMeta = Schema.Struct({
34
34
  *
35
35
  * @example
36
36
  * ```ts
37
- * import { defineRule } from "agentreview"
37
+ * import { defineRule } from "agentlint"
38
38
  *
39
39
  * export const myRule = defineRule({
40
40
  * meta: {
@@ -65,7 +65,7 @@ function defineRule(rule) {
65
65
  /**
66
66
  * Configuration types and the `defineConfig` helper.
67
67
  *
68
- * A config file (`agentreview.config.ts`) default-exports an {@link AgentReviewConfig}
68
+ * A config file (`agentlint.config.ts`) default-exports an {@link AgentReviewConfig}
69
69
  * object that maps rule names to rule definitions and optionally scopes which
70
70
  * files are scanned.
71
71
  *
@@ -77,7 +77,7 @@ function defineRule(rule) {
77
77
  *
78
78
  * @example
79
79
  * ```ts
80
- * import { defineConfig } from "agentreview"
80
+ * import { defineConfig } from "agentlint"
81
81
  *
82
82
  * export default defineConfig({
83
83
  * include: ["src/**\/*.ts"],
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/domain/rule.ts","../src/domain/config.ts"],"sourcesContent":["/**\n * Rule definition types and the `defineRule` helper.\n *\n * A rule is a reusable lint check defined by {@link RuleMeta} (what to check)\n * and a `createOnce` factory (how to check it). The factory returns a\n * {@link Visitors} object whose keys are tree-sitter node types.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport type { AgentReviewNode } from \"./node.js\";\nimport type { TreeSitterNodeType } from \"./node-types.js\";\nimport type { RuleContext } from \"./rule-context.js\";\n\n/**\n * Static metadata for a rule.\n *\n * Defined as a `Schema.Struct` so that rule metadata is validated at\n * runtime when `defineRule` is called — catches typos, missing fields,\n * and wrong types with clear error messages.\n *\n * @since 0.1.0\n * @category models\n */\nexport const RuleMeta = Schema.Struct({\n /** Unique identifier. kebab-case. Used in output, --rule filtering, agentreview-ignore. */\n name: Schema.String,\n /** One-liner explaining what the rule checks. */\n description: Schema.String,\n /** File extensions this rule applies to, without the dot. e.g. `[\"ts\", \"tsx\"]` */\n languages: Schema.Array(Schema.String),\n /**\n * Natural language instruction for the calling AI agent.\n * Defines pass/fail criteria and how to evaluate flagged matches.\n */\n instruction: Schema.String,\n /** If provided, rule only runs on files matching these globs (after global filtering). */\n include: Schema.optional(Schema.Array(Schema.String)),\n /** If provided, files matching these globs are excluded from this rule. */\n ignore: Schema.optional(Schema.Array(Schema.String)),\n});\n\n/** @since 0.1.0 */\nexport type RuleMeta = Schema.Schema.Type<typeof RuleMeta>;\n\n/**\n * Callback invoked when a matching AST node type is visited.\n *\n * @since 0.1.0\n * @category models\n */\nexport type VisitorHandler = (node: AgentReviewNode) => void;\n\n/**\n * Visitor object returned by `createOnce`.\n *\n * Maps tree-sitter node type strings to handler functions.\n * Known node types provide autocomplete; any string is accepted.\n *\n * @since 0.1.0\n * @category models\n */\nexport type Visitors = {\n /**\n * Called once before each file is traversed.\n * Return `false` to skip this file entirely for this rule.\n */\n before?: ((filename: string) => boolean | void) | undefined;\n /**\n * Called once after all files have been visited.\n * Use for aggregate analysis.\n */\n after?: (() => void) | undefined;\n} & { [K in TreeSitterNodeType]?: VisitorHandler } & {\n [nodeType: string]: VisitorHandler | ((filename: string) => boolean | void) | (() => void) | undefined;\n};\n\n/**\n * A complete rule definition.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface AgentReviewRule {\n readonly meta: RuleMeta;\n /**\n * Called once per agentreview run (not per file).\n * The returned visitor object is reused across files.\n * Per-file state must be reset in `before()`.\n */\n readonly createOnce: (context: RuleContext) => Visitors;\n}\n\n/**\n * Identity function that provides type inference and IDE support for rule definitions.\n *\n * @example\n * ```ts\n * import { defineRule } from \"agentreview\"\n *\n * export const myRule = defineRule({\n * meta: {\n * name: \"my-rule\",\n * description: \"Checks for something\",\n * languages: [\"ts\", \"tsx\"],\n * instruction: \"Evaluate whether ...\"\n * },\n * createOnce(context) {\n * return {\n * comment(node) {\n * context.flag({ node, message: \"Found comment\" })\n * }\n * }\n * }\n * })\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function defineRule(rule: AgentReviewRule): AgentReviewRule {\n Schema.decodeUnknownSync(RuleMeta)(rule.meta);\n return rule;\n}\n","/**\n * Configuration types and the `defineConfig` helper.\n *\n * A config file (`agentreview.config.ts`) default-exports an {@link AgentReviewConfig}\n * object that maps rule names to rule definitions and optionally scopes which\n * files are scanned.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport type { AgentReviewRule } from \"./rule.js\";\nimport { RuleMeta } from \"./rule.js\";\n\n/**\n * Top-level configuration schema for `agentreview.config.ts`.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface AgentReviewConfig {\n /** Rule registry. Keys are kebab-case names used in output and `--rule` filtering. */\n readonly rules: Record<string, AgentReviewRule>;\n /** If provided, only files matching at least one pattern are scanned. */\n readonly include?: ReadonlyArray<string> | undefined;\n /** Files matching any pattern are excluded (merged with built-in defaults). */\n readonly ignore?: ReadonlyArray<string> | undefined;\n}\n\n/**\n * Identity function that provides type inference and IDE support for config files.\n *\n * @example\n * ```ts\n * import { defineConfig } from \"agentreview\"\n *\n * export default defineConfig({\n * include: [\"src/**\\/*.ts\"],\n * rules: { \"my-rule\": myRule }\n * })\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function defineConfig(config: AgentReviewConfig): AgentReviewConfig {\n for (const rule of Object.values(config.rules)) {\n Schema.decodeUnknownSync(RuleMeta)(rule.meta);\n }\n return config;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,WAAW,OAAO,OAAO;CAEpC,MAAM,OAAO;CAEb,aAAa,OAAO;CAEpB,WAAW,OAAO,MAAM,OAAO,OAAO;CAKtC,aAAa,OAAO;CAEpB,SAAS,OAAO,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC;CAErD,QAAQ,OAAO,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC;CACrD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFF,SAAgB,WAAW,MAAwC;AACjE,QAAO,kBAAkB,SAAS,CAAC,KAAK,KAAK;AAC7C,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9ET,SAAgB,aAAa,QAA8C;AACzE,MAAK,MAAM,QAAQ,OAAO,OAAO,OAAO,MAAM,CAC5C,QAAO,kBAAkB,SAAS,CAAC,KAAK,KAAK;AAE/C,QAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/domain/rule.ts","../src/domain/config.ts"],"sourcesContent":["/**\n * Rule definition types and the `defineRule` helper.\n *\n * A rule is a reusable lint check defined by {@link RuleMeta} (what to check)\n * and a `createOnce` factory (how to check it). The factory returns a\n * {@link Visitors} object whose keys are tree-sitter node types.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport type { AgentReviewNode } from \"./node.js\";\nimport type { TreeSitterNodeType } from \"./node-types.js\";\nimport type { RuleContext } from \"./rule-context.js\";\n\n/**\n * Static metadata for a rule.\n *\n * Defined as a `Schema.Struct` so that rule metadata is validated at\n * runtime when `defineRule` is called — catches typos, missing fields,\n * and wrong types with clear error messages.\n *\n * @since 0.1.0\n * @category models\n */\nexport const RuleMeta = Schema.Struct({\n /** Unique identifier. kebab-case. Used in output, --rule filtering, agentlint-ignore. */\n name: Schema.String,\n /** One-liner explaining what the rule checks. */\n description: Schema.String,\n /** File extensions this rule applies to, without the dot. e.g. `[\"ts\", \"tsx\"]` */\n languages: Schema.Array(Schema.String),\n /**\n * Natural language instruction for the calling AI agent.\n * Defines pass/fail criteria and how to evaluate flagged matches.\n */\n instruction: Schema.String,\n /** If provided, rule only runs on files matching these globs (after global filtering). */\n include: Schema.optional(Schema.Array(Schema.String)),\n /** If provided, files matching these globs are excluded from this rule. */\n ignore: Schema.optional(Schema.Array(Schema.String)),\n});\n\n/** @since 0.1.0 */\nexport type RuleMeta = Schema.Schema.Type<typeof RuleMeta>;\n\n/**\n * Callback invoked when a matching AST node type is visited.\n *\n * @since 0.1.0\n * @category models\n */\nexport type VisitorHandler = (node: AgentReviewNode) => void;\n\n/**\n * Visitor object returned by `createOnce`.\n *\n * Maps tree-sitter node type strings to handler functions.\n * Known node types provide autocomplete; any string is accepted.\n *\n * @since 0.1.0\n * @category models\n */\nexport type Visitors = {\n /**\n * Called once before each file is traversed.\n * Return `false` to skip this file entirely for this rule.\n */\n before?: ((filename: string) => boolean | void) | undefined;\n /**\n * Called once after all files have been visited.\n * Use for aggregate analysis.\n */\n after?: (() => void) | undefined;\n} & { [K in TreeSitterNodeType]?: VisitorHandler } & {\n [nodeType: string]: VisitorHandler | ((filename: string) => boolean | void) | (() => void) | undefined;\n};\n\n/**\n * A complete rule definition.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface AgentReviewRule {\n readonly meta: RuleMeta;\n /**\n * Called once per agentlint run (not per file).\n * The returned visitor object is reused across files.\n * Per-file state must be reset in `before()`.\n */\n readonly createOnce: (context: RuleContext) => Visitors;\n}\n\n/**\n * Identity function that provides type inference and IDE support for rule definitions.\n *\n * @example\n * ```ts\n * import { defineRule } from \"agentlint\"\n *\n * export const myRule = defineRule({\n * meta: {\n * name: \"my-rule\",\n * description: \"Checks for something\",\n * languages: [\"ts\", \"tsx\"],\n * instruction: \"Evaluate whether ...\"\n * },\n * createOnce(context) {\n * return {\n * comment(node) {\n * context.flag({ node, message: \"Found comment\" })\n * }\n * }\n * }\n * })\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function defineRule(rule: AgentReviewRule): AgentReviewRule {\n Schema.decodeUnknownSync(RuleMeta)(rule.meta);\n return rule;\n}\n","/**\n * Configuration types and the `defineConfig` helper.\n *\n * A config file (`agentlint.config.ts`) default-exports an {@link AgentReviewConfig}\n * object that maps rule names to rule definitions and optionally scopes which\n * files are scanned.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport type { AgentReviewRule } from \"./rule.js\";\nimport { RuleMeta } from \"./rule.js\";\n\n/**\n * Top-level configuration schema for `agentlint.config.ts`.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface AgentReviewConfig {\n /** Rule registry. Keys are kebab-case names used in output and `--rule` filtering. */\n readonly rules: Record<string, AgentReviewRule>;\n /** If provided, only files matching at least one pattern are scanned. */\n readonly include?: ReadonlyArray<string> | undefined;\n /** Files matching any pattern are excluded (merged with built-in defaults). */\n readonly ignore?: ReadonlyArray<string> | undefined;\n}\n\n/**\n * Identity function that provides type inference and IDE support for config files.\n *\n * @example\n * ```ts\n * import { defineConfig } from \"agentlint\"\n *\n * export default defineConfig({\n * include: [\"src/**\\/*.ts\"],\n * rules: { \"my-rule\": myRule }\n * })\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function defineConfig(config: AgentReviewConfig): AgentReviewConfig {\n for (const rule of Object.values(config.rules)) {\n Schema.decodeUnknownSync(RuleMeta)(rule.meta);\n }\n return config;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,WAAW,OAAO,OAAO;CAEpC,MAAM,OAAO;CAEb,aAAa,OAAO;CAEpB,WAAW,OAAO,MAAM,OAAO,OAAO;CAKtC,aAAa,OAAO;CAEpB,SAAS,OAAO,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC;CAErD,QAAQ,OAAO,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC;CACrD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFF,SAAgB,WAAW,MAAwC;AACjE,QAAO,kBAAkB,SAAS,CAAC,KAAK,KAAK;AAC7C,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9ET,SAAgB,aAAa,QAA8C;AACzE,MAAK,MAAM,QAAQ,OAAO,OAAO,OAAO,MAAM,CAC5C,QAAO,kBAAkB,SAAS,CAAC,KAAK,KAAK;AAE/C,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurelienbbn/agentlint",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Stateless, deterministic CLI that bridges traditional linters and AI-assisted code review",
5
5
  "keywords": [
6
6
  "agent",
@@ -33,8 +33,8 @@
33
33
  }
34
34
  },
35
35
  "dependencies": {
36
- "@effect/platform-node": "4.0.0-beta.43",
37
- "effect": "^4.0.0-beta.43",
36
+ "@effect/platform-node": "4.0.0-beta.44",
37
+ "effect": "4.0.0-beta.44",
38
38
  "jiti": "^2.4.2",
39
39
  "picomatch": "^4.0.2",
40
40
  "web-tree-sitter": "^0.25.3"
@@ -64,6 +64,6 @@
64
64
  "fmt": "oxfmt --write",
65
65
  "fmt:check": "oxfmt --check",
66
66
  "changeset": "changeset",
67
- "check": "pnpm typecheck && pnpm lint && pnpm fmt:check && pnpm test"
67
+ "check": "pnpm typecheck && pnpm lint && pnpm fmt:check && intent validate && pnpm test"
68
68
  }
69
69
  }
@@ -7,7 +7,7 @@ description: >
7
7
  linting, improve their feedback loop, or asks "how do I make sure X."
8
8
  type: core
9
9
  library: agentlint
10
- library_version: "0.1.0"
10
+ library_version: "0.1.1"
11
11
  sources:
12
12
  - "aurelienbobenrieth/agentlint:README.md"
13
13
  - "aurelienbobenrieth/agentlint:CONTRIBUTING.md"
@@ -125,7 +125,7 @@ handling or propagation."
125
125
  ### Testing
126
126
 
127
127
  ```bash
128
- npx agentlint check --all --rule rule-name
129
- npx agentlint check src/handlers/checkout.ts --rule rule-name
130
- npx agentlint check --all --rule rule-name --dry-run
128
+ pnpm agentlint check --all --rule rule-name
129
+ pnpm agentlint check src/handlers/checkout.ts --rule rule-name
130
+ pnpm agentlint check --all --rule rule-name --dry-run
131
131
  ```
@@ -8,7 +8,7 @@ description: >
8
8
  inline suppression, and output interpretation.
9
9
  type: core
10
10
  library: agentlint
11
- library_version: "0.1.0"
11
+ library_version: "0.1.1"
12
12
  sources:
13
13
  - "aurelienbobenrieth/agentlint:README.md"
14
14
  - "aurelienbobenrieth/agentlint:src/bin.ts"
@@ -21,8 +21,8 @@ Stateless, deterministic linter whose output is designed for you (an AI coding a
21
21
  ## Setup
22
22
 
23
23
  ```bash
24
- npm install agentlint
25
- npx agentlint init
24
+ pnpm add @aurelienbbn/agentlint
25
+ pnpm agentlint init
26
26
  ```
27
27
 
28
28
  This creates `agentlint.config.ts` with a starter template. Add rules to the `rules` object.
@@ -33,22 +33,22 @@ This creates `agentlint.config.ts` with a starter template. Add rules to the `ru
33
33
 
34
34
  ```bash
35
35
  # Default: scan files changed in current branch
36
- npx agentlint check
36
+ pnpm agentlint check
37
37
 
38
38
  # Scan specific files or globs
39
- npx agentlint check src/utils.ts "src/**/*.tsx"
39
+ pnpm agentlint check src/utils.ts "src/**/*.tsx"
40
40
 
41
41
  # Scan all files
42
- npx agentlint check --all
42
+ pnpm agentlint check --all
43
43
 
44
44
  # Only run a specific rule
45
- npx agentlint check --rule no-noise-comments
45
+ pnpm agentlint check --rule no-noise-comments
46
46
 
47
47
  # Dry-run (counts only, no instruction blocks)
48
- npx agentlint check --dry-run
48
+ pnpm agentlint check --dry-run
49
49
 
50
50
  # Diff against a specific branch
51
- npx agentlint check --base main
51
+ pnpm agentlint check --base main
52
52
  ```
53
53
 
54
54
  ### Read and act on output
@@ -70,13 +70,13 @@ Process one rule section at a time:
70
70
 
71
71
  ```bash
72
72
  # Mark specific hashes as reviewed (they disappear from future output)
73
- npx agentlint review abc1234 def5678
73
+ pnpm agentlint review abc1234 def5678
74
74
 
75
75
  # Mark all current flags as reviewed
76
- npx agentlint review --all
76
+ pnpm agentlint review --all
77
77
 
78
78
  # Reset reviewed state (see all flags again)
79
- npx agentlint review --reset
79
+ pnpm agentlint review --reset
80
80
  ```
81
81
 
82
82
  ### Suppress inline
@@ -123,14 +123,14 @@ Wrong:
123
123
 
124
124
  ```bash
125
125
  # Treating non-zero exit as a failure and stopping
126
- npx agentlint check || echo "agentlint failed"
126
+ pnpm agentlint check || echo "agentlint failed"
127
127
  ```
128
128
 
129
129
  Correct:
130
130
 
131
131
  ```bash
132
132
  # Exit code 1 means findings exist — read and evaluate the output
133
- npx agentlint check
133
+ pnpm agentlint check
134
134
  # Then process the stdout, don't treat it as a crash
135
135
  ```
136
136