@corbat-tech/coco 2.14.1 → 2.15.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/index.js +673 -66
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +638 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -4705,12 +4705,12 @@ var init_copilot2 = __esm({
|
|
|
4705
4705
|
init_openai();
|
|
4706
4706
|
init_copilot();
|
|
4707
4707
|
CONTEXT_WINDOWS4 = {
|
|
4708
|
-
// Claude models
|
|
4709
|
-
"claude-sonnet-4.6":
|
|
4710
|
-
"claude-opus-4.6":
|
|
4711
|
-
"claude-sonnet-4.5":
|
|
4712
|
-
"claude-opus-4.5":
|
|
4713
|
-
"claude-haiku-4.5":
|
|
4708
|
+
// Claude models — Copilot API caps these at 168 000 (not 200 000 like Anthropic direct)
|
|
4709
|
+
"claude-sonnet-4.6": 168e3,
|
|
4710
|
+
"claude-opus-4.6": 168e3,
|
|
4711
|
+
"claude-sonnet-4.5": 168e3,
|
|
4712
|
+
"claude-opus-4.5": 168e3,
|
|
4713
|
+
"claude-haiku-4.5": 168e3,
|
|
4714
4714
|
// OpenAI models — chat/completions
|
|
4715
4715
|
"gpt-4.1": 1048576,
|
|
4716
4716
|
// OpenAI models — /responses API (Codex/GPT-5+)
|
|
@@ -9401,7 +9401,7 @@ function humanizeError(message, toolName) {
|
|
|
9401
9401
|
)) {
|
|
9402
9402
|
return msg;
|
|
9403
9403
|
}
|
|
9404
|
-
if (/run git_init\b
|
|
9404
|
+
if (/run git_init\b/i.test(msg)) {
|
|
9405
9405
|
return msg;
|
|
9406
9406
|
}
|
|
9407
9407
|
if (/ECONNREFUSED/i.test(msg)) {
|
|
@@ -10450,6 +10450,18 @@ var init_subprocess_registry = __esm({
|
|
|
10450
10450
|
}
|
|
10451
10451
|
});
|
|
10452
10452
|
async function detectTestFramework(projectPath) {
|
|
10453
|
+
try {
|
|
10454
|
+
await access(join(projectPath, "pom.xml"), constants.R_OK);
|
|
10455
|
+
return "maven";
|
|
10456
|
+
} catch {
|
|
10457
|
+
}
|
|
10458
|
+
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
10459
|
+
try {
|
|
10460
|
+
await access(join(projectPath, f), constants.R_OK);
|
|
10461
|
+
return "gradle";
|
|
10462
|
+
} catch {
|
|
10463
|
+
}
|
|
10464
|
+
}
|
|
10453
10465
|
try {
|
|
10454
10466
|
const pkgPath = join(projectPath, "package.json");
|
|
10455
10467
|
const pkgContent = await readFile(pkgPath, "utf-8");
|
|
@@ -10511,6 +10523,55 @@ function parseCoverageSummary(report) {
|
|
|
10511
10523
|
}
|
|
10512
10524
|
};
|
|
10513
10525
|
}
|
|
10526
|
+
function parseJacocoCsv(csv) {
|
|
10527
|
+
const lines = csv.trim().split("\n").slice(1);
|
|
10528
|
+
let lineMissed = 0, lineCovered = 0;
|
|
10529
|
+
let branchMissed = 0, branchCovered = 0;
|
|
10530
|
+
let methodMissed = 0, methodCovered = 0;
|
|
10531
|
+
let instrMissed = 0, instrCovered = 0;
|
|
10532
|
+
for (const line of lines) {
|
|
10533
|
+
const cols = line.split(",");
|
|
10534
|
+
if (cols.length < 13) continue;
|
|
10535
|
+
instrMissed += parseInt(cols[3] ?? "0", 10);
|
|
10536
|
+
instrCovered += parseInt(cols[4] ?? "0", 10);
|
|
10537
|
+
branchMissed += parseInt(cols[5] ?? "0", 10);
|
|
10538
|
+
branchCovered += parseInt(cols[6] ?? "0", 10);
|
|
10539
|
+
lineMissed += parseInt(cols[7] ?? "0", 10);
|
|
10540
|
+
lineCovered += parseInt(cols[8] ?? "0", 10);
|
|
10541
|
+
methodMissed += parseInt(cols[11] ?? "0", 10);
|
|
10542
|
+
methodCovered += parseInt(cols[12] ?? "0", 10);
|
|
10543
|
+
}
|
|
10544
|
+
const pct = (covered, missed) => {
|
|
10545
|
+
const total = covered + missed;
|
|
10546
|
+
return total > 0 ? Math.round(covered / total * 1e3) / 10 : 0;
|
|
10547
|
+
};
|
|
10548
|
+
return {
|
|
10549
|
+
lines: {
|
|
10550
|
+
total: lineCovered + lineMissed,
|
|
10551
|
+
covered: lineCovered,
|
|
10552
|
+
skipped: 0,
|
|
10553
|
+
percentage: pct(lineCovered, lineMissed)
|
|
10554
|
+
},
|
|
10555
|
+
branches: {
|
|
10556
|
+
total: branchCovered + branchMissed,
|
|
10557
|
+
covered: branchCovered,
|
|
10558
|
+
skipped: 0,
|
|
10559
|
+
percentage: pct(branchCovered, branchMissed)
|
|
10560
|
+
},
|
|
10561
|
+
functions: {
|
|
10562
|
+
total: methodCovered + methodMissed,
|
|
10563
|
+
covered: methodCovered,
|
|
10564
|
+
skipped: 0,
|
|
10565
|
+
percentage: pct(methodCovered, methodMissed)
|
|
10566
|
+
},
|
|
10567
|
+
statements: {
|
|
10568
|
+
total: instrCovered + instrMissed,
|
|
10569
|
+
covered: instrCovered,
|
|
10570
|
+
skipped: 0,
|
|
10571
|
+
percentage: pct(instrCovered, instrMissed)
|
|
10572
|
+
}
|
|
10573
|
+
};
|
|
10574
|
+
}
|
|
10514
10575
|
var CoverageAnalyzer;
|
|
10515
10576
|
var init_coverage = __esm({
|
|
10516
10577
|
"src/quality/analyzers/coverage.ts"() {
|
|
@@ -10524,29 +10585,53 @@ var init_coverage = __esm({
|
|
|
10524
10585
|
*/
|
|
10525
10586
|
async analyze() {
|
|
10526
10587
|
const framework = await detectTestFramework(this.projectPath);
|
|
10527
|
-
const coverageTool = await detectCoverageTool(this.projectPath);
|
|
10528
10588
|
if (!framework) {
|
|
10529
|
-
|
|
10589
|
+
return this.zeroCoverage();
|
|
10530
10590
|
}
|
|
10531
|
-
const existingCoverage = await this.readExistingCoverage();
|
|
10591
|
+
const existingCoverage = await this.readExistingCoverage(framework);
|
|
10532
10592
|
if (existingCoverage) {
|
|
10533
10593
|
return existingCoverage;
|
|
10534
10594
|
}
|
|
10595
|
+
if (framework === "maven" || framework === "gradle") {
|
|
10596
|
+
return this.zeroCoverage();
|
|
10597
|
+
}
|
|
10598
|
+
const coverageTool = await detectCoverageTool(this.projectPath);
|
|
10535
10599
|
return await this.runWithCoverage(framework, coverageTool);
|
|
10536
10600
|
}
|
|
10601
|
+
/** Return empty coverage metrics (graceful fallback) */
|
|
10602
|
+
zeroCoverage() {
|
|
10603
|
+
const zero = { total: 0, covered: 0, skipped: 0, percentage: 0 };
|
|
10604
|
+
return { lines: zero, branches: zero, functions: zero, statements: zero };
|
|
10605
|
+
}
|
|
10537
10606
|
/**
|
|
10538
|
-
* Read existing coverage report if available
|
|
10607
|
+
* Read existing coverage report if available.
|
|
10608
|
+
* Supports Node.js (c8/nyc JSON) and JVM (JaCoCo CSV) formats.
|
|
10539
10609
|
*/
|
|
10540
|
-
async readExistingCoverage() {
|
|
10610
|
+
async readExistingCoverage(framework) {
|
|
10611
|
+
if (framework === "maven" || framework === "gradle") {
|
|
10612
|
+
const jacocoPaths = framework === "maven" ? [
|
|
10613
|
+
join(this.projectPath, "target", "site", "jacoco", "jacoco.csv"),
|
|
10614
|
+
join(this.projectPath, "target", "site", "jacoco-ut", "jacoco.csv")
|
|
10615
|
+
] : [join(this.projectPath, "build", "reports", "jacoco", "test", "jacocoTestReport.csv")];
|
|
10616
|
+
for (const csvPath of jacocoPaths) {
|
|
10617
|
+
try {
|
|
10618
|
+
await access(csvPath, constants.R_OK);
|
|
10619
|
+
const csv = await readFile(csvPath, "utf-8");
|
|
10620
|
+
return parseJacocoCsv(csv);
|
|
10621
|
+
} catch {
|
|
10622
|
+
}
|
|
10623
|
+
}
|
|
10624
|
+
return null;
|
|
10625
|
+
}
|
|
10541
10626
|
const possiblePaths = [
|
|
10542
10627
|
join(this.projectPath, "coverage", "coverage-summary.json"),
|
|
10543
10628
|
join(this.projectPath, ".coverage", "coverage-summary.json"),
|
|
10544
10629
|
join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
|
|
10545
10630
|
];
|
|
10546
|
-
for (const
|
|
10631
|
+
for (const p45 of possiblePaths) {
|
|
10547
10632
|
try {
|
|
10548
|
-
await access(
|
|
10549
|
-
const content = await readFile(
|
|
10633
|
+
await access(p45, constants.R_OK);
|
|
10634
|
+
const content = await readFile(p45, "utf-8");
|
|
10550
10635
|
const report = JSON.parse(content);
|
|
10551
10636
|
return parseCoverageSummary(report);
|
|
10552
10637
|
} catch {
|
|
@@ -11221,7 +11306,7 @@ var init_build_verifier = __esm({
|
|
|
11221
11306
|
stderr: ""
|
|
11222
11307
|
};
|
|
11223
11308
|
}
|
|
11224
|
-
const SAFE_BUILD_PATTERN = /^(npm|pnpm|yarn|bun)\s+(run\s+)?[\w:.-]+$|^npx\s+tsc(\s+--[\w-]+)*$/;
|
|
11309
|
+
const SAFE_BUILD_PATTERN = /^(npm|pnpm|yarn|bun)\s+(run\s+)?[\w:.-]+$|^npx\s+tsc(\s+--[\w-]+)*$|^\.(\/|\\)(mvnw|gradlew)(\s+[\w:.-]+)*(\s+-[\w-]+)*$/;
|
|
11225
11310
|
if (!SAFE_BUILD_PATTERN.test(buildCommand2.trim())) {
|
|
11226
11311
|
return {
|
|
11227
11312
|
success: false,
|
|
@@ -11326,9 +11411,20 @@ var init_build_verifier = __esm({
|
|
|
11326
11411
|
}
|
|
11327
11412
|
}
|
|
11328
11413
|
/**
|
|
11329
|
-
* Detect build command from
|
|
11414
|
+
* Detect build command from project build files.
|
|
11415
|
+
* Checks Maven, Gradle, and Node.js in that order.
|
|
11330
11416
|
*/
|
|
11331
11417
|
async detectBuildCommand() {
|
|
11418
|
+
if (await this.fileExists(path36.join(this.projectPath, "pom.xml"))) {
|
|
11419
|
+
const wrapper = path36.join(this.projectPath, "mvnw");
|
|
11420
|
+
return await this.fileExists(wrapper) ? "./mvnw compile -B -q" : "mvn compile -B -q";
|
|
11421
|
+
}
|
|
11422
|
+
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
11423
|
+
if (await this.fileExists(path36.join(this.projectPath, f))) {
|
|
11424
|
+
const wrapper = path36.join(this.projectPath, "gradlew");
|
|
11425
|
+
return await this.fileExists(wrapper) ? "./gradlew classes -q" : "gradle classes -q";
|
|
11426
|
+
}
|
|
11427
|
+
}
|
|
11332
11428
|
try {
|
|
11333
11429
|
const packageJsonPath = path36.join(this.projectPath, "package.json");
|
|
11334
11430
|
const content = await fs34.readFile(packageJsonPath, "utf-8");
|
|
@@ -11339,10 +11435,9 @@ var init_build_verifier = __esm({
|
|
|
11339
11435
|
if (packageJson.devDependencies?.typescript || packageJson.dependencies?.typescript) {
|
|
11340
11436
|
return "npx tsc --noEmit";
|
|
11341
11437
|
}
|
|
11342
|
-
return null;
|
|
11343
11438
|
} catch {
|
|
11344
|
-
return null;
|
|
11345
11439
|
}
|
|
11440
|
+
return null;
|
|
11346
11441
|
}
|
|
11347
11442
|
/**
|
|
11348
11443
|
* Parse errors from build output
|
|
@@ -11416,6 +11511,16 @@ var init_build_verifier = __esm({
|
|
|
11416
11511
|
};
|
|
11417
11512
|
}
|
|
11418
11513
|
});
|
|
11514
|
+
async function resolveJvmExecutable(projectPath, tool) {
|
|
11515
|
+
const wrapper = tool === "maven" ? "mvnw" : "gradlew";
|
|
11516
|
+
const fallback = tool === "maven" ? "mvn" : "gradle";
|
|
11517
|
+
try {
|
|
11518
|
+
await access(join(projectPath, wrapper));
|
|
11519
|
+
return join(projectPath, wrapper);
|
|
11520
|
+
} catch {
|
|
11521
|
+
return fallback;
|
|
11522
|
+
}
|
|
11523
|
+
}
|
|
11419
11524
|
function parseVitestOutput(stdout) {
|
|
11420
11525
|
const testsMatch = stdout.match(
|
|
11421
11526
|
/Tests\s+(?:(\d+)\s+passed)?(?:\s*\|\s*(\d+)\s+failed)?(?:\s*\|\s*(\d+)\s+skipped)?/
|
|
@@ -11468,10 +11573,29 @@ function buildTestCommand(framework) {
|
|
|
11468
11573
|
return { command: "npx", args: ["jest", "--json"] };
|
|
11469
11574
|
case "mocha":
|
|
11470
11575
|
return { command: "npx", args: ["mocha", "--reporter=json"] };
|
|
11576
|
+
case "maven":
|
|
11577
|
+
return { command: "__maven__", args: ["test", "--no-transfer-progress", "-B"] };
|
|
11578
|
+
case "gradle":
|
|
11579
|
+
return { command: "__gradle__", args: ["test"] };
|
|
11471
11580
|
default:
|
|
11472
11581
|
return null;
|
|
11473
11582
|
}
|
|
11474
11583
|
}
|
|
11584
|
+
function parseMavenOutput(output) {
|
|
11585
|
+
let passed = 0, failed = 0, skipped = 0;
|
|
11586
|
+
const pattern = /Tests run:\s*(\d+),\s*Failures:\s*(\d+),\s*Errors:\s*(\d+),\s*Skipped:\s*(\d+)/gi;
|
|
11587
|
+
for (const match of output.matchAll(pattern)) {
|
|
11588
|
+
const total = parseInt(match[1] ?? "0", 10);
|
|
11589
|
+
const failures = parseInt(match[2] ?? "0", 10);
|
|
11590
|
+
const errors = parseInt(match[3] ?? "0", 10);
|
|
11591
|
+
const skip = parseInt(match[4] ?? "0", 10);
|
|
11592
|
+
const f = failures + errors;
|
|
11593
|
+
passed += total - f - skip;
|
|
11594
|
+
failed += f;
|
|
11595
|
+
skipped += skip;
|
|
11596
|
+
}
|
|
11597
|
+
return { passed, failed, skipped };
|
|
11598
|
+
}
|
|
11475
11599
|
var CorrectnessAnalyzer;
|
|
11476
11600
|
var init_correctness = __esm({
|
|
11477
11601
|
"src/quality/analyzers/correctness.ts"() {
|
|
@@ -11529,6 +11653,11 @@ var init_correctness = __esm({
|
|
|
11529
11653
|
if (!cmd) {
|
|
11530
11654
|
return { passed: 0, failed: 0, skipped: 0 };
|
|
11531
11655
|
}
|
|
11656
|
+
if (cmd.command === "__maven__") {
|
|
11657
|
+
cmd.command = await resolveJvmExecutable(this.projectPath, "maven");
|
|
11658
|
+
} else if (cmd.command === "__gradle__") {
|
|
11659
|
+
cmd.command = await resolveJvmExecutable(this.projectPath, "gradle");
|
|
11660
|
+
}
|
|
11532
11661
|
try {
|
|
11533
11662
|
const proc = execa(cmd.command, cmd.args, {
|
|
11534
11663
|
cwd: this.projectPath,
|
|
@@ -11540,15 +11669,15 @@ var init_correctness = __esm({
|
|
|
11540
11669
|
});
|
|
11541
11670
|
trackSubprocess(proc);
|
|
11542
11671
|
const result = await proc;
|
|
11543
|
-
const output = result.stdout + "\n" + result.stderr;
|
|
11672
|
+
const output = (result.stdout ?? "") + "\n" + (result.stderr ?? "");
|
|
11544
11673
|
switch (framework) {
|
|
11545
11674
|
case "vitest":
|
|
11546
11675
|
return parseVitestOutput(output);
|
|
11547
11676
|
case "jest":
|
|
11548
|
-
return parseJestOutput(result.stdout);
|
|
11677
|
+
return parseJestOutput(result.stdout ?? "");
|
|
11549
11678
|
case "mocha": {
|
|
11550
11679
|
try {
|
|
11551
|
-
const json2 = JSON.parse(result.stdout);
|
|
11680
|
+
const json2 = JSON.parse(result.stdout ?? "");
|
|
11552
11681
|
return {
|
|
11553
11682
|
passed: json2.stats?.passes ?? 0,
|
|
11554
11683
|
failed: json2.stats?.failures ?? 0,
|
|
@@ -11558,6 +11687,9 @@ var init_correctness = __esm({
|
|
|
11558
11687
|
return { passed: 0, failed: 0, skipped: 0 };
|
|
11559
11688
|
}
|
|
11560
11689
|
}
|
|
11690
|
+
case "maven":
|
|
11691
|
+
case "gradle":
|
|
11692
|
+
return parseMavenOutput(output);
|
|
11561
11693
|
default:
|
|
11562
11694
|
return { passed: 0, failed: 0, skipped: 0 };
|
|
11563
11695
|
}
|
|
@@ -14498,9 +14630,31 @@ var init_evaluator = __esm({
|
|
|
14498
14630
|
return suggestions;
|
|
14499
14631
|
}
|
|
14500
14632
|
/**
|
|
14501
|
-
* Find source files in project
|
|
14633
|
+
* Find source files in project, adapting to the detected language stack.
|
|
14502
14634
|
*/
|
|
14503
14635
|
async findSourceFiles() {
|
|
14636
|
+
const { access: access16 } = await import('fs/promises');
|
|
14637
|
+
const { join: join26 } = await import('path');
|
|
14638
|
+
let isJava = false;
|
|
14639
|
+
try {
|
|
14640
|
+
await access16(join26(this.projectPath, "pom.xml"));
|
|
14641
|
+
isJava = true;
|
|
14642
|
+
} catch {
|
|
14643
|
+
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
14644
|
+
try {
|
|
14645
|
+
await access16(join26(this.projectPath, f));
|
|
14646
|
+
isJava = true;
|
|
14647
|
+
break;
|
|
14648
|
+
} catch {
|
|
14649
|
+
}
|
|
14650
|
+
}
|
|
14651
|
+
}
|
|
14652
|
+
if (isJava) {
|
|
14653
|
+
return glob("src/main/java/**/*.java", {
|
|
14654
|
+
cwd: this.projectPath,
|
|
14655
|
+
absolute: true
|
|
14656
|
+
});
|
|
14657
|
+
}
|
|
14504
14658
|
return glob("**/*.{ts,js,tsx,jsx}", {
|
|
14505
14659
|
cwd: this.projectPath,
|
|
14506
14660
|
absolute: true,
|
|
@@ -14511,6 +14665,18 @@ var init_evaluator = __esm({
|
|
|
14511
14665
|
}
|
|
14512
14666
|
});
|
|
14513
14667
|
async function detectLinter2(cwd) {
|
|
14668
|
+
try {
|
|
14669
|
+
await fs34__default.access(path36__default.join(cwd, "pom.xml"));
|
|
14670
|
+
return "maven-checkstyle";
|
|
14671
|
+
} catch {
|
|
14672
|
+
}
|
|
14673
|
+
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
14674
|
+
try {
|
|
14675
|
+
await fs34__default.access(path36__default.join(cwd, f));
|
|
14676
|
+
return "gradle-checkstyle";
|
|
14677
|
+
} catch {
|
|
14678
|
+
}
|
|
14679
|
+
}
|
|
14514
14680
|
try {
|
|
14515
14681
|
const pkgPath = path36__default.join(cwd, "package.json");
|
|
14516
14682
|
const pkgContent = await fs34__default.readFile(pkgPath, "utf-8");
|
|
@@ -14527,6 +14693,44 @@ async function detectLinter2(cwd) {
|
|
|
14527
14693
|
return null;
|
|
14528
14694
|
}
|
|
14529
14695
|
}
|
|
14696
|
+
async function mavenExec(cwd) {
|
|
14697
|
+
try {
|
|
14698
|
+
await fs34__default.access(path36__default.join(cwd, "mvnw"));
|
|
14699
|
+
return "./mvnw";
|
|
14700
|
+
} catch {
|
|
14701
|
+
return "mvn";
|
|
14702
|
+
}
|
|
14703
|
+
}
|
|
14704
|
+
async function gradleExec(cwd) {
|
|
14705
|
+
try {
|
|
14706
|
+
await fs34__default.access(path36__default.join(cwd, "gradlew"));
|
|
14707
|
+
return "./gradlew";
|
|
14708
|
+
} catch {
|
|
14709
|
+
return "gradle";
|
|
14710
|
+
}
|
|
14711
|
+
}
|
|
14712
|
+
function parseCheckstyleOutput(stdout, stderr) {
|
|
14713
|
+
const output = stdout + "\n" + stderr;
|
|
14714
|
+
const issues = [];
|
|
14715
|
+
let errors = 0;
|
|
14716
|
+
let warnings = 0;
|
|
14717
|
+
const lineRe = /\[(ERROR|WARN(?:ING)?)\]\s+(.+?):(?:\[(\d+)(?:,(\d+))?\])?\s*(?:\([^)]*\))?\s*(.+)/gi;
|
|
14718
|
+
for (const m of output.matchAll(lineRe)) {
|
|
14719
|
+
const sev = (m[1] ?? "").toUpperCase().startsWith("ERROR") ? "error" : "warning";
|
|
14720
|
+
if (sev === "error") errors++;
|
|
14721
|
+
else warnings++;
|
|
14722
|
+
issues.push({
|
|
14723
|
+
file: m[2]?.trim() ?? "",
|
|
14724
|
+
line: parseInt(m[3] ?? "0", 10),
|
|
14725
|
+
column: parseInt(m[4] ?? "0", 10),
|
|
14726
|
+
severity: sev,
|
|
14727
|
+
message: m[5]?.trim() ?? "",
|
|
14728
|
+
rule: ""
|
|
14729
|
+
});
|
|
14730
|
+
}
|
|
14731
|
+
const score = Math.max(0, 100 - errors * 5 - warnings * 2);
|
|
14732
|
+
return { errors, warnings, fixable: 0, issues, score };
|
|
14733
|
+
}
|
|
14530
14734
|
function parseLintResults(_linter, stdout, _stderr) {
|
|
14531
14735
|
const issues = [];
|
|
14532
14736
|
let errors = 0;
|
|
@@ -14566,6 +14770,28 @@ function parseLintResults(_linter, stdout, _stderr) {
|
|
|
14566
14770
|
}
|
|
14567
14771
|
async function findSourceFiles(cwd) {
|
|
14568
14772
|
const { glob: glob17 } = await import('glob');
|
|
14773
|
+
let isJava = false;
|
|
14774
|
+
try {
|
|
14775
|
+
await fs34__default.access(path36__default.join(cwd, "pom.xml"));
|
|
14776
|
+
isJava = true;
|
|
14777
|
+
} catch {
|
|
14778
|
+
}
|
|
14779
|
+
if (!isJava) {
|
|
14780
|
+
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
14781
|
+
try {
|
|
14782
|
+
await fs34__default.access(path36__default.join(cwd, f));
|
|
14783
|
+
isJava = true;
|
|
14784
|
+
break;
|
|
14785
|
+
} catch {
|
|
14786
|
+
}
|
|
14787
|
+
}
|
|
14788
|
+
}
|
|
14789
|
+
if (isJava) {
|
|
14790
|
+
return glob17("src/main/java/**/*.java", {
|
|
14791
|
+
cwd,
|
|
14792
|
+
absolute: true
|
|
14793
|
+
});
|
|
14794
|
+
}
|
|
14569
14795
|
return glob17("src/**/*.{ts,js,tsx,jsx}", {
|
|
14570
14796
|
cwd,
|
|
14571
14797
|
absolute: true,
|
|
@@ -14583,6 +14809,8 @@ function analyzeFileComplexity(content, file) {
|
|
|
14583
14809
|
const line = lines[i] ?? "";
|
|
14584
14810
|
const funcMatch = line.match(
|
|
14585
14811
|
/(?:function|async function)\s+(\w+)|(\w+)\s*(?:=|:)\s*(?:async\s*)?\(?.*\)?\s*=>/
|
|
14812
|
+
) ?? line.match(
|
|
14813
|
+
/(?:public|private|protected|static|final|native|synchronized|abstract)\s+\S+\s+(\w+)\s*\(/
|
|
14586
14814
|
);
|
|
14587
14815
|
if (funcMatch && braceDepth === 0) {
|
|
14588
14816
|
if (currentFunction) {
|
|
@@ -14625,19 +14853,20 @@ var init_quality = __esm({
|
|
|
14625
14853
|
init_evaluator();
|
|
14626
14854
|
runLinterTool = defineTool({
|
|
14627
14855
|
name: "run_linter",
|
|
14628
|
-
description: `Run linter on the codebase (auto-detects eslint, oxlint,
|
|
14856
|
+
description: `Run linter on the codebase (auto-detects eslint, oxlint, biome for Node.js; checkstyle for Maven/Gradle).
|
|
14629
14857
|
|
|
14630
14858
|
Examples:
|
|
14631
14859
|
- Lint all: {} \u2192 { "errors": 0, "warnings": 5, "score": 90 }
|
|
14632
|
-
- Auto-fix: { "fix": true }
|
|
14860
|
+
- Auto-fix (Node.js): { "fix": true }
|
|
14633
14861
|
- Specific files: { "files": ["src/app.ts", "src/utils.ts"] }
|
|
14634
|
-
- Force linter: { "linter": "eslint" }
|
|
14862
|
+
- Force linter: { "linter": "eslint" }
|
|
14863
|
+
- Java project (Maven): automatically runs checkstyle:check if plugin is configured`,
|
|
14635
14864
|
category: "quality",
|
|
14636
14865
|
parameters: z.object({
|
|
14637
14866
|
cwd: z.string().optional().describe("Project directory"),
|
|
14638
14867
|
files: z.array(z.string()).optional().describe("Specific files to lint"),
|
|
14639
|
-
fix: z.boolean().optional().default(false).describe("Auto-fix issues"),
|
|
14640
|
-
linter: z.string().optional().describe("Linter to use (eslint, oxlint, biome)")
|
|
14868
|
+
fix: z.boolean().optional().default(false).describe("Auto-fix issues (Node.js only)"),
|
|
14869
|
+
linter: z.string().optional().describe("Linter to use (eslint, oxlint, biome, maven-checkstyle, gradle-checkstyle)")
|
|
14641
14870
|
}),
|
|
14642
14871
|
async execute({ cwd, files, fix, linter }) {
|
|
14643
14872
|
const projectDir = cwd ?? process.cwd();
|
|
@@ -14650,13 +14879,23 @@ Examples:
|
|
|
14650
14879
|
issues: [],
|
|
14651
14880
|
score: null,
|
|
14652
14881
|
linter: "none",
|
|
14653
|
-
message: "No linter detected (looked for: eslint, oxlint, biome). Install one or use bash_exec to run a custom linter."
|
|
14882
|
+
message: "No linter detected (looked for: eslint, oxlint, biome for Node.js; checkstyle plugin for Maven/Gradle). Install one or use bash_exec to run a custom linter."
|
|
14654
14883
|
};
|
|
14655
14884
|
}
|
|
14656
14885
|
try {
|
|
14657
14886
|
const args = [];
|
|
14658
14887
|
let command = "npx";
|
|
14659
14888
|
switch (detectedLinter) {
|
|
14889
|
+
case "maven-checkstyle": {
|
|
14890
|
+
command = await mavenExec(projectDir);
|
|
14891
|
+
args.push("checkstyle:check", "--no-transfer-progress", "-q");
|
|
14892
|
+
break;
|
|
14893
|
+
}
|
|
14894
|
+
case "gradle-checkstyle": {
|
|
14895
|
+
command = await gradleExec(projectDir);
|
|
14896
|
+
args.push("checkstyleMain", "--quiet");
|
|
14897
|
+
break;
|
|
14898
|
+
}
|
|
14660
14899
|
case "oxlint":
|
|
14661
14900
|
args.push("oxlint");
|
|
14662
14901
|
if (files && files.length > 0) {
|
|
@@ -14697,7 +14936,25 @@ Examples:
|
|
|
14697
14936
|
reject: false,
|
|
14698
14937
|
timeout: 12e4
|
|
14699
14938
|
});
|
|
14700
|
-
|
|
14939
|
+
const combinedOutput = (result.stdout ?? "") + (result.stderr ?? "");
|
|
14940
|
+
if ((detectedLinter === "maven-checkstyle" || detectedLinter === "gradle-checkstyle") && /No plugin found|Task.*not found|checkstyle.*not configured/i.test(combinedOutput)) {
|
|
14941
|
+
return {
|
|
14942
|
+
errors: 0,
|
|
14943
|
+
warnings: 0,
|
|
14944
|
+
fixable: 0,
|
|
14945
|
+
issues: [],
|
|
14946
|
+
score: null,
|
|
14947
|
+
linter: "none",
|
|
14948
|
+
message: "Checkstyle plugin not configured in build file. Add maven-checkstyle-plugin (Maven) or checkstyle plugin (Gradle) to enable Java linting."
|
|
14949
|
+
};
|
|
14950
|
+
}
|
|
14951
|
+
if (detectedLinter === "maven-checkstyle" || detectedLinter === "gradle-checkstyle") {
|
|
14952
|
+
return {
|
|
14953
|
+
...parseCheckstyleOutput(result.stdout ?? "", result.stderr ?? ""),
|
|
14954
|
+
linter: detectedLinter
|
|
14955
|
+
};
|
|
14956
|
+
}
|
|
14957
|
+
return parseLintResults(detectedLinter, result.stdout ?? "", result.stderr ?? "");
|
|
14701
14958
|
} catch (error) {
|
|
14702
14959
|
throw new ToolError(
|
|
14703
14960
|
`Linting failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -20220,7 +20477,8 @@ async function detectProjectStack(cwd) {
|
|
|
20220
20477
|
testingFrameworks = parsed.testingFrameworks;
|
|
20221
20478
|
languages = parsed.languages;
|
|
20222
20479
|
} else if (stack === "java") {
|
|
20223
|
-
const
|
|
20480
|
+
const isGradle = await fileExists2(path36__default.join(cwd, "build.gradle")) || await fileExists2(path36__default.join(cwd, "build.gradle.kts"));
|
|
20481
|
+
const parsed = isGradle ? { dependencies: {}, frameworks: [], buildTools: ["gradle"], testingFrameworks: ["JUnit"] } : await parsePomXml(cwd);
|
|
20224
20482
|
dependencies = parsed.dependencies;
|
|
20225
20483
|
frameworks = parsed.frameworks;
|
|
20226
20484
|
buildTools2 = parsed.buildTools;
|
|
@@ -37902,6 +38160,18 @@ init_registry4();
|
|
|
37902
38160
|
init_errors();
|
|
37903
38161
|
init_subprocess_registry();
|
|
37904
38162
|
async function detectTestFramework2(cwd) {
|
|
38163
|
+
try {
|
|
38164
|
+
await fs34__default.access(path36__default.join(cwd, "pom.xml"));
|
|
38165
|
+
return "maven";
|
|
38166
|
+
} catch {
|
|
38167
|
+
}
|
|
38168
|
+
for (const gradleFile of ["build.gradle", "build.gradle.kts"]) {
|
|
38169
|
+
try {
|
|
38170
|
+
await fs34__default.access(path36__default.join(cwd, gradleFile));
|
|
38171
|
+
return "gradle";
|
|
38172
|
+
} catch {
|
|
38173
|
+
}
|
|
38174
|
+
}
|
|
37905
38175
|
try {
|
|
37906
38176
|
const pkgPath = path36__default.join(cwd, "package.json");
|
|
37907
38177
|
const pkgContent = await fs34__default.readFile(pkgPath, "utf-8");
|
|
@@ -37919,36 +38189,79 @@ async function detectTestFramework2(cwd) {
|
|
|
37919
38189
|
return null;
|
|
37920
38190
|
}
|
|
37921
38191
|
}
|
|
38192
|
+
function toMavenTestFilter(pattern) {
|
|
38193
|
+
const base = path36__default.basename(pattern).replace(/\.java$/, "");
|
|
38194
|
+
return base;
|
|
38195
|
+
}
|
|
38196
|
+
function toGradleTestFilter(pattern) {
|
|
38197
|
+
const base = path36__default.basename(pattern).replace(/\.java$/, "");
|
|
38198
|
+
return `*${base}`;
|
|
38199
|
+
}
|
|
38200
|
+
async function mavenExecutable(cwd) {
|
|
38201
|
+
try {
|
|
38202
|
+
await fs34__default.access(path36__default.join(cwd, "mvnw"));
|
|
38203
|
+
return "./mvnw";
|
|
38204
|
+
} catch {
|
|
38205
|
+
return "mvn";
|
|
38206
|
+
}
|
|
38207
|
+
}
|
|
38208
|
+
async function gradleExecutable(cwd) {
|
|
38209
|
+
try {
|
|
38210
|
+
await fs34__default.access(path36__default.join(cwd, "gradlew"));
|
|
38211
|
+
return "./gradlew";
|
|
38212
|
+
} catch {
|
|
38213
|
+
return "gradle";
|
|
38214
|
+
}
|
|
38215
|
+
}
|
|
37922
38216
|
var runTestsTool = defineTool({
|
|
37923
38217
|
name: "run_tests",
|
|
37924
|
-
description: `Run tests in the project (auto-detects vitest, jest, or mocha).
|
|
38218
|
+
description: `Run tests in the project (auto-detects Maven/Gradle/JUnit, vitest, jest, or mocha).
|
|
37925
38219
|
|
|
37926
38220
|
Examples:
|
|
37927
38221
|
- Run all tests: {}
|
|
37928
38222
|
- With coverage: { "coverage": true }
|
|
37929
|
-
- Specific pattern: { "pattern": "src/**/*.test.ts" }
|
|
37930
|
-
- Specific
|
|
38223
|
+
- Specific pattern (JS): { "pattern": "src/**/*.test.ts" }
|
|
38224
|
+
- Specific test class (Java): { "pattern": "**/ItemRestControllerIT.java" }
|
|
38225
|
+
- Specific framework: { "framework": "maven" }
|
|
38226
|
+
- Maven module: { "framework": "maven", "args": ["-pl", "stock-core"] }`,
|
|
37931
38227
|
category: "test",
|
|
37932
38228
|
parameters: z.object({
|
|
37933
38229
|
cwd: z.string().optional().describe("Project directory"),
|
|
37934
|
-
pattern: z.string().optional().describe("Test file pattern"),
|
|
38230
|
+
pattern: z.string().optional().describe("Test file pattern or class glob"),
|
|
37935
38231
|
coverage: z.boolean().optional().default(false).describe("Collect coverage"),
|
|
37936
|
-
framework: z.string().optional().describe("Test framework (vitest, jest, mocha)"),
|
|
37937
|
-
watch: z.boolean().optional().default(false).describe("Watch mode")
|
|
38232
|
+
framework: z.string().optional().describe("Test framework (maven, gradle, vitest, jest, mocha)"),
|
|
38233
|
+
watch: z.boolean().optional().default(false).describe("Watch mode"),
|
|
38234
|
+
args: z.array(z.string()).optional().describe("Extra arguments (e.g. Maven -pl module)")
|
|
37938
38235
|
}),
|
|
37939
|
-
async execute({ cwd, pattern, coverage, framework, watch }) {
|
|
38236
|
+
async execute({ cwd, pattern, coverage, framework, watch, args: extraArgs }) {
|
|
37940
38237
|
const projectDir = cwd ?? process.cwd();
|
|
37941
38238
|
const detectedFramework = framework ?? await detectTestFramework2(projectDir);
|
|
37942
38239
|
if (!detectedFramework) {
|
|
37943
|
-
throw new ToolError(
|
|
37944
|
-
|
|
37945
|
-
|
|
38240
|
+
throw new ToolError(
|
|
38241
|
+
"No test framework detected. For Java projects ensure pom.xml or build.gradle exists. For Node.js projects install vitest, jest, or mocha.",
|
|
38242
|
+
{ tool: "run_tests" }
|
|
38243
|
+
);
|
|
37946
38244
|
}
|
|
37947
38245
|
const startTime = performance.now();
|
|
37948
38246
|
try {
|
|
37949
38247
|
const args = [];
|
|
37950
38248
|
let command = "npx";
|
|
37951
38249
|
switch (detectedFramework) {
|
|
38250
|
+
case "maven": {
|
|
38251
|
+
command = await mavenExecutable(projectDir);
|
|
38252
|
+
args.push(coverage ? "verify" : "test");
|
|
38253
|
+
if (extraArgs && extraArgs.length > 0) args.push(...extraArgs);
|
|
38254
|
+
if (pattern) args.push(`-Dtest=${toMavenTestFilter(pattern)}`);
|
|
38255
|
+
break;
|
|
38256
|
+
}
|
|
38257
|
+
case "gradle": {
|
|
38258
|
+
command = await gradleExecutable(projectDir);
|
|
38259
|
+
args.push("test");
|
|
38260
|
+
if (extraArgs && extraArgs.length > 0) args.push(...extraArgs);
|
|
38261
|
+
if (pattern) args.push("--tests", toGradleTestFilter(pattern));
|
|
38262
|
+
if (coverage) args.push("jacocoTestReport");
|
|
38263
|
+
break;
|
|
38264
|
+
}
|
|
37952
38265
|
case "vitest":
|
|
37953
38266
|
args.push("vitest", "run");
|
|
37954
38267
|
if (coverage) args.push("--coverage");
|
|
@@ -37986,8 +38299,8 @@ Examples:
|
|
|
37986
38299
|
const duration = performance.now() - startTime;
|
|
37987
38300
|
return parseTestResults(
|
|
37988
38301
|
detectedFramework,
|
|
37989
|
-
result.stdout,
|
|
37990
|
-
result.stderr,
|
|
38302
|
+
result.stdout ?? "",
|
|
38303
|
+
result.stderr ?? "",
|
|
37991
38304
|
result.exitCode ?? 0,
|
|
37992
38305
|
duration
|
|
37993
38306
|
);
|
|
@@ -38001,18 +38314,37 @@ Examples:
|
|
|
38001
38314
|
}
|
|
38002
38315
|
});
|
|
38003
38316
|
function parseTestResults(framework, stdout, stderr, exitCode, duration) {
|
|
38004
|
-
|
|
38005
|
-
|
|
38006
|
-
|
|
38007
|
-
|
|
38008
|
-
|
|
38317
|
+
if (framework === "vitest" || framework === "jest") {
|
|
38318
|
+
try {
|
|
38319
|
+
const jsonMatch = stdout.match(/\{[\s\S]*\}/);
|
|
38320
|
+
if (jsonMatch) {
|
|
38321
|
+
const json2 = JSON.parse(jsonMatch[0]);
|
|
38009
38322
|
return parseJestLikeResults(json2, duration);
|
|
38010
38323
|
}
|
|
38324
|
+
} catch {
|
|
38011
38325
|
}
|
|
38012
|
-
} catch {
|
|
38013
38326
|
}
|
|
38014
|
-
const
|
|
38015
|
-
|
|
38327
|
+
const mavenMatch = stdout.match(
|
|
38328
|
+
/Tests run:\s*(\d+),\s*Failures:\s*(\d+),\s*Errors:\s*(\d+),\s*Skipped:\s*(\d+)/i
|
|
38329
|
+
);
|
|
38330
|
+
if (mavenMatch) {
|
|
38331
|
+
const total = parseInt(mavenMatch[1] ?? "0", 10);
|
|
38332
|
+
const failures = parseInt(mavenMatch[2] ?? "0", 10);
|
|
38333
|
+
const errors = parseInt(mavenMatch[3] ?? "0", 10);
|
|
38334
|
+
const skipped2 = parseInt(mavenMatch[4] ?? "0", 10);
|
|
38335
|
+
const failed2 = failures + errors;
|
|
38336
|
+
return {
|
|
38337
|
+
passed: total - failed2 - skipped2,
|
|
38338
|
+
failed: failed2,
|
|
38339
|
+
skipped: skipped2,
|
|
38340
|
+
total,
|
|
38341
|
+
duration,
|
|
38342
|
+
success: exitCode === 0,
|
|
38343
|
+
failures: failed2 > 0 ? parseFailuresFromOutput(stderr || stdout) : []
|
|
38344
|
+
};
|
|
38345
|
+
}
|
|
38346
|
+
const passMatch = stdout.match(/(\d+)\s*(?:passed|passing|tests\s+run)/i);
|
|
38347
|
+
const failMatch = stdout.match(/(\d+)\s*(?:failed|failing|failures)/i);
|
|
38016
38348
|
const skipMatch = stdout.match(/(\d+)\s*(?:skipped|pending)/i);
|
|
38017
38349
|
const passed = passMatch ? parseInt(passMatch[1] ?? "0", 10) : 0;
|
|
38018
38350
|
const failed = failMatch ? parseInt(failMatch[1] ?? "0", 10) : 0;
|
|
@@ -38069,6 +38401,37 @@ function parseFailuresFromOutput(output) {
|
|
|
38069
38401
|
}
|
|
38070
38402
|
return failures;
|
|
38071
38403
|
}
|
|
38404
|
+
function parseJacocoCsvCoverage(csv) {
|
|
38405
|
+
const lines = csv.trim().split("\n").slice(1);
|
|
38406
|
+
if (lines.length === 0) return null;
|
|
38407
|
+
let lineMissed = 0, lineCovered = 0;
|
|
38408
|
+
let branchMissed = 0, branchCovered = 0;
|
|
38409
|
+
let methodMissed = 0, methodCovered = 0;
|
|
38410
|
+
let instrMissed = 0, instrCovered = 0;
|
|
38411
|
+
for (const line of lines) {
|
|
38412
|
+
const cols = line.split(",");
|
|
38413
|
+
if (cols.length < 13) continue;
|
|
38414
|
+
instrMissed += parseInt(cols[3] ?? "0", 10);
|
|
38415
|
+
instrCovered += parseInt(cols[4] ?? "0", 10);
|
|
38416
|
+
branchMissed += parseInt(cols[5] ?? "0", 10);
|
|
38417
|
+
branchCovered += parseInt(cols[6] ?? "0", 10);
|
|
38418
|
+
lineMissed += parseInt(cols[7] ?? "0", 10);
|
|
38419
|
+
lineCovered += parseInt(cols[8] ?? "0", 10);
|
|
38420
|
+
methodMissed += parseInt(cols[11] ?? "0", 10);
|
|
38421
|
+
methodCovered += parseInt(cols[12] ?? "0", 10);
|
|
38422
|
+
}
|
|
38423
|
+
if (lineCovered + lineMissed === 0) return null;
|
|
38424
|
+
const pct = (covered, missed) => {
|
|
38425
|
+
const total = covered + missed;
|
|
38426
|
+
return total > 0 ? Math.round(covered / total * 1e3) / 10 : 0;
|
|
38427
|
+
};
|
|
38428
|
+
return {
|
|
38429
|
+
lines: pct(lineCovered, lineMissed),
|
|
38430
|
+
branches: pct(branchCovered, branchMissed),
|
|
38431
|
+
functions: pct(methodCovered, methodMissed),
|
|
38432
|
+
statements: pct(instrCovered, instrMissed)
|
|
38433
|
+
};
|
|
38434
|
+
}
|
|
38072
38435
|
var getCoverageTool = defineTool({
|
|
38073
38436
|
name: "get_coverage",
|
|
38074
38437
|
description: `Get test coverage report (requires running tests with --coverage first).
|
|
@@ -38087,11 +38450,23 @@ Examples:
|
|
|
38087
38450
|
const coverageLocations = [
|
|
38088
38451
|
path36__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
38089
38452
|
path36__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
38090
|
-
path36__default.join(projectDir, ".nyc_output", "coverage-summary.json")
|
|
38453
|
+
path36__default.join(projectDir, ".nyc_output", "coverage-summary.json"),
|
|
38454
|
+
// Maven JaCoCo
|
|
38455
|
+
path36__default.join(projectDir, "target", "site", "jacoco", "jacoco.csv"),
|
|
38456
|
+
path36__default.join(projectDir, "target", "site", "jacoco-ut", "jacoco.csv"),
|
|
38457
|
+
// Gradle JaCoCo
|
|
38458
|
+
path36__default.join(projectDir, "build", "reports", "jacoco", "test", "jacocoTestReport.csv")
|
|
38091
38459
|
];
|
|
38092
38460
|
for (const location of coverageLocations) {
|
|
38093
38461
|
try {
|
|
38094
38462
|
const content = await fs34__default.readFile(location, "utf-8");
|
|
38463
|
+
if (location.endsWith(".csv")) {
|
|
38464
|
+
const result = parseJacocoCsvCoverage(content);
|
|
38465
|
+
if (result) {
|
|
38466
|
+
return { ...result, report: format === "detailed" ? content : void 0 };
|
|
38467
|
+
}
|
|
38468
|
+
continue;
|
|
38469
|
+
}
|
|
38095
38470
|
const coverage = JSON.parse(content);
|
|
38096
38471
|
if (coverage.total) {
|
|
38097
38472
|
return {
|
|
@@ -38105,9 +38480,10 @@ Examples:
|
|
|
38105
38480
|
} catch {
|
|
38106
38481
|
}
|
|
38107
38482
|
}
|
|
38108
|
-
throw new ToolError(
|
|
38109
|
-
|
|
38110
|
-
|
|
38483
|
+
throw new ToolError(
|
|
38484
|
+
"Coverage data not found. For Maven projects run 'mvn verify' with JaCoCo plugin. For Node.js run tests with --coverage.",
|
|
38485
|
+
{ tool: "get_coverage" }
|
|
38486
|
+
);
|
|
38111
38487
|
} catch (error) {
|
|
38112
38488
|
if (error instanceof ToolError) throw error;
|
|
38113
38489
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -38124,20 +38500,24 @@ var runTestFileTool = defineTool({
|
|
|
38124
38500
|
|
|
38125
38501
|
Examples:
|
|
38126
38502
|
- Single file: { "file": "src/utils.test.ts" }
|
|
38127
|
-
-
|
|
38503
|
+
- Java test: { "file": "**/ItemRestControllerIT.java" }
|
|
38504
|
+
- With framework: { "file": "test/app.spec.js", "framework": "jest" }
|
|
38505
|
+
- Maven module: { "file": "**/MyTest.java", "args": ["-pl", "my-module"] }`,
|
|
38128
38506
|
category: "test",
|
|
38129
38507
|
parameters: z.object({
|
|
38130
38508
|
cwd: z.string().optional().describe("Project directory"),
|
|
38131
|
-
file: z.string().describe("Test file path"),
|
|
38132
|
-
framework: z.string().optional().describe("Test framework")
|
|
38509
|
+
file: z.string().describe("Test file path or class glob"),
|
|
38510
|
+
framework: z.string().optional().describe("Test framework (maven, gradle, vitest, jest, mocha)"),
|
|
38511
|
+
args: z.array(z.string()).optional().describe("Extra arguments (e.g. Maven -pl module)")
|
|
38133
38512
|
}),
|
|
38134
|
-
async execute({ cwd, file, framework }) {
|
|
38513
|
+
async execute({ cwd, file, framework, args }) {
|
|
38135
38514
|
return runTestsTool.execute({
|
|
38136
38515
|
cwd,
|
|
38137
38516
|
pattern: file,
|
|
38138
38517
|
coverage: false,
|
|
38139
38518
|
framework,
|
|
38140
|
-
watch: false
|
|
38519
|
+
watch: false,
|
|
38520
|
+
args
|
|
38141
38521
|
});
|
|
38142
38522
|
}
|
|
38143
38523
|
});
|
|
@@ -40136,7 +40516,7 @@ Examples:
|
|
|
40136
40516
|
if (stats.isFile()) {
|
|
40137
40517
|
filesToSearch = [targetPath];
|
|
40138
40518
|
} else {
|
|
40139
|
-
const globPattern = include ?? "**/*.{ts,tsx,js,jsx,json,md,txt}";
|
|
40519
|
+
const globPattern = include ?? "**/*.{ts,tsx,js,jsx,java,py,go,rs,json,md,txt}";
|
|
40140
40520
|
const defaultExclude = ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/coverage/**"];
|
|
40141
40521
|
const excludePatterns = exclude ?? defaultExclude;
|
|
40142
40522
|
filesToSearch = await glob(globPattern, {
|
|
@@ -40875,7 +41255,205 @@ ${message}
|
|
|
40875
41255
|
}
|
|
40876
41256
|
}
|
|
40877
41257
|
});
|
|
40878
|
-
|
|
41258
|
+
async function resolveMaven(cwd) {
|
|
41259
|
+
try {
|
|
41260
|
+
await fs34__default.access(path36__default.join(cwd, "mvnw"));
|
|
41261
|
+
return "./mvnw";
|
|
41262
|
+
} catch {
|
|
41263
|
+
return "mvn";
|
|
41264
|
+
}
|
|
41265
|
+
}
|
|
41266
|
+
async function resolveGradle(cwd) {
|
|
41267
|
+
try {
|
|
41268
|
+
await fs34__default.access(path36__default.join(cwd, "gradlew"));
|
|
41269
|
+
return "./gradlew";
|
|
41270
|
+
} catch {
|
|
41271
|
+
return "gradle";
|
|
41272
|
+
}
|
|
41273
|
+
}
|
|
41274
|
+
var runMavenTool = defineTool({
|
|
41275
|
+
name: "run_maven",
|
|
41276
|
+
description: `Run a Maven goal (auto-detects ./mvnw wrapper).
|
|
41277
|
+
|
|
41278
|
+
Examples:
|
|
41279
|
+
- Compile: { "goal": "compile" }
|
|
41280
|
+
- Run tests: { "goal": "test" }
|
|
41281
|
+
- Package: { "goal": "package" }
|
|
41282
|
+
- Skip tests: { "goal": "package", "args": ["-DskipTests"] }
|
|
41283
|
+
- Specific module: { "goal": "test", "args": ["-pl", "stock-core"] }
|
|
41284
|
+
- Quiet mode: { "goal": "verify", "args": ["-q", "--no-transfer-progress"] }`,
|
|
41285
|
+
category: "build",
|
|
41286
|
+
parameters: z.object({
|
|
41287
|
+
goal: z.string().describe("Maven goal (compile, test, package, verify, clean, install, ...)"),
|
|
41288
|
+
cwd: z.string().optional().describe("Project directory"),
|
|
41289
|
+
args: z.array(z.string()).optional().describe("Additional Maven arguments"),
|
|
41290
|
+
env: z.record(z.string(), z.string()).optional().describe("Environment variables"),
|
|
41291
|
+
timeout: z.number().optional().describe("Timeout in milliseconds")
|
|
41292
|
+
}),
|
|
41293
|
+
async execute({ goal, cwd, args, env: env2, timeout }) {
|
|
41294
|
+
const projectDir = cwd ?? process.cwd();
|
|
41295
|
+
const startTime = performance.now();
|
|
41296
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS4;
|
|
41297
|
+
const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
|
|
41298
|
+
const heartbeat = new CommandHeartbeat2({
|
|
41299
|
+
onUpdate: (stats) => {
|
|
41300
|
+
if (stats.elapsedSeconds > 10)
|
|
41301
|
+
process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
|
|
41302
|
+
},
|
|
41303
|
+
onWarn: (message) => process.stderr.write(`
|
|
41304
|
+
${message}
|
|
41305
|
+
`)
|
|
41306
|
+
});
|
|
41307
|
+
try {
|
|
41308
|
+
heartbeat.start();
|
|
41309
|
+
const command = await resolveMaven(projectDir);
|
|
41310
|
+
const cmdArgs = [goal, "--no-transfer-progress", "-B", ...args ?? []];
|
|
41311
|
+
const subprocess = execa(command, cmdArgs, {
|
|
41312
|
+
cwd: projectDir,
|
|
41313
|
+
timeout: timeoutMs,
|
|
41314
|
+
env: { ...process.env, ...env2 },
|
|
41315
|
+
reject: false,
|
|
41316
|
+
buffer: false,
|
|
41317
|
+
maxBuffer: MAX_OUTPUT_SIZE2
|
|
41318
|
+
});
|
|
41319
|
+
let stdoutBuffer = "";
|
|
41320
|
+
let stderrBuffer = "";
|
|
41321
|
+
subprocess.stdout?.on("data", (chunk) => {
|
|
41322
|
+
const text13 = chunk.toString();
|
|
41323
|
+
stdoutBuffer += text13;
|
|
41324
|
+
process.stdout.write(text13);
|
|
41325
|
+
heartbeat.activity();
|
|
41326
|
+
});
|
|
41327
|
+
subprocess.stderr?.on("data", (chunk) => {
|
|
41328
|
+
const text13 = chunk.toString();
|
|
41329
|
+
stderrBuffer += text13;
|
|
41330
|
+
process.stderr.write(text13);
|
|
41331
|
+
heartbeat.activity();
|
|
41332
|
+
});
|
|
41333
|
+
const result = await subprocess;
|
|
41334
|
+
const buildResult2 = {
|
|
41335
|
+
success: result.exitCode === 0,
|
|
41336
|
+
stdout: truncateOutput2(stdoutBuffer),
|
|
41337
|
+
stderr: truncateOutput2(stderrBuffer),
|
|
41338
|
+
exitCode: result.exitCode ?? 0,
|
|
41339
|
+
duration: performance.now() - startTime
|
|
41340
|
+
};
|
|
41341
|
+
if (!buildResult2.success) {
|
|
41342
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "run_maven");
|
|
41343
|
+
}
|
|
41344
|
+
return buildResult2;
|
|
41345
|
+
} catch (error) {
|
|
41346
|
+
if (error.timedOut) {
|
|
41347
|
+
throw new TimeoutError(`Maven goal '${goal}' timed out after ${timeoutMs}ms`, {
|
|
41348
|
+
timeoutMs,
|
|
41349
|
+
operation: `mvn ${goal}`
|
|
41350
|
+
});
|
|
41351
|
+
}
|
|
41352
|
+
throw new ToolError(
|
|
41353
|
+
`Maven failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
41354
|
+
{ tool: "run_maven", cause: error instanceof Error ? error : void 0 }
|
|
41355
|
+
);
|
|
41356
|
+
} finally {
|
|
41357
|
+
heartbeat.stop();
|
|
41358
|
+
process.stderr.write("\r \r");
|
|
41359
|
+
}
|
|
41360
|
+
}
|
|
41361
|
+
});
|
|
41362
|
+
var runGradleTool = defineTool({
|
|
41363
|
+
name: "run_gradle",
|
|
41364
|
+
description: `Run a Gradle task (auto-detects ./gradlew wrapper).
|
|
41365
|
+
|
|
41366
|
+
Examples:
|
|
41367
|
+
- Build: { "task": "build" }
|
|
41368
|
+
- Run tests: { "task": "test" }
|
|
41369
|
+
- Assemble: { "task": "assemble" }
|
|
41370
|
+
- Skip tests: { "task": "build", "args": ["-x", "test"] }
|
|
41371
|
+
- Specific subproject: { "task": ":stock-core:test" }`,
|
|
41372
|
+
category: "build",
|
|
41373
|
+
parameters: z.object({
|
|
41374
|
+
task: z.string().describe("Gradle task (build, test, assemble, clean, check, ...)"),
|
|
41375
|
+
cwd: z.string().optional().describe("Project directory"),
|
|
41376
|
+
args: z.array(z.string()).optional().describe("Additional Gradle arguments"),
|
|
41377
|
+
env: z.record(z.string(), z.string()).optional().describe("Environment variables"),
|
|
41378
|
+
timeout: z.number().optional().describe("Timeout in milliseconds")
|
|
41379
|
+
}),
|
|
41380
|
+
async execute({ task, cwd, args, env: env2, timeout }) {
|
|
41381
|
+
const projectDir = cwd ?? process.cwd();
|
|
41382
|
+
const startTime = performance.now();
|
|
41383
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS4;
|
|
41384
|
+
const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
|
|
41385
|
+
const heartbeat = new CommandHeartbeat2({
|
|
41386
|
+
onUpdate: (stats) => {
|
|
41387
|
+
if (stats.elapsedSeconds > 10)
|
|
41388
|
+
process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
|
|
41389
|
+
},
|
|
41390
|
+
onWarn: (message) => process.stderr.write(`
|
|
41391
|
+
${message}
|
|
41392
|
+
`)
|
|
41393
|
+
});
|
|
41394
|
+
try {
|
|
41395
|
+
heartbeat.start();
|
|
41396
|
+
const command = await resolveGradle(projectDir);
|
|
41397
|
+
const cmdArgs = [task, "--console=plain", ...args ?? []];
|
|
41398
|
+
const subprocess = execa(command, cmdArgs, {
|
|
41399
|
+
cwd: projectDir,
|
|
41400
|
+
timeout: timeoutMs,
|
|
41401
|
+
env: { ...process.env, ...env2 },
|
|
41402
|
+
reject: false,
|
|
41403
|
+
buffer: false,
|
|
41404
|
+
maxBuffer: MAX_OUTPUT_SIZE2
|
|
41405
|
+
});
|
|
41406
|
+
let stdoutBuffer = "";
|
|
41407
|
+
let stderrBuffer = "";
|
|
41408
|
+
subprocess.stdout?.on("data", (chunk) => {
|
|
41409
|
+
const text13 = chunk.toString();
|
|
41410
|
+
stdoutBuffer += text13;
|
|
41411
|
+
process.stdout.write(text13);
|
|
41412
|
+
heartbeat.activity();
|
|
41413
|
+
});
|
|
41414
|
+
subprocess.stderr?.on("data", (chunk) => {
|
|
41415
|
+
const text13 = chunk.toString();
|
|
41416
|
+
stderrBuffer += text13;
|
|
41417
|
+
process.stderr.write(text13);
|
|
41418
|
+
heartbeat.activity();
|
|
41419
|
+
});
|
|
41420
|
+
const result = await subprocess;
|
|
41421
|
+
const buildResult2 = {
|
|
41422
|
+
success: result.exitCode === 0,
|
|
41423
|
+
stdout: truncateOutput2(stdoutBuffer),
|
|
41424
|
+
stderr: truncateOutput2(stderrBuffer),
|
|
41425
|
+
exitCode: result.exitCode ?? 0,
|
|
41426
|
+
duration: performance.now() - startTime
|
|
41427
|
+
};
|
|
41428
|
+
if (!buildResult2.success) {
|
|
41429
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "run_gradle");
|
|
41430
|
+
}
|
|
41431
|
+
return buildResult2;
|
|
41432
|
+
} catch (error) {
|
|
41433
|
+
if (error.timedOut) {
|
|
41434
|
+
throw new TimeoutError(`Gradle task '${task}' timed out after ${timeoutMs}ms`, {
|
|
41435
|
+
timeoutMs,
|
|
41436
|
+
operation: `gradle ${task}`
|
|
41437
|
+
});
|
|
41438
|
+
}
|
|
41439
|
+
throw new ToolError(
|
|
41440
|
+
`Gradle failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
41441
|
+
{ tool: "run_gradle", cause: error instanceof Error ? error : void 0 }
|
|
41442
|
+
);
|
|
41443
|
+
} finally {
|
|
41444
|
+
heartbeat.stop();
|
|
41445
|
+
process.stderr.write("\r \r");
|
|
41446
|
+
}
|
|
41447
|
+
}
|
|
41448
|
+
});
|
|
41449
|
+
var buildTools = [
|
|
41450
|
+
runScriptTool,
|
|
41451
|
+
installDepsTool,
|
|
41452
|
+
makeTool,
|
|
41453
|
+
tscTool,
|
|
41454
|
+
runMavenTool,
|
|
41455
|
+
runGradleTool
|
|
41456
|
+
];
|
|
40879
41457
|
|
|
40880
41458
|
// src/tools/permissions.ts
|
|
40881
41459
|
init_registry4();
|
|
@@ -47940,11 +48518,21 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
47940
48518
|
break;
|
|
47941
48519
|
}
|
|
47942
48520
|
}
|
|
47943
|
-
const inputText = messages.map((m) =>
|
|
48521
|
+
const inputText = messages.map((m) => {
|
|
48522
|
+
if (typeof m.content === "string") return m.content;
|
|
48523
|
+
try {
|
|
48524
|
+
return JSON.stringify(m.content);
|
|
48525
|
+
} catch {
|
|
48526
|
+
return "";
|
|
48527
|
+
}
|
|
48528
|
+
}).join("\n");
|
|
47944
48529
|
const estimatedInputTokens = provider.countTokens(inputText);
|
|
47945
|
-
|
|
47946
|
-
|
|
47947
|
-
|
|
48530
|
+
let serializedToolCalls = "";
|
|
48531
|
+
try {
|
|
48532
|
+
serializedToolCalls = JSON.stringify(collectedToolCalls);
|
|
48533
|
+
} catch {
|
|
48534
|
+
}
|
|
48535
|
+
const estimatedOutputTokens = provider.countTokens(responseContent + serializedToolCalls);
|
|
47948
48536
|
totalInputTokens += estimatedInputTokens;
|
|
47949
48537
|
totalOutputTokens += estimatedOutputTokens;
|
|
47950
48538
|
if (collectedToolCalls.length === 0) {
|
|
@@ -49485,6 +50073,25 @@ async function startRepl(options = {}) {
|
|
|
49485
50073
|
continue;
|
|
49486
50074
|
}
|
|
49487
50075
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
50076
|
+
if (errorMsg.includes("prompt token count") && errorMsg.includes("exceeds the limit")) {
|
|
50077
|
+
renderError("Context window full \u2014 compacting conversation history...");
|
|
50078
|
+
try {
|
|
50079
|
+
const compactionResult = await checkAndCompactContext(
|
|
50080
|
+
session,
|
|
50081
|
+
provider,
|
|
50082
|
+
void 0,
|
|
50083
|
+
toolRegistry
|
|
50084
|
+
);
|
|
50085
|
+
if (compactionResult?.wasCompacted) {
|
|
50086
|
+
console.log(chalk2.green(" \u2713 Context compacted. Please retry your message."));
|
|
50087
|
+
} else {
|
|
50088
|
+
console.log(chalk2.yellow(" \u26A0 Could not compact context. Use /clear to start fresh."));
|
|
50089
|
+
}
|
|
50090
|
+
} catch {
|
|
50091
|
+
console.log(chalk2.yellow(" \u26A0 Context compaction failed. Use /clear to start fresh."));
|
|
50092
|
+
}
|
|
50093
|
+
continue;
|
|
50094
|
+
}
|
|
49488
50095
|
if (errorMsg.includes("context length") || errorMsg.includes("tokens to keep")) {
|
|
49489
50096
|
renderError(errorMsg);
|
|
49490
50097
|
console.log();
|