@delegance/claude-autopilot 5.2.0 → 5.2.2
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.
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
// src/cli/autoregress-bridge.ts
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
3
4
|
import { spawnSync } from 'node:child_process';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { findPackageRoot } from "./_pkg-root.js";
|
|
6
|
+
// Resolve autoregress.ts via the canonical package root walker — works under
|
|
7
|
+
// both source (src/cli/...) and compiled (dist/src/cli/...) layouts. The prior
|
|
8
|
+
// `path.resolve(__dirname, '../../scripts/autoregress.ts')` worked from source
|
|
9
|
+
// but resolved to `dist/scripts/autoregress.ts` under the compiled layout (the
|
|
10
|
+
// shipped scripts/ lives at the package root, not under dist/), so global
|
|
11
|
+
// installs got ERR_MODULE_NOT_FOUND on every `claude-autopilot autoregress`.
|
|
12
|
+
function resolveScript() {
|
|
13
|
+
const root = findPackageRoot(import.meta.url);
|
|
14
|
+
if (root) {
|
|
15
|
+
const p = path.join(root, 'scripts', 'autoregress.ts');
|
|
16
|
+
if (fs.existsSync(p))
|
|
17
|
+
return p;
|
|
18
|
+
}
|
|
19
|
+
// Last-resort fallback for non-standard layouts (linked dev installs, etc.)
|
|
20
|
+
return 'scripts/autoregress.ts';
|
|
21
|
+
}
|
|
7
22
|
const VALID_MODES = ['run', 'update', 'generate', 'diff'];
|
|
8
23
|
export function buildAutoregressArgs(args) {
|
|
9
24
|
const mode = args[0] && VALID_MODES.includes(args[0]) ? args[0] : 'run';
|
|
@@ -12,10 +27,11 @@ export function buildAutoregressArgs(args) {
|
|
|
12
27
|
}
|
|
13
28
|
export function runAutoregress(args) {
|
|
14
29
|
const resolvedArgs = buildAutoregressArgs(args);
|
|
15
|
-
const
|
|
30
|
+
const script = resolveScript();
|
|
31
|
+
const result = spawnSync(process.execPath, ['--import', 'tsx', script, ...resolvedArgs], { stdio: 'inherit', cwd: process.cwd() });
|
|
16
32
|
if (result.error) {
|
|
17
33
|
console.error(`[autoregress] failed to launch: ${result.error.message}`);
|
|
18
|
-
console.error(` script: ${
|
|
34
|
+
console.error(` script: ${script}`);
|
|
19
35
|
return 1;
|
|
20
36
|
}
|
|
21
37
|
return result.status ?? 1;
|
package/dist/src/cli/costs.js
CHANGED
|
@@ -22,7 +22,8 @@ function fmtTokens(n) {
|
|
|
22
22
|
export async function runCosts(cwd = process.cwd()) {
|
|
23
23
|
const log = readCostLog(cwd);
|
|
24
24
|
if (log.length === 0) {
|
|
25
|
-
console.log(fmt('yellow',
|
|
25
|
+
console.log(fmt('yellow', `[costs] No run history found in ${cwd} — run \`guardrail run\` first.`));
|
|
26
|
+
console.log(fmt('dim', ` (Costs are scoped per-project. \`cd\` to the project before checking.)`));
|
|
26
27
|
return 0;
|
|
27
28
|
}
|
|
28
29
|
// 7-day window
|
|
@@ -33,12 +34,13 @@ export async function runCosts(cwd = process.cwd()) {
|
|
|
33
34
|
const totalInput = log.reduce((s, e) => s + e.inputTokens, 0);
|
|
34
35
|
const totalOutput = log.reduce((s, e) => s + e.outputTokens, 0);
|
|
35
36
|
const recentCost = recent.reduce((s, e) => s + e.costUSD, 0);
|
|
36
|
-
console.log(`\n${fmt('bold', '[costs]')}\n`);
|
|
37
|
+
console.log(`\n${fmt('bold', '[costs]')} ${fmt('dim', cwd)}\n`);
|
|
37
38
|
// Summary row
|
|
38
39
|
console.log(fmt('bold', 'Summary'));
|
|
39
40
|
console.log(` All-time runs: ${log.length}`);
|
|
40
41
|
console.log(` All-time cost: ${fmtUSD(totalCost)} (${fmtTokens(totalInput)} in / ${fmtTokens(totalOutput)} out)`);
|
|
41
42
|
console.log(` Last 7 days: ${fmtUSD(recentCost)} (${recent.length} run${recent.length !== 1 ? 's' : ''})`);
|
|
43
|
+
console.log(fmt('dim', ` (per-project — scoped to ${cwd}/.guardrail-cache/costs.jsonl)`));
|
|
42
44
|
console.log('');
|
|
43
45
|
// Last 10 runs table
|
|
44
46
|
console.log(fmt('bold', `Recent runs (last ${last10.length})`));
|
package/dist/src/cli/pr.js
CHANGED
|
@@ -25,9 +25,15 @@ function gitFetch(remote, ref, cwd) {
|
|
|
25
25
|
export async function runPr(options = {}) {
|
|
26
26
|
const cwd = options.cwd ?? process.cwd();
|
|
27
27
|
const configPath = options.configPath ?? path.join(cwd, 'guardrail.config.yaml');
|
|
28
|
+
// 5.2.2 — pr previously hard-failed when guardrail.config.yaml was missing
|
|
29
|
+
// ("not found at <path>"). The first-run UX surprised users running
|
|
30
|
+
// `claude-autopilot pr <n>` on a fresh repo: setup hadn't been invoked, and
|
|
31
|
+
// the error didn't say to invoke it. Now matches `run`'s behavior — defer
|
|
32
|
+
// config-loading to the underlying runCommand, which auto-detects stack +
|
|
33
|
+
// testCommand when the file is missing.
|
|
28
34
|
if (!fs.existsSync(configPath)) {
|
|
29
|
-
console.
|
|
30
|
-
|
|
35
|
+
console.log(fmt('dim', `[pr] guardrail.config.yaml not found — auto-detecting from stack signals.`));
|
|
36
|
+
console.log(fmt('dim', ` Run \`claude-autopilot setup\` first to commit a config.`));
|
|
31
37
|
}
|
|
32
38
|
// Resolve PR number
|
|
33
39
|
let prNumber = options.prNumber;
|
|
@@ -3,6 +3,14 @@ import * as path from 'node:path';
|
|
|
3
3
|
const CACHE_DIR = '.guardrail-cache';
|
|
4
4
|
const LOG_FILE = 'costs.jsonl';
|
|
5
5
|
export function appendCostLog(cwd, entry) {
|
|
6
|
+
// Skip no-op entries that only pollute the report — runs that didn't
|
|
7
|
+
// actually invoke an LLM (dry-runs, no-findings paths, "no code files at
|
|
8
|
+
// path" early returns). Without this filter, randai's costs.jsonl picked up
|
|
9
|
+
// 6 zero-token zero-duration entries from setup-flow scans, drowning the
|
|
10
|
+
// 4 real review entries in `claude-autopilot costs` output.
|
|
11
|
+
if (entry.inputTokens === 0 && entry.outputTokens === 0 && entry.costUSD === 0) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
6
14
|
// Cost log is observability, not a contract. A failed write (read-only FS,
|
|
7
15
|
// full disk, permission error) must NEVER block the caller — every callsite
|
|
8
16
|
// calls this *after* its primary output is emitted, and a throw here would
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
// Detects a Python venv next to the project and prepends its bin/ to PATH so
|
|
5
|
+
// commands like `pytest -q` resolve to the venv's binary instead of failing
|
|
6
|
+
// with "command not found" or hitting an unrelated system Python. Surfaced by
|
|
7
|
+
// the 5.0.8 e2e test on randai-johnson — claude-autopilot pr ran the test
|
|
8
|
+
// command from PATH and reported "tests failed" even though the venv-installed
|
|
9
|
+
// pytest passed cleanly.
|
|
10
|
+
function venvAwareEnv(cwd) {
|
|
11
|
+
const root = cwd ?? process.cwd();
|
|
12
|
+
for (const candidate of ['.venv', 'venv', 'env']) {
|
|
13
|
+
const binDir = path.join(root, candidate, 'bin');
|
|
14
|
+
if (fs.existsSync(path.join(binDir, 'python')) || fs.existsSync(path.join(binDir, 'python3'))) {
|
|
15
|
+
return { ...process.env, PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ''}` };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return process.env;
|
|
19
|
+
}
|
|
2
20
|
export async function runTestsPhase(input) {
|
|
3
21
|
const start = Date.now();
|
|
4
22
|
if (!input.testCommand) {
|
|
@@ -13,6 +31,7 @@ export async function runTestsPhase(input) {
|
|
|
13
31
|
timeout: 120000,
|
|
14
32
|
shell: process.env.SHELL ?? "/bin/sh",
|
|
15
33
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
34
|
+
env: venvAwareEnv(input.cwd),
|
|
16
35
|
});
|
|
17
36
|
}
|
|
18
37
|
catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delegance/claude-autopilot",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Autonomous development pipeline for Claude Code: brainstorm → spec → plan → implement → migrate → validate → PR → review → merge. Multi-model, local-first, every phase a skill you can intervene in.",
|
|
6
6
|
"keywords": [
|
|
@@ -22,3 +22,14 @@ chunking:
|
|
|
22
22
|
pipeline:
|
|
23
23
|
runReviewOnStaticFail: true
|
|
24
24
|
runReviewOnTestFail: true
|
|
25
|
+
# Optional: multi-model council. Uncomment + set ANTHROPIC_API_KEY and/or
|
|
26
|
+
# OPENAI_API_KEY. Both APIs supported — chat-completions and Responses API
|
|
27
|
+
# for codex/o-series models (auto-detected by name).
|
|
28
|
+
# Usage: claude-autopilot council --prompt "..." --context-file <path>
|
|
29
|
+
# council:
|
|
30
|
+
# models:
|
|
31
|
+
# - { adapter: claude, model: claude-opus-4-7, label: opus }
|
|
32
|
+
# - { adapter: openai, model: gpt-5.3-codex, label: codex }
|
|
33
|
+
# synthesizer: { adapter: claude, model: claude-sonnet-4-6, label: synth }
|
|
34
|
+
# timeout_ms: 30000
|
|
35
|
+
# min_successful_responses: 1
|