repolens-ai 3.1.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +61 -71
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -823,15 +823,14 @@ async function readCodeContents(cwd) {
823
823
  });
824
824
  const results = [];
825
825
  for (const file of codeFiles.slice(0, MAX_FILES_TO_READ)) {
826
- try {
826
+ const parsed = safely(() => {
827
827
  const fullPath = path3.join(cwd, file);
828
828
  const stat = fs3.statSync(fullPath);
829
- if (stat.size > MAX_FILE_SIZE) continue;
829
+ if (stat.size > MAX_FILE_SIZE) return null;
830
830
  const content = fs3.readFileSync(fullPath, "utf-8");
831
- const parsed = parseFileContent(file, content);
832
- results.push(parsed);
833
- } catch {
834
- }
831
+ return parseFileContent(file, content);
832
+ }, null, `contentReader:${file}`);
833
+ if (parsed) results.push(parsed);
835
834
  }
836
835
  return results;
837
836
  }
@@ -936,6 +935,7 @@ var init_contentReader = __esm({
936
935
  "src/core/contentReader.ts"() {
937
936
  "use strict";
938
937
  init_paths();
938
+ init_errors();
939
939
  CODE_EXTENSIONS = /* @__PURE__ */ new Set([
940
940
  ".ts",
941
941
  ".tsx",
@@ -1210,7 +1210,7 @@ function toClaudeMd(agentsContent) {
1210
1210
  }
1211
1211
  sections.push("");
1212
1212
  sections.push("---");
1213
- sections.push(`*Synced from AGENTS.md by [RepoLens AI](https://github.com/repolens/repolens-ai) on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}*`);
1213
+ sections.push(`*Synced from AGENTS.md by [RepoLens AI](https://github.com/Harry-Kien/repolens-ai) on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}*`);
1214
1214
  return sections.join("\n");
1215
1215
  }
1216
1216
  function toCursorRules(agentsContent) {
@@ -1308,7 +1308,7 @@ function toCodexMd(agentsContent) {
1308
1308
  }
1309
1309
  sections.push("");
1310
1310
  sections.push("---");
1311
- sections.push(`*Synced from AGENTS.md by [RepoLens AI](https://github.com/repolens/repolens-ai) on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}*`);
1311
+ sections.push(`*Synced from AGENTS.md by [RepoLens AI](https://github.com/Harry-Kien/repolens-ai) on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}*`);
1312
1312
  return sections.join("\n");
1313
1313
  }
1314
1314
  function createSyncPlan(source, allContextFiles, cwd) {
@@ -2307,7 +2307,7 @@ function generateSmartAgentsMd(fw, arch, scan, summary, ctx) {
2307
2307
  s2.push("");
2308
2308
  }
2309
2309
  s2.push("---");
2310
- s2.push("*Generated by [RepoLens AI](https://github.com/repolens/repolens-ai)*");
2310
+ s2.push("*Generated by [RepoLens AI](https://github.com/Harry-Kien/repolens-ai)*");
2311
2311
  return s2.join("\n");
2312
2312
  }
2313
2313
  function capitalize(s2) {
@@ -3330,7 +3330,7 @@ var init_masks = __esm({
3330
3330
  });
3331
3331
 
3332
3332
  // src/core/gitDiff.ts
3333
- import { execSync } from "child_process";
3333
+ import { execFileSync } from "child_process";
3334
3334
  function analyzeGitDiff(cwd) {
3335
3335
  const result = {
3336
3336
  isGitRepo: false,
@@ -3340,57 +3340,32 @@ function analyzeGitDiff(cwd) {
3340
3340
  dangerousChanges: [],
3341
3341
  summary: ""
3342
3342
  };
3343
- try {
3344
- execSync("git rev-parse --is-inside-work-tree", { cwd, stdio: "pipe" });
3345
- result.isGitRepo = true;
3346
- } catch {
3343
+ result.isGitRepo = safely(
3344
+ () => runGit(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true",
3345
+ false,
3346
+ "gitDiff:isGitRepo"
3347
+ );
3348
+ if (!result.isGitRepo) {
3347
3349
  result.summary = "Not a git repository";
3348
3350
  return result;
3349
3351
  }
3350
- try {
3351
- const namesOutput = execSync("git diff --name-only HEAD 2>nul || git diff --name-only", {
3352
- cwd,
3353
- encoding: "utf-8",
3354
- stdio: ["pipe", "pipe", "pipe"]
3355
- }).trim();
3352
+ const diffRead = safely(() => {
3353
+ const namesOutput = runGitWithFallback(cwd, ["diff", "--name-only", "HEAD"], ["diff", "--name-only"], "gitDiff:names");
3356
3354
  result.changedFiles = namesOutput ? namesOutput.split("\n").filter(Boolean) : [];
3357
- const stagedOutput = execSync("git diff --cached --name-only", {
3358
- cwd,
3359
- encoding: "utf-8",
3360
- stdio: ["pipe", "pipe", "pipe"]
3361
- }).trim();
3355
+ const stagedOutput = runGit(cwd, ["diff", "--cached", "--name-only"]);
3362
3356
  const stagedFiles = stagedOutput ? stagedOutput.split("\n").filter(Boolean) : [];
3363
- const untrackedOutput = execSync("git ls-files --others --exclude-standard", {
3364
- cwd,
3365
- encoding: "utf-8",
3366
- stdio: ["pipe", "pipe", "pipe"]
3367
- }).trim();
3357
+ const untrackedOutput = runGit(cwd, ["ls-files", "--others", "--exclude-standard"]);
3368
3358
  const untrackedFiles = untrackedOutput ? untrackedOutput.split("\n").filter(Boolean) : [];
3369
3359
  result.changedFiles = [.../* @__PURE__ */ new Set([...result.changedFiles, ...stagedFiles, ...untrackedFiles])];
3370
3360
  if (result.changedFiles.length === 0) {
3371
3361
  result.summary = "No uncommitted changes detected";
3372
- return result;
3373
- }
3374
- try {
3375
- result.diffStat = maskSecrets(
3376
- execSync("git diff --stat HEAD 2>nul || git diff --stat", {
3377
- cwd,
3378
- encoding: "utf-8",
3379
- stdio: ["pipe", "pipe", "pipe"]
3380
- }).trim()
3381
- );
3382
- } catch {
3383
- }
3384
- try {
3385
- const rawDiff = execSync("git diff HEAD 2>nul || git diff", {
3386
- cwd,
3387
- encoding: "utf-8",
3388
- maxBuffer: 1024 * 1024,
3389
- stdio: ["pipe", "pipe", "pipe"]
3390
- });
3391
- result.fullDiff = maskSecrets(rawDiff.substring(0, 5e4));
3392
- } catch {
3362
+ return true;
3393
3363
  }
3364
+ result.diffStat = maskSecrets(
3365
+ runGitWithFallback(cwd, ["diff", "--stat", "HEAD"], ["diff", "--stat"], "gitDiff:stat")
3366
+ );
3367
+ const rawDiff = runGitWithFallback(cwd, ["diff", "HEAD"], ["diff"], "gitDiff:full", 1024 * 1024);
3368
+ result.fullDiff = maskSecrets(rawDiff.substring(0, 5e4));
3394
3369
  for (const file of result.changedFiles) {
3395
3370
  for (const { pattern, message } of DANGEROUS_FILE_PATTERNS) {
3396
3371
  if (pattern.test(file)) {
@@ -3398,19 +3373,17 @@ function analyzeGitDiff(cwd) {
3398
3373
  }
3399
3374
  }
3400
3375
  }
3401
- try {
3402
- const deletedOutput = execSync("git diff --diff-filter=D --name-only HEAD 2>nul || git diff --diff-filter=D --name-only", {
3403
- cwd,
3404
- encoding: "utf-8",
3405
- stdio: ["pipe", "pipe", "pipe"]
3406
- }).trim();
3407
- const deleted = deletedOutput ? deletedOutput.split("\n").filter(Boolean) : [];
3408
- for (const f2 of deleted) {
3409
- if (/\.(test|spec)\./i.test(f2)) {
3410
- result.dangerousChanges.push({ level: "high", message: "Test file deleted", file: f2 });
3411
- }
3376
+ const deletedOutput = runGitWithFallback(
3377
+ cwd,
3378
+ ["diff", "--diff-filter=D", "--name-only", "HEAD"],
3379
+ ["diff", "--diff-filter=D", "--name-only"],
3380
+ "gitDiff:deleted"
3381
+ );
3382
+ const deleted = deletedOutput ? deletedOutput.split("\n").filter(Boolean) : [];
3383
+ for (const f2 of deleted) {
3384
+ if (/\.(test|spec)\./i.test(f2)) {
3385
+ result.dangerousChanges.push({ level: "high", message: "Test file deleted", file: f2 });
3412
3386
  }
3413
- } catch {
3414
3387
  }
3415
3388
  if (result.fullDiff) {
3416
3389
  if (/^\+.*\beval\s*\(/m.test(result.fullDiff)) {
@@ -3421,16 +3394,32 @@ function analyzeGitDiff(cwd) {
3421
3394
  }
3422
3395
  }
3423
3396
  result.summary = `${result.changedFiles.length} file(s) changed, ${result.dangerousChanges.length} potential risk(s)`;
3424
- } catch {
3397
+ return true;
3398
+ }, false, "gitDiff:read");
3399
+ if (!diffRead) {
3425
3400
  result.summary = "Unable to read git diff";
3426
3401
  }
3427
3402
  return result;
3428
3403
  }
3404
+ function runGit(cwd, args, maxBuffer = 1024 * 1024) {
3405
+ return execFileSync("git", args, {
3406
+ cwd,
3407
+ encoding: "utf-8",
3408
+ maxBuffer,
3409
+ stdio: ["ignore", "pipe", "pipe"]
3410
+ }).trim();
3411
+ }
3412
+ function runGitWithFallback(cwd, primaryArgs, fallbackArgs, context, maxBuffer) {
3413
+ const primary = safely(() => runGit(cwd, primaryArgs, maxBuffer), null, `${context}:primary`);
3414
+ if (primary !== null) return primary;
3415
+ return safely(() => runGit(cwd, fallbackArgs, maxBuffer), "", `${context}:fallback`);
3416
+ }
3429
3417
  var DANGEROUS_FILE_PATTERNS;
3430
3418
  var init_gitDiff = __esm({
3431
3419
  "src/core/gitDiff.ts"() {
3432
3420
  "use strict";
3433
3421
  init_masks();
3422
+ init_errors();
3434
3423
  DANGEROUS_FILE_PATTERNS = [
3435
3424
  { pattern: /auth/i, message: "Auth-related file modified" },
3436
3425
  { pattern: /middleware/i, message: "Middleware file modified" },
@@ -4090,7 +4079,7 @@ var init_check = __esm({
4090
4079
  // src/core/driftDetector.ts
4091
4080
  import * as fs10 from "fs";
4092
4081
  import * as path10 from "path";
4093
- import { execSync as execSync2 } from "child_process";
4082
+ import { execSync } from "child_process";
4094
4083
  function detectDrift(contextContent, contextPath, cwd, projectFiles) {
4095
4084
  const lines = contextContent.split("\n");
4096
4085
  const staleFiles = detectStaleFileRefs(lines, cwd, projectFiles);
@@ -4329,7 +4318,7 @@ function analyzeTemporalDrift(contextPath, cwd) {
4329
4318
  return stat.mtime;
4330
4319
  }, null, "contextStat");
4331
4320
  const codeLastModified = safely(() => {
4332
- const result = execSync2('git log -1 --format=%ci -- "src/" "app/" "lib/" "*.ts" "*.js" "*.py"', {
4321
+ const result = execSync('git log -1 --format=%ci -- "src/" "app/" "lib/" "*.ts" "*.js" "*.py"', {
4333
4322
  cwd,
4334
4323
  encoding: "utf-8",
4335
4324
  stdio: "pipe",
@@ -4415,7 +4404,8 @@ import fg3 from "fast-glob";
4415
4404
  async function detectRisks(cwd) {
4416
4405
  const risks = [];
4417
4406
  const ignore = getGlobIgnorePatterns();
4418
- const envFiles = await fg3("**/.env*", { cwd, ignore, dot: true });
4407
+ const envIgnore = ignore.filter((pattern) => !pattern.includes(".env"));
4408
+ const envFiles = await fg3("**/.env*", { cwd, ignore: envIgnore, dot: true });
4419
4409
  for (const f2 of envFiles) {
4420
4410
  if (!f2.endsWith(".example") && !f2.endsWith(".sample")) {
4421
4411
  risks.push({ level: "high", category: "security", message: `.env file found \u2014 may contain secrets`, file: f2 });
@@ -5430,7 +5420,7 @@ function generateSmartAgents(scan, fw, arch, summary, answers, contents) {
5430
5420
  s2.push("");
5431
5421
  }
5432
5422
  s2.push("---");
5433
- s2.push("*Generated by [RepoLens AI](https://github.com/repolens/repolens-ai)*");
5423
+ s2.push("*Generated by [RepoLens AI](https://github.com/Harry-Kien/repolens-ai)*");
5434
5424
  return s2.join("\n");
5435
5425
  }
5436
5426
  var init_init = __esm({
@@ -5766,7 +5756,7 @@ function render() {
5766
5756
  html += '</div></div>';
5767
5757
  }
5768
5758
 
5769
- html += '<div class="footer">RepoLens AI v2.0 \xB7 The AI Context Intelligence Platform \xB7 <a href="https://github.com/repolens/repolens-ai" style="color:var(--accent)">GitHub</a></div>';
5759
+ html += '<div class="footer">RepoLens AI v3.1 \xB7 The AI Context Intelligence Platform \xB7 <a href="https://github.com/Harry-Kien/repolens-ai" style="color:var(--accent)">GitHub</a></div>';
5770
5760
  html += '</div>';
5771
5761
 
5772
5762
  document.getElementById('app').innerHTML = html;
@@ -20282,7 +20272,7 @@ function generateMarkdownReport(options) {
20282
20272
  lines.push("");
20283
20273
  }
20284
20274
  lines.push("---");
20285
- lines.push("*Generated by [RepoLens AI](https://github.com/repolens/repolens-ai)*");
20275
+ lines.push("*Generated by [RepoLens AI](https://github.com/Harry-Kien/repolens-ai)*");
20286
20276
  const content = lines.join("\n");
20287
20277
  const outputPath = options.outputPath || path19.join(process.cwd(), "repolens-report.md");
20288
20278
  fs19.writeFileSync(outputPath, content, "utf-8");
@@ -20816,7 +20806,7 @@ import { Command } from "commander";
20816
20806
  var program = new Command();
20817
20807
  program.name("repolens").description(
20818
20808
  'RepoLens AI - The Context Quality Guardian\n\n Quick start: repolens setup\n Daily use: repolens context | repolens prompt "add login" | repolens check\n Score check: repolens lint\n Visual UI: repolens dashboard\n\n Your AI agents are only as good as the context you give them.'
20819
- ).version("3.1.0");
20809
+ ).version("3.1.1");
20820
20810
  program.command("setup").description("One-click setup - AST analysis + AGENTS.md + sync to AI tools").option("--no-sync", "Skip syncing to other tools").option("--no-skills", "Skip generating skill files").action(withErrorHandler(async (options) => {
20821
20811
  const { setupCommand: setupCommand2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
20822
20812
  await setupCommand2({ sync: options.sync, skills: options.skills });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repolens-ai",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "The Context Quality Guardian for AI Coding Agents - AST-powered analysis, drift detection, cross-tool sync",
5
5
  "author": "harry-kien <kientrantrung3@gmail.com>",
6
6
  "license": "MIT",