bugzero 0.0.40 → 0.0.42
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 +4 -2
- package/dist/index.js +167 -44
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -100,8 +100,9 @@ bugzero rescue
|
|
|
100
100
|
### Safety
|
|
101
101
|
|
|
102
102
|
- **Backups on every patch.** Each file BugZero modifies gets a `.opspilot.bak` copy of its original content first.
|
|
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
|
|
103
|
+
- **Dry-run mode.** `bugzero rescue --dry-run` runs validation and error analysis, but makes no fix attempts and never modifies your source files (it still writes a report that diagnoses the failures it found). It exits with code 1 if it found failures and 0 if everything already passes, so you can use it as a check in scripts.
|
|
104
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.
|
|
105
|
+
- **Command timeouts.** `--timeout <seconds>` (available on both `hunt` and `rescue`) stops any build, lint, or test command that runs longer than that. It kills the whole process tree rather than just the shell, so a hung test run cannot linger in the background, and the step is reported as failed along with whatever output it produced. Without it, a command that hangs will hang BugZero too, so it is worth setting in CI.
|
|
105
106
|
|
|
106
107
|
### Project awareness
|
|
107
108
|
|
|
@@ -190,7 +191,7 @@ OPENROUTER_API_KEY=your_openrouter_api_key_here
|
|
|
190
191
|
## Commands
|
|
191
192
|
|
|
192
193
|
### `bugzero hunt`
|
|
193
|
-
Run build, lint, and test checks. Reports all failures without modifying any files.
|
|
194
|
+
Run build, lint, and test checks. Reports all failures without modifying any files. Accepts `--timeout <seconds>`, like `rescue`.
|
|
194
195
|
|
|
195
196
|
```bash
|
|
196
197
|
bugzero hunt --path /path/to/your/project
|
|
@@ -210,6 +211,7 @@ bugzero rescue --path /path/to/your/project
|
|
|
210
211
|
|---|---|---|---|
|
|
211
212
|
| `--path <dir>` | `-p` | `.` | Path to the target project |
|
|
212
213
|
| `--max-attempts <n>` | `-n` | `3` | Maximum AI fix iterations before giving up |
|
|
214
|
+
| `--timeout <seconds>` | `-t` | none | Stop any build, lint, or test command that runs longer than this many seconds |
|
|
213
215
|
| `--dry-run` | | `false` | Analyze only — no files will be written |
|
|
214
216
|
|
|
215
217
|
</details>
|
package/dist/index.js
CHANGED
|
@@ -479,9 +479,9 @@ var require_dist2 = __commonJS({
|
|
|
479
479
|
});
|
|
480
480
|
module2.exports = __toCommonJS(index_exports);
|
|
481
481
|
var import_fs2 = __toESM2(require("fs"));
|
|
482
|
-
var import_path2 = __toESM2(require("path"));
|
|
483
|
-
var import_fs3 = __toESM2(require("fs"));
|
|
484
482
|
var import_path3 = __toESM2(require("path"));
|
|
483
|
+
var import_fs3 = __toESM2(require("fs"));
|
|
484
|
+
var import_path2 = __toESM2(require("path"));
|
|
485
485
|
var VALID_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
486
486
|
var LOCKFILE_MANAGERS = [
|
|
487
487
|
{ file: "pnpm-workspace.yaml", manager: "pnpm" },
|
|
@@ -493,7 +493,7 @@ var require_dist2 = __commonJS({
|
|
|
493
493
|
];
|
|
494
494
|
function detectPackageManager3(cwd = process.cwd()) {
|
|
495
495
|
try {
|
|
496
|
-
const pkgPath =
|
|
496
|
+
const pkgPath = import_path2.default.join(cwd, "package.json");
|
|
497
497
|
if (import_fs3.default.existsSync(pkgPath)) {
|
|
498
498
|
const pkg = JSON.parse(import_fs3.default.readFileSync(pkgPath, "utf-8"));
|
|
499
499
|
if (typeof pkg.packageManager === "string") {
|
|
@@ -506,39 +506,76 @@ var require_dist2 = __commonJS({
|
|
|
506
506
|
} catch {
|
|
507
507
|
}
|
|
508
508
|
for (const { file, manager } of LOCKFILE_MANAGERS) {
|
|
509
|
-
if (import_fs3.default.existsSync(
|
|
509
|
+
if (import_fs3.default.existsSync(import_path2.default.join(cwd, file))) return manager;
|
|
510
510
|
}
|
|
511
511
|
return "npm";
|
|
512
512
|
}
|
|
513
513
|
function getRunScriptCommand(manager, script) {
|
|
514
514
|
return `${manager} run ${script}`;
|
|
515
515
|
}
|
|
516
|
-
|
|
516
|
+
var import_child_process = require("child_process");
|
|
517
|
+
var import_path22 = __toESM2(require("path"));
|
|
518
|
+
var import_tree_kill = __toESM2(require("tree-kill"));
|
|
519
|
+
function killProcessTree(pid) {
|
|
520
|
+
if (process.platform === "win32") {
|
|
521
|
+
const systemRoot = process.env.SystemRoot ?? process.env.windir ?? "C:\\Windows";
|
|
522
|
+
const taskkill = import_path22.default.join(systemRoot, "System32", "taskkill.exe");
|
|
523
|
+
(0, import_child_process.spawnSync)(taskkill, ["/pid", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
(0, import_tree_kill.default)(pid, "SIGKILL");
|
|
527
|
+
}
|
|
528
|
+
var KILL_GRACE_MS = 5e3;
|
|
529
|
+
async function runCommand(command, cwd, options = {}) {
|
|
517
530
|
const { execa } = await import("execa");
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
env
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
output: result.all ?? result.stdout
|
|
531
|
-
};
|
|
532
|
-
} catch (err) {
|
|
531
|
+
const subprocess = execa(command, {
|
|
532
|
+
shell: true,
|
|
533
|
+
cwd: cwd ?? process.cwd(),
|
|
534
|
+
all: true,
|
|
535
|
+
env: {
|
|
536
|
+
...process.env,
|
|
537
|
+
CI: "true"
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
const timedOutResult = (output, confirmedStopped) => {
|
|
541
|
+
const seconds = options.timeoutMs / 1e3;
|
|
542
|
+
const note = confirmedStopped ? "and was stopped" : "and could not be confirmed stopped";
|
|
533
543
|
return {
|
|
534
544
|
success: false,
|
|
535
|
-
|
|
545
|
+
timedOut: true,
|
|
546
|
+
output: `${output}
|
|
547
|
+
|
|
548
|
+
[BugZero] Command timed out after ${seconds}s ${note}: ${command}`
|
|
536
549
|
};
|
|
550
|
+
};
|
|
551
|
+
let timedOut = false;
|
|
552
|
+
let timer;
|
|
553
|
+
let graceTimer;
|
|
554
|
+
const gaveUp = new Promise((resolve) => {
|
|
555
|
+
if (options.timeoutMs === void 0) return;
|
|
556
|
+
timer = setTimeout(() => {
|
|
557
|
+
timedOut = true;
|
|
558
|
+
if (subprocess.pid !== void 0) killProcessTree(subprocess.pid);
|
|
559
|
+
graceTimer = setTimeout(() => resolve(timedOutResult("", false)), KILL_GRACE_MS);
|
|
560
|
+
}, options.timeoutMs);
|
|
561
|
+
});
|
|
562
|
+
const finished = subprocess.then(
|
|
563
|
+
(result) => ({ success: true, output: result.all ?? result.stdout }),
|
|
564
|
+
(err) => {
|
|
565
|
+
const output = err.all ?? err.stderr ?? err.stdout ?? err.message;
|
|
566
|
+
return timedOut ? timedOutResult(output, true) : { success: false, output };
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
try {
|
|
570
|
+
return await Promise.race([finished, gaveUp]);
|
|
571
|
+
} finally {
|
|
572
|
+
clearTimeout(timer);
|
|
573
|
+
clearTimeout(graceTimer);
|
|
537
574
|
}
|
|
538
575
|
}
|
|
539
576
|
function readScripts(cwd = process.cwd()) {
|
|
540
577
|
try {
|
|
541
|
-
const pkgPath =
|
|
578
|
+
const pkgPath = import_path3.default.join(cwd, "package.json");
|
|
542
579
|
if (!import_fs2.default.existsSync(pkgPath)) return [];
|
|
543
580
|
const pkg = JSON.parse(import_fs2.default.readFileSync(pkgPath, "utf-8"));
|
|
544
581
|
if (typeof pkg.scripts !== "object" || pkg.scripts === null) return [];
|
|
@@ -547,15 +584,15 @@ var require_dist2 = __commonJS({
|
|
|
547
584
|
return [];
|
|
548
585
|
}
|
|
549
586
|
}
|
|
550
|
-
async function runScript(script, cwd) {
|
|
587
|
+
async function runScript(script, cwd, options) {
|
|
551
588
|
if (!readScripts(cwd).includes(script)) {
|
|
552
589
|
return { success: true, output: "", skipped: true };
|
|
553
590
|
}
|
|
554
|
-
return runCommand(getRunScriptCommand(detectPackageManager3(cwd), script), cwd);
|
|
591
|
+
return runCommand(getRunScriptCommand(detectPackageManager3(cwd), script), cwd, options);
|
|
555
592
|
}
|
|
556
|
-
var runBuild = (cwd) => runScript("build", cwd);
|
|
557
|
-
var runLint = (cwd) => runScript("lint", cwd);
|
|
558
|
-
var runTests = (cwd) => runScript("test", cwd);
|
|
593
|
+
var runBuild = (cwd, options) => runScript("build", cwd, options);
|
|
594
|
+
var runLint = (cwd, options) => runScript("lint", cwd, options);
|
|
595
|
+
var runTests = (cwd, options) => runScript("test", cwd, options);
|
|
559
596
|
var TS_ERROR_RE = /^(.+)\((\d+),(\d+)\):\s+error\s+TS\d+:\s+(.+)$/gm;
|
|
560
597
|
var ESLINT_ERROR_RE = /^\s+(\d+):(\d+)\s+error\s+(.+)$/gm;
|
|
561
598
|
var JEST_FAIL_RE = /● (.+)/g;
|
|
@@ -610,7 +647,7 @@ var require_dist2 = __commonJS({
|
|
|
610
647
|
{ step: "lint", label: "lint", run: runLint },
|
|
611
648
|
{ step: "test", label: "tests", run: runTests }
|
|
612
649
|
];
|
|
613
|
-
async function runValidationPipeline(cwd) {
|
|
650
|
+
async function runValidationPipeline(cwd, options) {
|
|
614
651
|
const targetCwd = cwd ?? process.cwd();
|
|
615
652
|
const scripts = readScripts(targetCwd);
|
|
616
653
|
let ranAnyStep = false;
|
|
@@ -621,7 +658,7 @@ var require_dist2 = __commonJS({
|
|
|
621
658
|
}
|
|
622
659
|
ranAnyStep = true;
|
|
623
660
|
console.log(`[BugZero] Running ${label}...`);
|
|
624
|
-
const result = await run(targetCwd);
|
|
661
|
+
const result = await run(targetCwd, options);
|
|
625
662
|
if (!result.success) {
|
|
626
663
|
return { success: false, step, output: result.output };
|
|
627
664
|
}
|
|
@@ -1307,6 +1344,11 @@ var require_dist6 = __commonJS({
|
|
|
1307
1344
|
completionTokens: (0, import_langgraph.Annotation)({
|
|
1308
1345
|
reducer: (old, value) => old + value,
|
|
1309
1346
|
default: () => 0
|
|
1347
|
+
}),
|
|
1348
|
+
/** Per-command timeout in milliseconds for validation steps (undefined = no limit) */
|
|
1349
|
+
timeoutMs: (0, import_langgraph.Annotation)({
|
|
1350
|
+
reducer: (_, value) => value,
|
|
1351
|
+
default: () => void 0
|
|
1310
1352
|
})
|
|
1311
1353
|
});
|
|
1312
1354
|
var import_ai_provider = require_dist3();
|
|
@@ -1387,7 +1429,7 @@ Any other files from that same suggestion were rolled back to keep the change at
|
|
|
1387
1429
|
};
|
|
1388
1430
|
}
|
|
1389
1431
|
console.log("[BugZero] Re-running validation pipeline to verify fix\u2026");
|
|
1390
|
-
const result = await (0, import_analyzers.runValidationPipeline)(state.cwd);
|
|
1432
|
+
const result = await (0, import_analyzers.runValidationPipeline)(state.cwd, { timeoutMs: state.timeoutMs });
|
|
1391
1433
|
if (result.success) {
|
|
1392
1434
|
console.log("[BugZero] \u2705 Validation succeeded!");
|
|
1393
1435
|
} else {
|
|
@@ -1456,7 +1498,8 @@ var require_dist7 = __commonJS({
|
|
|
1456
1498
|
detectPackageManager: () => import_analyzers2.detectPackageManager,
|
|
1457
1499
|
orchestrate: () => orchestrate2,
|
|
1458
1500
|
orchestrateAndFix: () => orchestrateAndFix2,
|
|
1459
|
-
resolveMaxAttempts: () => resolveMaxAttempts2
|
|
1501
|
+
resolveMaxAttempts: () => resolveMaxAttempts2,
|
|
1502
|
+
resolveTimeoutMs: () => resolveTimeoutMs2
|
|
1460
1503
|
});
|
|
1461
1504
|
module2.exports = __toCommonJS(index_exports);
|
|
1462
1505
|
var import_fs2 = __toESM2(require("fs"));
|
|
@@ -1491,7 +1534,59 @@ var require_dist7 = __commonJS({
|
|
|
1491
1534
|
var import_fs3 = __toESM2(require("fs"));
|
|
1492
1535
|
var import_path3 = __toESM2(require("path"));
|
|
1493
1536
|
var import_url = require("url");
|
|
1537
|
+
function buildDryRunPrompt(cwd, rawOutput) {
|
|
1538
|
+
return `You are an expert software engineer assistant. BugZero ran in dry-run mode on the project located at "${cwd}": it ran the project's build/lint/test checks and found failures, but it intentionally attempted NO fixes and modified NO files.
|
|
1539
|
+
Below is the error output.
|
|
1540
|
+
Please analyze these logs and generate a professional, beautifully formatted Markdown report summarizing:
|
|
1541
|
+
1. **Diagnosis:** Clear explanation of what failed and why.
|
|
1542
|
+
2. **Root Cause:** The underlying issue in the code or config.
|
|
1543
|
+
3. **Suggested Fix:** Step-by-step instructions on what files need to be modified and what exact changes to make.
|
|
1544
|
+
|
|
1545
|
+
Error Logs:
|
|
1546
|
+
${rawOutput}
|
|
1547
|
+
|
|
1548
|
+
Generate the Markdown report directly. Do not wrap it in markdown block fences (\`\`\`markdown ... \`\`\`). Just write the markdown text directly.`;
|
|
1549
|
+
}
|
|
1550
|
+
function buildDryRunMetadata(response) {
|
|
1551
|
+
const usage = response.usage ? `Prompt: **${response.usage.prompt_tokens}** | Completion: **${response.usage.completion_tokens}** | Total: **${response.usage.total_tokens}**` : "*N/A*";
|
|
1552
|
+
return `
|
|
1553
|
+
|
|
1554
|
+
---
|
|
1555
|
+
### \u{1F50D} BugZero Dry Run Metadata
|
|
1556
|
+
- **Mode:** Dry run (no fixes attempted, no files modified)
|
|
1557
|
+
- **AI Brain (Model) used for Diagnosis:** \`${response.model || "unknown"}\`
|
|
1558
|
+
- **Token Usage for Diagnosis:** ${usage}`;
|
|
1559
|
+
}
|
|
1560
|
+
function buildDryRunFallbackReport(params) {
|
|
1561
|
+
const aiNote = params.aiError ? `
|
|
1562
|
+
*AI diagnosis was unavailable for this report: ${params.aiError}*
|
|
1563
|
+
` : "";
|
|
1564
|
+
return `# \u{1F50D} BugZero Dry Run Report
|
|
1565
|
+
|
|
1566
|
+
**Date:** ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
1567
|
+
**Project Path:** \`${params.cwd}\`
|
|
1568
|
+
**Framework:** \`${params.framework}\`
|
|
1569
|
+
|
|
1570
|
+
## \u{1F4CA} Summary
|
|
1571
|
+
- **Mode:** Dry run \u2014 no fixes were attempted and no files were modified
|
|
1572
|
+
- **Result:** \u274C Failures detected
|
|
1573
|
+
${aiNote}
|
|
1574
|
+
## \u274C Detected Errors & Logs
|
|
1575
|
+
\`\`\`text
|
|
1576
|
+
${params.rawOutput}
|
|
1577
|
+
\`\`\`
|
|
1578
|
+
|
|
1579
|
+
Re-run without \`--dry-run\` to let BugZero attempt a fix.
|
|
1580
|
+
`;
|
|
1581
|
+
}
|
|
1494
1582
|
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
1583
|
+
function resolveTimeoutMs2(seconds) {
|
|
1584
|
+
if (seconds === void 0) return void 0;
|
|
1585
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
1586
|
+
throw new Error(`--timeout must be a positive number of seconds (received ${seconds}).`);
|
|
1587
|
+
}
|
|
1588
|
+
return Math.round(seconds * 1e3);
|
|
1589
|
+
}
|
|
1495
1590
|
function resolveMaxAttempts2(value) {
|
|
1496
1591
|
const attempts = value ?? DEFAULT_MAX_ATTEMPTS;
|
|
1497
1592
|
if (!Number.isInteger(attempts) || attempts < 1) {
|
|
@@ -1514,10 +1609,11 @@ var require_dist7 = __commonJS({
|
|
|
1514
1609
|
async function orchestrate2(options = {}) {
|
|
1515
1610
|
const cwd = options.cwd ?? process.cwd();
|
|
1516
1611
|
assertNodeProject(cwd);
|
|
1612
|
+
const timeoutMs = resolveTimeoutMs2(options.timeoutSeconds);
|
|
1517
1613
|
const [build, lint, test] = await Promise.all([
|
|
1518
|
-
(0, import_analyzers.runBuild)(cwd),
|
|
1519
|
-
(0, import_analyzers.runLint)(cwd),
|
|
1520
|
-
(0, import_analyzers.runTests)(cwd)
|
|
1614
|
+
(0, import_analyzers.runBuild)(cwd, { timeoutMs }),
|
|
1615
|
+
(0, import_analyzers.runLint)(cwd, { timeoutMs }),
|
|
1616
|
+
(0, import_analyzers.runTests)(cwd, { timeoutMs })
|
|
1521
1617
|
]);
|
|
1522
1618
|
await writeReport(cwd, "hunt", {
|
|
1523
1619
|
success: build.success && lint.success && test.success,
|
|
@@ -1531,8 +1627,9 @@ var require_dist7 = __commonJS({
|
|
|
1531
1627
|
const cwd = options.cwd ?? process.cwd();
|
|
1532
1628
|
assertNodeProject(cwd);
|
|
1533
1629
|
const maxAttempts = resolveMaxAttempts2(options.maxAttempts);
|
|
1630
|
+
const timeoutMs = resolveTimeoutMs2(options.timeoutSeconds);
|
|
1534
1631
|
console.log(`[BugZero] Running validation pipeline in: ${cwd}`);
|
|
1535
|
-
const pipelineResult = await (0, import_analyzers.runValidationPipeline)(cwd);
|
|
1632
|
+
const pipelineResult = await (0, import_analyzers.runValidationPipeline)(cwd, { timeoutMs });
|
|
1536
1633
|
if (pipelineResult.success) {
|
|
1537
1634
|
console.log("[BugZero] Validation already passing \u2014 nothing to fix.");
|
|
1538
1635
|
await writeReport(cwd, "rescue", {
|
|
@@ -1552,7 +1649,8 @@ var require_dist7 = __commonJS({
|
|
|
1552
1649
|
attempts: 0,
|
|
1553
1650
|
maxAttempts,
|
|
1554
1651
|
error: "Dry-run: analysis complete, no files modified.",
|
|
1555
|
-
rawOutput: pipelineResult.output
|
|
1652
|
+
rawOutput: pipelineResult.output,
|
|
1653
|
+
dryRun: true
|
|
1556
1654
|
});
|
|
1557
1655
|
return {
|
|
1558
1656
|
success: false,
|
|
@@ -1564,7 +1662,8 @@ var require_dist7 = __commonJS({
|
|
|
1564
1662
|
const finalState = await (0, import_agents.runRepairWorkflow)({
|
|
1565
1663
|
cwd,
|
|
1566
1664
|
logs: pipelineResult.output,
|
|
1567
|
-
maxAttempts
|
|
1665
|
+
maxAttempts,
|
|
1666
|
+
timeoutMs
|
|
1568
1667
|
});
|
|
1569
1668
|
const result = {
|
|
1570
1669
|
success: finalState.success,
|
|
@@ -1689,7 +1788,20 @@ ${logs}
|
|
|
1689
1788
|
}
|
|
1690
1789
|
} else {
|
|
1691
1790
|
const { success, attempts, maxAttempts, appliedFix, error, rawOutput, modelUsed, promptTokens, completionTokens } = data;
|
|
1692
|
-
if (
|
|
1791
|
+
if (data.dryRun) {
|
|
1792
|
+
console.log("[BugZero] Calling AI to diagnose the detected errors and write report...");
|
|
1793
|
+
try {
|
|
1794
|
+
const result = await provider.invoke(buildDryRunPrompt(cwd, rawOutput ?? ""), { cwd });
|
|
1795
|
+
content = result.content + buildDryRunMetadata(result);
|
|
1796
|
+
} catch (e) {
|
|
1797
|
+
content = buildDryRunFallbackReport({
|
|
1798
|
+
cwd,
|
|
1799
|
+
framework: detectFramework2(cwd),
|
|
1800
|
+
rawOutput: rawOutput ?? "",
|
|
1801
|
+
aiError: e.message
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
} else if (success && appliedFix) {
|
|
1693
1805
|
console.log("[BugZero] Calling AI to write solution summary report...");
|
|
1694
1806
|
const patchedFiles = appliedFix.patches.map((p) => p.filePath).join(", ");
|
|
1695
1807
|
const prompt = `You are an expert software engineer assistant. An automated AI agent successfully resolved a build/lint/test failure in a project located at "${cwd}" after ${attempts} attempts by applying a patch to: ${patchedFiles}.
|
|
@@ -1869,20 +1981,29 @@ function buildRescueSummary(result, options) {
|
|
|
1869
1981
|
|
|
1870
1982
|
// src/index.ts
|
|
1871
1983
|
var { version } = JSON.parse(import_fs.default.readFileSync(import_path.default.join(__dirname, "..", "package.json"), "utf-8"));
|
|
1984
|
+
var TIMEOUT_DESCRIPTION = "Stop any build/lint/test command that runs longer than this many seconds";
|
|
1985
|
+
function parseTimeout(raw) {
|
|
1986
|
+
if (raw === void 0) return void 0;
|
|
1987
|
+
const seconds = Number(raw);
|
|
1988
|
+
(0, import_core.resolveTimeoutMs)(seconds);
|
|
1989
|
+
return seconds;
|
|
1990
|
+
}
|
|
1872
1991
|
var program = new import_commander.Command();
|
|
1873
1992
|
program.name("bugzero").description("AI-powered build issue fixer \u2014 detects and repairs build errors automatically").version(version);
|
|
1874
|
-
program.command("hunt").description("Run build, lint, and tests \u2014 report issues without modifying files").option("-p, --path <dir>", "Path to the target project", ".").action(async (opts) => {
|
|
1993
|
+
program.command("hunt").description("Run build, lint, and tests \u2014 report issues without modifying files").option("-p, --path <dir>", "Path to the target project", ".").option("-t, --timeout <seconds>", TIMEOUT_DESCRIPTION).action(async (opts) => {
|
|
1875
1994
|
try {
|
|
1876
1995
|
const cwd = import_path.default.resolve(opts.path);
|
|
1996
|
+
const timeoutSeconds = parseTimeout(opts.timeout);
|
|
1877
1997
|
const framework = (0, import_core.detectFramework)(cwd);
|
|
1878
1998
|
const packageManager = (0, import_core.detectPackageManager)(cwd);
|
|
1879
1999
|
console.log(`
|
|
1880
2000
|
\u{1F50D} BugZero \u2014 Analyzing project`);
|
|
1881
2001
|
console.log(` Path: ${cwd}`);
|
|
1882
2002
|
console.log(` Framework: ${framework}`);
|
|
1883
|
-
console.log(` Package manager: ${packageManager}
|
|
1884
|
-
`);
|
|
1885
|
-
|
|
2003
|
+
console.log(` Package manager: ${packageManager}`);
|
|
2004
|
+
if (timeoutSeconds !== void 0) console.log(` Timeout: ${timeoutSeconds}s per command`);
|
|
2005
|
+
console.log();
|
|
2006
|
+
const { build, lint, test } = await (0, import_core.orchestrate)({ cwd, timeoutSeconds });
|
|
1886
2007
|
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");
|
|
1887
2008
|
const label = (r) => r.skipped ? "\u23ED\uFE0F Skipped (no script)" : r.success ? "\u2705 Passed" : "\u274C Failed (see report)";
|
|
1888
2009
|
console.log(` Build: ${label(build)}`);
|
|
@@ -1900,10 +2021,11 @@ ${allPassed ? "\u2705 All checks passed" : "\u274C Issues found \u2014 run 'bugz
|
|
|
1900
2021
|
process.exit(1);
|
|
1901
2022
|
}
|
|
1902
2023
|
});
|
|
1903
|
-
program.command("rescue").description("Detect build failures and automatically apply AI-generated fixes").option("-p, --path <dir>", "Path to the target project", ".").option("-n, --max-attempts <number>", "Maximum AI fix attempts", "3").option("--dry-run", "Analyse only \u2014 print what would be fixed without writing files", false).action(async (opts) => {
|
|
2024
|
+
program.command("rescue").description("Detect build failures and automatically apply AI-generated fixes").option("-p, --path <dir>", "Path to the target project", ".").option("-n, --max-attempts <number>", "Maximum AI fix attempts", "3").option("-t, --timeout <seconds>", TIMEOUT_DESCRIPTION).option("--dry-run", "Analyse only \u2014 print what would be fixed without writing files", false).action(async (opts) => {
|
|
1904
2025
|
try {
|
|
1905
2026
|
const cwd = import_path.default.resolve(opts.path);
|
|
1906
2027
|
const maxAttempts = (0, import_core.resolveMaxAttempts)(Number(opts.maxAttempts));
|
|
2028
|
+
const timeoutSeconds = parseTimeout(opts.timeout);
|
|
1907
2029
|
const dryRun = opts.dryRun;
|
|
1908
2030
|
const framework = (0, import_core.detectFramework)(cwd);
|
|
1909
2031
|
const packageManager = (0, import_core.detectPackageManager)(cwd);
|
|
@@ -1913,9 +2035,10 @@ program.command("rescue").description("Detect build failures and automatically a
|
|
|
1913
2035
|
console.log(` Framework: ${framework}`);
|
|
1914
2036
|
console.log(` Package manager: ${packageManager}`);
|
|
1915
2037
|
console.log(` Max attempts: ${maxAttempts}`);
|
|
2038
|
+
if (timeoutSeconds !== void 0) console.log(` Timeout: ${timeoutSeconds}s per command`);
|
|
1916
2039
|
if (dryRun) console.log(` Mode: DRY RUN (no files will be modified)`);
|
|
1917
2040
|
console.log();
|
|
1918
|
-
const result = await (0, import_core.orchestrateAndFix)({ cwd, maxAttempts, dryRun });
|
|
2041
|
+
const result = await (0, import_core.orchestrateAndFix)({ cwd, maxAttempts, dryRun, timeoutSeconds });
|
|
1919
2042
|
console.log("\n\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");
|
|
1920
2043
|
const summary = buildRescueSummary(result, { dryRun });
|
|
1921
2044
|
for (const line of summary.lines) console.log(line);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bugzero",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.42",
|
|
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)",
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"@langchain/langgraph": "^1.3.2",
|
|
49
49
|
"axios": "^1.16.1",
|
|
50
50
|
"commander": "^15.0.0",
|
|
51
|
-
"execa": "^7.2.0"
|
|
51
|
+
"execa": "^7.2.0",
|
|
52
|
+
"tree-kill": "^1.2.2"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@opspilot/agents": "workspace:*",
|