bugzero 0.0.36 → 0.0.37
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/README.md +2 -0
- package/dist/index.js +97 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,11 +101,13 @@ bugzero rescue
|
|
|
101
101
|
|
|
102
102
|
- **Backups on every patch.** Each file BugZero modifies gets a `.opspilot.bak` copy of its original content first.
|
|
103
103
|
- **Dry-run mode.** `bugzero rescue --dry-run` runs validation and error analysis, but makes no fix attempts and never modifies your source files (a report is still written).
|
|
104
|
+
- **Prompt size limits.** Very long error output and very large source files are shortened before being sent to the model (for logs, the start and end are kept), so a big failure can't exceed the model's context window or waste tokens.
|
|
104
105
|
|
|
105
106
|
### Project awareness
|
|
106
107
|
|
|
107
108
|
- **Framework detection.** Identifies Next.js, NestJS, Vite, Remix, Astro, SvelteKit, Nuxt, Angular, Create React App, or a plain TypeScript project from its config files and dependencies, and shows the result in the run banner.
|
|
108
109
|
- **Package manager detection.** Runs build, lint, and test with the tool your project actually uses — npm, pnpm, yarn, or bun. It checks the `packageManager` field in `package.json` first, then `pnpm-workspace.yaml` or a lockfile, and falls back to npm.
|
|
110
|
+
- **Script-aware validation.** Only runs the build, lint, and test scripts your `package.json` actually defines. A missing script is reported as skipped rather than failed, so a project without a `lint` script no longer shows a false lint failure. Pointing `--path` at a directory with no `package.json` stops immediately with a clear error.
|
|
109
111
|
- **Error parsing.** Recognizes TypeScript compiler errors (file, line, column, message), ESLint errors, and Jest failures to classify what broke and how many errors were found. Output in any other format is still passed to the model as raw logs.
|
|
110
112
|
|
|
111
113
|
### Integrations and output
|
package/dist/index.js
CHANGED
|
@@ -469,15 +469,19 @@ var require_dist2 = __commonJS({
|
|
|
469
469
|
detectPackageManager: () => detectPackageManager3,
|
|
470
470
|
getRunScriptCommand: () => getRunScriptCommand,
|
|
471
471
|
parseErrors: () => parseErrors,
|
|
472
|
+
readScripts: () => readScripts,
|
|
472
473
|
runBuild: () => runBuild,
|
|
473
474
|
runCommand: () => runCommand,
|
|
474
475
|
runLint: () => runLint,
|
|
476
|
+
runScript: () => runScript,
|
|
475
477
|
runTests: () => runTests,
|
|
476
478
|
runValidationPipeline: () => runValidationPipeline
|
|
477
479
|
});
|
|
478
480
|
module2.exports = __toCommonJS(index_exports);
|
|
479
481
|
var import_fs2 = __toESM2(require("fs"));
|
|
480
482
|
var import_path2 = __toESM2(require("path"));
|
|
483
|
+
var import_fs3 = __toESM2(require("fs"));
|
|
484
|
+
var import_path3 = __toESM2(require("path"));
|
|
481
485
|
var VALID_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
482
486
|
var LOCKFILE_MANAGERS = [
|
|
483
487
|
{ file: "pnpm-workspace.yaml", manager: "pnpm" },
|
|
@@ -489,9 +493,9 @@ var require_dist2 = __commonJS({
|
|
|
489
493
|
];
|
|
490
494
|
function detectPackageManager3(cwd = process.cwd()) {
|
|
491
495
|
try {
|
|
492
|
-
const pkgPath =
|
|
493
|
-
if (
|
|
494
|
-
const pkg = JSON.parse(
|
|
496
|
+
const pkgPath = import_path3.default.join(cwd, "package.json");
|
|
497
|
+
if (import_fs3.default.existsSync(pkgPath)) {
|
|
498
|
+
const pkg = JSON.parse(import_fs3.default.readFileSync(pkgPath, "utf-8"));
|
|
495
499
|
if (typeof pkg.packageManager === "string") {
|
|
496
500
|
const name = pkg.packageManager.split("@")[0].trim();
|
|
497
501
|
if (VALID_MANAGERS.includes(name)) {
|
|
@@ -502,7 +506,7 @@ var require_dist2 = __commonJS({
|
|
|
502
506
|
} catch {
|
|
503
507
|
}
|
|
504
508
|
for (const { file, manager } of LOCKFILE_MANAGERS) {
|
|
505
|
-
if (
|
|
509
|
+
if (import_fs3.default.existsSync(import_path3.default.join(cwd, file))) return manager;
|
|
506
510
|
}
|
|
507
511
|
return "npm";
|
|
508
512
|
}
|
|
@@ -532,9 +536,26 @@ var require_dist2 = __commonJS({
|
|
|
532
536
|
};
|
|
533
537
|
}
|
|
534
538
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
539
|
+
function readScripts(cwd = process.cwd()) {
|
|
540
|
+
try {
|
|
541
|
+
const pkgPath = import_path2.default.join(cwd, "package.json");
|
|
542
|
+
if (!import_fs2.default.existsSync(pkgPath)) return [];
|
|
543
|
+
const pkg = JSON.parse(import_fs2.default.readFileSync(pkgPath, "utf-8"));
|
|
544
|
+
if (typeof pkg.scripts !== "object" || pkg.scripts === null) return [];
|
|
545
|
+
return Object.keys(pkg.scripts);
|
|
546
|
+
} catch {
|
|
547
|
+
return [];
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
async function runScript(script, cwd) {
|
|
551
|
+
if (!readScripts(cwd).includes(script)) {
|
|
552
|
+
return { success: true, output: "", skipped: true };
|
|
553
|
+
}
|
|
554
|
+
return runCommand(getRunScriptCommand(detectPackageManager3(cwd), script), cwd);
|
|
555
|
+
}
|
|
556
|
+
var runBuild = (cwd) => runScript("build", cwd);
|
|
557
|
+
var runLint = (cwd) => runScript("lint", cwd);
|
|
558
|
+
var runTests = (cwd) => runScript("test", cwd);
|
|
538
559
|
var TS_ERROR_RE = /^(.+)\((\d+),(\d+)\):\s+error\s+TS\d+:\s+(.+)$/gm;
|
|
539
560
|
var ESLINT_ERROR_RE = /^\s+(\d+):(\d+)\s+error\s+(.+)$/gm;
|
|
540
561
|
var JEST_FAIL_RE = /● (.+)/g;
|
|
@@ -584,37 +605,29 @@ var require_dist2 = __commonJS({
|
|
|
584
605
|
}
|
|
585
606
|
return errors;
|
|
586
607
|
}
|
|
587
|
-
var
|
|
588
|
-
|
|
608
|
+
var STEPS = [
|
|
609
|
+
{ step: "build", label: "build", run: runBuild },
|
|
610
|
+
{ step: "lint", label: "lint", run: runLint },
|
|
611
|
+
{ step: "test", label: "tests", run: runTests }
|
|
612
|
+
];
|
|
589
613
|
async function runValidationPipeline(cwd) {
|
|
590
614
|
const targetCwd = cwd ?? process.cwd();
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
if (
|
|
595
|
-
|
|
596
|
-
|
|
615
|
+
const scripts = readScripts(targetCwd);
|
|
616
|
+
let ranAnyStep = false;
|
|
617
|
+
for (const { step, label, run } of STEPS) {
|
|
618
|
+
if (!scripts.includes(step)) {
|
|
619
|
+
console.log(`[BugZero] Skipping ${label}: no "${step}" script in package.json.`);
|
|
620
|
+
continue;
|
|
597
621
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
return { success: false, step: "build", output: buildRes.output };
|
|
604
|
-
}
|
|
605
|
-
if (scripts.includes("lint")) {
|
|
606
|
-
console.log(`[BugZero] Running lint...`);
|
|
607
|
-
const lintRes = await runLint(targetCwd);
|
|
608
|
-
if (!lintRes.success) {
|
|
609
|
-
return { success: false, step: "lint", output: lintRes.output };
|
|
622
|
+
ranAnyStep = true;
|
|
623
|
+
console.log(`[BugZero] Running ${label}...`);
|
|
624
|
+
const result = await run(targetCwd);
|
|
625
|
+
if (!result.success) {
|
|
626
|
+
return { success: false, step, output: result.output };
|
|
610
627
|
}
|
|
611
628
|
}
|
|
612
|
-
if (
|
|
613
|
-
console.
|
|
614
|
-
const testRes = await runTests(targetCwd);
|
|
615
|
-
if (!testRes.success) {
|
|
616
|
-
return { success: false, step: "test", output: testRes.output };
|
|
617
|
-
}
|
|
629
|
+
if (!ranAnyStep) {
|
|
630
|
+
console.warn(`[BugZero] No build, lint, or test scripts found in package.json \u2014 nothing to validate.`);
|
|
618
631
|
}
|
|
619
632
|
return { success: true, step: "none", output: "" };
|
|
620
633
|
}
|
|
@@ -777,11 +790,26 @@ var require_dist4 = __commonJS({
|
|
|
777
790
|
var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
778
791
|
var index_exports = {};
|
|
779
792
|
__export(index_exports, {
|
|
780
|
-
buildAnalysisPrompt: () => buildAnalysisPrompt
|
|
793
|
+
buildAnalysisPrompt: () => buildAnalysisPrompt,
|
|
794
|
+
truncateLogs: () => truncateLogs
|
|
781
795
|
});
|
|
782
796
|
module2.exports = __toCommonJS(index_exports);
|
|
783
797
|
var import_fs2 = __toESM2(require("fs"));
|
|
784
798
|
var import_path2 = __toESM2(require("path"));
|
|
799
|
+
var MAX_LOG_CHARS = 2e4;
|
|
800
|
+
var MAX_FILE_CHARS = 2e4;
|
|
801
|
+
var MAX_CONTEXT_CHARS = 6e4;
|
|
802
|
+
function truncateLogs(logs, maxChars = MAX_LOG_CHARS) {
|
|
803
|
+
if (logs.length <= maxChars) return logs;
|
|
804
|
+
const head = logs.slice(0, Math.floor(maxChars * 0.6));
|
|
805
|
+
const tail = logs.slice(logs.length - Math.floor(maxChars * 0.4));
|
|
806
|
+
const omitted = logs.length - head.length - tail.length;
|
|
807
|
+
return `${head}
|
|
808
|
+
|
|
809
|
+
... [${omitted} characters of log output omitted to fit the model's context] ...
|
|
810
|
+
|
|
811
|
+
${tail}`;
|
|
812
|
+
}
|
|
785
813
|
function resolveExistingPathPrefix(candidate) {
|
|
786
814
|
let current = candidate.replace(/(?::\d+)+$/, "").replace(/['"()\[\]`]+$/, "").trim();
|
|
787
815
|
while (current.length > 0) {
|
|
@@ -844,9 +872,15 @@ var require_dist4 = __commonJS({
|
|
|
844
872
|
return;
|
|
845
873
|
}
|
|
846
874
|
if (processedFiles.has(filePath)) return;
|
|
875
|
+
if (context.length >= MAX_CONTEXT_CHARS) return;
|
|
847
876
|
processedFiles.add(filePath);
|
|
848
877
|
try {
|
|
849
|
-
|
|
878
|
+
let content = import_fs2.default.readFileSync(filePath, "utf-8");
|
|
879
|
+
if (content.length > MAX_FILE_CHARS) {
|
|
880
|
+
const omitted = content.length - MAX_FILE_CHARS;
|
|
881
|
+
content = `${content.slice(0, MAX_FILE_CHARS)}
|
|
882
|
+
... [file truncated: ${omitted} more characters not shown]`;
|
|
883
|
+
}
|
|
850
884
|
context += `
|
|
851
885
|
--- File: ${relPath} ---
|
|
852
886
|
\`\`\`
|
|
@@ -931,10 +965,11 @@ ${w}`).join("\n\n")}
|
|
|
931
965
|
|
|
932
966
|
**CRITICAL RULE:** Do NOT suggest modifying or creating the files listed under "Previous Failed Attempts" if they failed with a "File not found" or "Search string not found" error. You must inspect the compiler error logs below to find the actual file that exists and contains the error.`;
|
|
933
967
|
}
|
|
968
|
+
compilerLogs = truncateLogs(compilerLogs);
|
|
934
969
|
const contextSection = getContextFiles(compilerLogs, cwd);
|
|
935
970
|
return `You are an expert software engineer specialising in fixing build, lint, and test failures.
|
|
936
971
|
|
|
937
|
-
A project located at "${cwd}" failed to build. Here is the
|
|
972
|
+
A project located at "${cwd}" failed to build. Here is the error output (very long output is shortened in the middle):
|
|
938
973
|
|
|
939
974
|
\`\`\`
|
|
940
975
|
${compilerLogs}
|
|
@@ -1444,12 +1479,24 @@ var require_dist7 = __commonJS({
|
|
|
1444
1479
|
}
|
|
1445
1480
|
var import_analyzers = require_dist2();
|
|
1446
1481
|
var import_agents = require_dist6();
|
|
1482
|
+
var import_fs3 = __toESM2(require("fs"));
|
|
1483
|
+
var import_path3 = __toESM2(require("path"));
|
|
1484
|
+
var import_url = require("url");
|
|
1447
1485
|
var import_fs22 = __toESM2(require("fs"));
|
|
1448
1486
|
var import_path22 = __toESM2(require("path"));
|
|
1449
|
-
|
|
1487
|
+
function assertNodeProject(cwd) {
|
|
1488
|
+
if (!import_fs22.default.existsSync(import_path22.default.join(cwd, "package.json"))) {
|
|
1489
|
+
throw new Error(`No package.json found in ${cwd}. Point --path at a Node.js project.`);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1450
1492
|
var import_ai_provider = require_dist3();
|
|
1493
|
+
function statusLabel(result) {
|
|
1494
|
+
if (result.skipped) return "\u23ED\uFE0F Skipped (no script defined)";
|
|
1495
|
+
return result.success ? "\u2705 Passed" : "\u274C Failed";
|
|
1496
|
+
}
|
|
1451
1497
|
async function orchestrate2(options = {}) {
|
|
1452
1498
|
const cwd = options.cwd ?? process.cwd();
|
|
1499
|
+
assertNodeProject(cwd);
|
|
1453
1500
|
const [build, lint, test] = await Promise.all([
|
|
1454
1501
|
(0, import_analyzers.runBuild)(cwd),
|
|
1455
1502
|
(0, import_analyzers.runLint)(cwd),
|
|
@@ -1465,6 +1512,7 @@ var require_dist7 = __commonJS({
|
|
|
1465
1512
|
}
|
|
1466
1513
|
async function orchestrateAndFix2(options = {}) {
|
|
1467
1514
|
const cwd = options.cwd ?? process.cwd();
|
|
1515
|
+
assertNodeProject(cwd);
|
|
1468
1516
|
const maxAttempts = options.maxAttempts ?? 3;
|
|
1469
1517
|
console.log(`[BugZero] Running validation pipeline in: ${cwd}`);
|
|
1470
1518
|
const pipelineResult = await (0, import_analyzers.runValidationPipeline)(cwd);
|
|
@@ -1597,9 +1645,9 @@ Generate the Markdown report directly. Do not wrap it in markdown block fences (
|
|
|
1597
1645
|
**Framework:** \`${detectFramework2(cwd)}\`
|
|
1598
1646
|
|
|
1599
1647
|
## \u{1F4CA} Status Summary
|
|
1600
|
-
- **Build:** ${build
|
|
1601
|
-
- **Lint:** ${lint
|
|
1602
|
-
- **Test:** ${test
|
|
1648
|
+
- **Build:** ${statusLabel(build)}
|
|
1649
|
+
- **Lint:** ${statusLabel(lint)}
|
|
1650
|
+
- **Test:** ${statusLabel(test)}
|
|
1603
1651
|
|
|
1604
1652
|
## \u274C Failed Checks & Error Output
|
|
1605
1653
|
${logs}
|
|
@@ -1618,9 +1666,9 @@ ${logs}
|
|
|
1618
1666
|
**Framework:** \`${detectFramework2(cwd)}\`
|
|
1619
1667
|
|
|
1620
1668
|
## \u{1F4CA} Status Summary
|
|
1621
|
-
- **Build:**
|
|
1622
|
-
- **Lint:**
|
|
1623
|
-
- **Test:**
|
|
1669
|
+
- **Build:** ${statusLabel(build)}
|
|
1670
|
+
- **Lint:** ${statusLabel(lint)}
|
|
1671
|
+
- **Test:** ${statusLabel(test)}
|
|
1624
1672
|
|
|
1625
1673
|
\u{1F389} **All checks passed! Your project is in perfect shape.**`;
|
|
1626
1674
|
}
|
|
@@ -1725,9 +1773,9 @@ ${rawOutput}
|
|
|
1725
1773
|
|
|
1726
1774
|
---
|
|
1727
1775
|
*Report generated by **BugZero** on ${(/* @__PURE__ */ new Date()).toLocaleString()}*`;
|
|
1728
|
-
const reportPath =
|
|
1776
|
+
const reportPath = import_path3.default.resolve(cwd, "bugzero-report.md");
|
|
1729
1777
|
try {
|
|
1730
|
-
|
|
1778
|
+
import_fs3.default.writeFileSync(reportPath, content, "utf-8");
|
|
1731
1779
|
const clickableUrl = (0, import_url.pathToFileURL)(reportPath).toString();
|
|
1732
1780
|
console.log(`
|
|
1733
1781
|
\u{1F4DD} Generated report successfully!
|
|
@@ -1769,9 +1817,10 @@ program.command("hunt").description("Run build, lint, and tests \u2014 report is
|
|
|
1769
1817
|
`);
|
|
1770
1818
|
const { build, lint, test } = await (0, import_core.orchestrate)({ cwd });
|
|
1771
1819
|
console.log("\u2500\u2500 Pipeline Summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1772
|
-
|
|
1773
|
-
console.log(`
|
|
1774
|
-
console.log(`
|
|
1820
|
+
const label = (r) => r.skipped ? "\u23ED\uFE0F Skipped (no script)" : r.success ? "\u2705 Passed" : "\u274C Failed (see report)";
|
|
1821
|
+
console.log(` Build: ${label(build)}`);
|
|
1822
|
+
console.log(` Lint: ${label(lint)}`);
|
|
1823
|
+
console.log(` Tests: ${label(test)}`);
|
|
1775
1824
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
1776
1825
|
const allPassed = build.success && lint.success && test.success;
|
|
1777
1826
|
console.log(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bugzero",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"description": "Autonomous AI-powered CLI and GitHub Action that detects build, lint, and test failures, generates multi-file patches, applies them atomically with fuzzy matching, and re-verifies until your project is green.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Saksham Agarwal (https://github.com/Saksham1800t)",
|