revu-ai 0.1.1 → 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/discovery.js CHANGED
@@ -1,11 +1,71 @@
1
+ import { execFileSync } from "node:child_process";
1
2
  import { readFileSync, existsSync } from "node:fs";
2
3
  import { join, resolve, sep } from "node:path";
3
4
  import fg from "fast-glob";
4
5
  import ignoreImport from "ignore";
5
6
  // `ignore` is published as CJS; under NodeNext its default export is the factory itself.
6
7
  const ignore = ignoreImport.default ?? ignoreImport;
7
- const ALWAYS_IGNORE = ["node_modules/**", ".git/**", "dist/**", "build/**"];
8
+ // Names we always skip even if the user hasn't gitignored them. Defensive against
9
+ // repos that vendor deps or build outputs without a .gitignore entry.
10
+ const ALWAYS_IGNORE_NAMES = ["node_modules", ".git", "dist", "build"];
11
+ // fast-glob's `ignore` patterns are micromatch globs without an implicit `**/` prefix —
12
+ // `node_modules/**` only matches at the cwd root, so nested `node_modules` (workspaces,
13
+ // pnpm, vendored deps) get walked. These patterns prune at any depth.
14
+ const FG_ALWAYS_IGNORE = ALWAYS_IGNORE_NAMES.map((n) => `**/${n}`);
15
+ // Git pathspec exclusions. `:(exclude,glob)` removes paths even if they're tracked
16
+ // or not gitignored — `--exclude-standard` only applies .gitignore rules, so a tracked
17
+ // `node_modules` (rare but possible) would otherwise leak through.
18
+ const GIT_EXCLUDE_PATHSPECS = ALWAYS_IGNORE_NAMES.map((n) => `:(exclude,glob)**/${n}/**`);
8
19
  export async function discoverRules(repoRoot, pattern) {
20
+ const matches = isGitRepo(repoRoot)
21
+ ? listFromGit(repoRoot, pattern)
22
+ : await listFromFs(repoRoot, pattern);
23
+ return matches.map((rel) => {
24
+ const abs = resolve(repoRoot, rel);
25
+ return {
26
+ ruleId: deriveRuleId(rel),
27
+ absPath: abs,
28
+ relPath: rel,
29
+ content: readFileSync(abs, "utf8"),
30
+ };
31
+ });
32
+ }
33
+ function isGitRepo(repoRoot) {
34
+ try {
35
+ execFileSync("git", ["rev-parse", "--git-dir"], {
36
+ cwd: repoRoot,
37
+ stdio: ["ignore", "ignore", "ignore"],
38
+ });
39
+ return true;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ // In a git repo, defer to git: it already honors every .gitignore source (root,
46
+ // nested, global, .git/info/exclude), respects worktree boundaries, and reads from
47
+ // the index. On a 50 GB monorepo this is orders of magnitude faster than walking
48
+ // the filesystem — git only knows about tracked files plus untracked-not-ignored,
49
+ // so traversal is bounded by repo size rather than disk size.
50
+ //
51
+ // -c include tracked files
52
+ // -o include untracked-not-ignored files
53
+ // --exclude-standard apply .gitignore + .git/info/exclude + global excludes
54
+ // -z null-delimit output (safe for paths with newlines/quotes)
55
+ // :(glob)… opt into glob-style `**` pathspec semantics
56
+ function listFromGit(repoRoot, pattern) {
57
+ const out = execFileSync("git", [
58
+ "ls-files",
59
+ "-co",
60
+ "--exclude-standard",
61
+ "-z",
62
+ "--",
63
+ `:(glob)${pattern}`,
64
+ ...GIT_EXCLUDE_PATHSPECS,
65
+ ], { cwd: repoRoot, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
66
+ return out.split("\0").filter(Boolean).sort();
67
+ }
68
+ async function listFromFs(repoRoot, pattern) {
9
69
  const ig = ignore();
10
70
  const gitignorePath = join(repoRoot, ".gitignore");
11
71
  if (existsSync(gitignorePath)) {
@@ -14,19 +74,10 @@ export async function discoverRules(repoRoot, pattern) {
14
74
  const matches = await fg(pattern, {
15
75
  cwd: repoRoot,
16
76
  dot: true,
17
- ignore: ALWAYS_IGNORE,
77
+ ignore: FG_ALWAYS_IGNORE,
18
78
  onlyFiles: true,
19
79
  });
20
- const filtered = matches.filter((rel) => !ig.ignores(rel));
21
- return filtered.map((rel) => {
22
- const abs = resolve(repoRoot, rel);
23
- return {
24
- ruleId: deriveRuleId(rel),
25
- absPath: abs,
26
- relPath: rel,
27
- content: readFileSync(abs, "utf8"),
28
- };
29
- });
80
+ return matches.filter((rel) => !ig.ignores(rel)).sort();
30
81
  }
31
82
  function deriveRuleId(relPath) {
32
83
  const withoutSuffix = relPath.replace(/\.revu\.md$/i, "");
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAY,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,YAAY,MAAM,QAAQ,CAAC;AAGlC,yFAAyF;AACzF,MAAM,MAAM,GAAI,YAA6D,CAAC,OAAO,IAAI,YAAY,CAAC;AAEtG,MAAM,aAAa,GAAG,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AAE5E,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IACnE,MAAM,EAAE,GAAI,MAAyF,EAAE,CAAC;IACxG,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACnD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,EAAE;QAChC,GAAG,EAAE,QAAQ;QACb,GAAG,EAAE,IAAI;QACT,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAE3D,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAY,EAAE;QACpC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO;YACL,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC;YACzB,OAAO,EAAE,GAAG;YACZ,OAAO,EAAE,GAAG;YACZ,OAAO,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC;SACnC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,OAAe;IACnC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACrE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "revu-ai",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Parallel AI code review with per-rule Claude agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,15 +20,6 @@
20
20
  "README.md",
21
21
  "LICENSE"
22
22
  ],
23
- "scripts": {
24
- "build": "tsc",
25
- "dev": "tsx src/cli.ts",
26
- "typecheck": "tsc --noEmit",
27
- "test": "vitest run",
28
- "test:watch": "vitest",
29
- "prepack": "pnpm run build",
30
- "prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build"
31
- },
32
23
  "engines": {
33
24
  "node": ">=20"
34
25
  },
@@ -69,5 +60,11 @@
69
60
  "typescript": "^5.6.0",
70
61
  "vitest": "^2.1.0"
71
62
  },
72
- "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
73
- }
63
+ "scripts": {
64
+ "build": "tsc",
65
+ "dev": "tsx src/cli.ts",
66
+ "typecheck": "tsc --noEmit",
67
+ "test": "vitest run",
68
+ "test:watch": "vitest"
69
+ }
70
+ }