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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/index.js +97 -48
  3. 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 = import_path2.default.join(cwd, "package.json");
493
- if (import_fs2.default.existsSync(pkgPath)) {
494
- const pkg = JSON.parse(import_fs2.default.readFileSync(pkgPath, "utf-8"));
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 (import_fs2.default.existsSync(import_path2.default.join(cwd, file))) return manager;
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
- var runBuild = (cwd) => runCommand(getRunScriptCommand(detectPackageManager3(cwd), "build"), cwd);
536
- var runLint = (cwd) => runCommand(getRunScriptCommand(detectPackageManager3(cwd), "lint"), cwd);
537
- var runTests = (cwd) => runCommand(getRunScriptCommand(detectPackageManager3(cwd), "test"), cwd);
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 import_fs22 = __toESM2(require("fs"));
588
- var import_path22 = __toESM2(require("path"));
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
- let scripts = [];
592
- try {
593
- const pkgPath = import_path22.default.resolve(targetCwd, "package.json");
594
- if (import_fs22.default.existsSync(pkgPath)) {
595
- const pkg = JSON.parse(import_fs22.default.readFileSync(pkgPath, "utf-8"));
596
- scripts = Object.keys(pkg.scripts || {});
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
- } catch {
599
- }
600
- console.log(`[BugZero] Running build...`);
601
- const buildRes = await runBuild(targetCwd);
602
- if (!buildRes.success) {
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 (scripts.includes("test")) {
613
- console.log(`[BugZero] Running tests...`);
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
- const content = import_fs2.default.readFileSync(filePath, "utf-8");
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 complete error output:
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
- var import_url = require("url");
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.success ? "\u2705 Passed" : "\u274C Failed"}
1601
- - **Lint:** ${lint.success ? "\u2705 Passed" : "\u274C Failed"}
1602
- - **Test:** ${test.success ? "\u2705 Passed" : "\u274C Failed"}
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:** \u2705 Passed
1622
- - **Lint:** \u2705 Passed
1623
- - **Test:** \u2705 Passed
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 = import_path22.default.resolve(cwd, "bugzero-report.md");
1776
+ const reportPath = import_path3.default.resolve(cwd, "bugzero-report.md");
1729
1777
  try {
1730
- import_fs22.default.writeFileSync(reportPath, content, "utf-8");
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
- console.log(` Build: ${build.success ? "\u2705 Passed" : "\u274C Failed (see report)"}`);
1773
- console.log(` Lint: ${lint.success ? "\u2705 Passed" : "\u274C Failed (see report)"}`);
1774
- console.log(` Tests: ${test.success ? "\u2705 Passed" : "\u274C Failed (see report)"}`);
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.36",
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)",