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.
- package/dist/cli.js +61 -71
- 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
|
-
|
|
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)
|
|
829
|
+
if (stat.size > MAX_FILE_SIZE) return null;
|
|
830
830
|
const content = fs3.readFileSync(fullPath, "utf-8");
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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 {
|
|
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
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
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
|
-
|
|
3351
|
-
const namesOutput =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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/
|
|
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
|
|
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/
|
|
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.
|
|
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.
|
|
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",
|