@ai-sdlc/orchestrator 0.5.0 → 0.9.0
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/action-enforcement.d.ts +26 -0
- package/dist/action-enforcement.js +70 -0
- package/dist/admission-composite.d.ts +67 -0
- package/dist/admission-composite.js +158 -0
- package/dist/admission-enrichment.d.ts +142 -0
- package/dist/admission-enrichment.js +331 -0
- package/dist/admission-hc.d.ts +62 -0
- package/dist/admission-hc.js +83 -0
- package/dist/admission-score.d.ts +148 -0
- package/dist/admission-score.js +237 -0
- package/dist/analysis/analyzer.js +3 -2
- package/dist/analysis/convention-detector.d.ts +85 -2
- package/dist/analysis/convention-detector.js +375 -70
- package/dist/analysis/diff-analyzer.d.ts +33 -0
- package/dist/analysis/diff-analyzer.js +122 -0
- package/dist/analysis/hotspot-analyzer.js +3 -1
- package/dist/analysis/index.d.ts +2 -1
- package/dist/analysis/index.js +2 -1
- package/dist/artifacts/index.d.ts +65 -0
- package/dist/artifacts/index.js +142 -0
- package/dist/backlog-adapter.d.ts +121 -0
- package/dist/backlog-adapter.js +438 -0
- package/dist/calibration.d.ts +43 -0
- package/dist/calibration.js +76 -0
- package/dist/cli/commands/agents.d.ts +24 -0
- package/dist/cli/commands/agents.js +66 -1
- package/dist/cli/commands/git-remote.d.ts +49 -0
- package/dist/cli/commands/git-remote.js +91 -0
- package/dist/cli/commands/health.d.ts +4 -0
- package/dist/cli/commands/health.js +13 -1
- package/dist/cli/commands/init.d.ts +26 -0
- package/dist/cli/commands/init.js +164 -22
- package/dist/cli/commands/mcp-setup.d.ts +31 -0
- package/dist/cli/commands/mcp-setup.js +78 -8
- package/dist/cli/formatters/table.js +15 -2
- package/dist/cli/index.d.ts +14 -1
- package/dist/cli/index.js +81 -20
- package/dist/cli/versions.d.ts +57 -0
- package/dist/cli/versions.js +128 -0
- package/dist/code-area-classifier.d.ts +21 -0
- package/dist/code-area-classifier.js +48 -0
- package/dist/config.d.ts +33 -1
- package/dist/config.js +78 -8
- package/dist/cycle-utils.d.ts +51 -0
- package/dist/cycle-utils.js +77 -0
- package/dist/database/adapters/external.d.ts +24 -0
- package/dist/database/adapters/external.js +80 -0
- package/dist/database/adapters/neon.d.ts +41 -0
- package/dist/database/adapters/neon.js +98 -0
- package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
- package/dist/database/adapters/pg-snapshot-restore.js +68 -0
- package/dist/database/adapters/sqlite-copy.d.ts +32 -0
- package/dist/database/adapters/sqlite-copy.js +145 -0
- package/dist/database/connection-injection.d.ts +35 -0
- package/dist/database/connection-injection.js +93 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.js +23 -0
- package/dist/database/registry.d.ts +13 -0
- package/dist/database/registry.js +27 -0
- package/dist/database/topology.d.ts +52 -0
- package/dist/database/topology.js +44 -0
- package/dist/database/types.d.ts +89 -0
- package/dist/database/types.js +26 -0
- package/dist/defaults.d.ts +5 -0
- package/dist/defaults.js +5 -0
- package/dist/design-authority.d.ts +40 -0
- package/dist/design-authority.js +71 -0
- package/dist/design-lookahead.d.ts +64 -0
- package/dist/design-lookahead.js +86 -0
- package/dist/design-quality-trend.d.ts +87 -0
- package/dist/design-quality-trend.js +190 -0
- package/dist/design-system-context.d.ts +46 -0
- package/dist/design-system-context.js +80 -0
- package/dist/design-system-correction-loop.d.ts +64 -0
- package/dist/design-system-correction-loop.js +128 -0
- package/dist/design-system-metrics.d.ts +61 -0
- package/dist/design-system-metrics.js +104 -0
- package/dist/design-system-stewardship.d.ts +22 -0
- package/dist/design-system-stewardship.js +85 -0
- package/dist/design-system-validation.d.ts +37 -0
- package/dist/design-system-validation.js +88 -0
- package/dist/dispatch/index.d.ts +4 -0
- package/dist/dispatch/index.js +4 -0
- package/dist/dispatch/merge-gate.d.ts +46 -0
- package/dist/dispatch/merge-gate.js +90 -0
- package/dist/dispatch/requeue.d.ts +57 -0
- package/dist/dispatch/requeue.js +131 -0
- package/dist/dispatch/worker-pool.d.ts +62 -0
- package/dist/dispatch/worker-pool.js +60 -0
- package/dist/execute.d.ts +40 -0
- package/dist/execute.js +295 -30
- package/dist/fix-ci.js +40 -3
- package/dist/fix-review.d.ts +66 -0
- package/dist/fix-review.js +448 -0
- package/dist/harness/adapters/claude-code.d.ts +29 -0
- package/dist/harness/adapters/claude-code.js +191 -0
- package/dist/harness/adapters/codex.d.ts +25 -0
- package/dist/harness/adapters/codex.js +61 -0
- package/dist/harness/independence.d.ts +51 -0
- package/dist/harness/independence.js +67 -0
- package/dist/harness/index.d.ts +14 -0
- package/dist/harness/index.js +20 -0
- package/dist/harness/registry.d.ts +17 -0
- package/dist/harness/registry.js +31 -0
- package/dist/harness/types.d.ts +123 -0
- package/dist/harness/types.js +8 -0
- package/dist/harness/version-probe.d.ts +14 -0
- package/dist/harness/version-probe.js +123 -0
- package/dist/index.d.ts +39 -5
- package/dist/index.js +48 -3
- package/dist/models/classifier.d.ts +76 -0
- package/dist/models/classifier.js +221 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/registry.d.ts +97 -0
- package/dist/models/registry.js +173 -0
- package/dist/pillar-breakdown.d.ts +63 -0
- package/dist/pillar-breakdown.js +153 -0
- package/dist/pipeline-cycle-detector.d.ts +70 -0
- package/dist/pipeline-cycle-detector.js +111 -0
- package/dist/priority.d.ts +7 -76
- package/dist/priority.js +18 -5
- package/dist/review-meta.d.ts +65 -0
- package/dist/review-meta.js +149 -0
- package/dist/review.d.ts +35 -0
- package/dist/review.js +84 -0
- package/dist/runners/claude-code-sdk.d.ts +31 -0
- package/dist/runners/claude-code-sdk.js +238 -0
- package/dist/runners/claude-code.d.ts +3 -0
- package/dist/runners/claude-code.js +319 -73
- package/dist/runners/codex.js +4 -1
- package/dist/runners/copilot.js +4 -1
- package/dist/runners/cursor.js +4 -1
- package/dist/runners/git-utils.d.ts +81 -0
- package/dist/runners/git-utils.js +201 -0
- package/dist/runners/index.d.ts +5 -1
- package/dist/runners/index.js +4 -0
- package/dist/runners/review-agent.d.ts +67 -0
- package/dist/runners/review-agent.js +350 -0
- package/dist/runners/runner-registry.js +10 -0
- package/dist/runners/sdk-review-runner.d.ts +65 -0
- package/dist/runners/sdk-review-runner.js +185 -0
- package/dist/runners/security-triage.d.ts +20 -4
- package/dist/runners/security-triage.js +42 -14
- package/dist/runners/types.d.ts +25 -0
- package/dist/runtime/attestations.d.ts +274 -0
- package/dist/runtime/attestations.js +460 -0
- package/dist/runtime/git-env.d.ts +53 -0
- package/dist/runtime/git-env.js +60 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/parallelism-flag.d.ts +10 -0
- package/dist/runtime/parallelism-flag.js +18 -0
- package/dist/runtime/port-allocator.d.ts +21 -0
- package/dist/runtime/port-allocator.js +66 -0
- package/dist/runtime/worktree-pool.d.ts +86 -0
- package/dist/runtime/worktree-pool.js +204 -0
- package/dist/runtime/worktree.d.ts +25 -0
- package/dist/runtime/worktree.js +111 -0
- package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
- package/dist/sa-scoring/auto-calibrate.js +107 -0
- package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
- package/dist/sa-scoring/c1-sa2-computable.js +59 -0
- package/dist/sa-scoring/composite.d.ts +107 -0
- package/dist/sa-scoring/composite.js +139 -0
- package/dist/sa-scoring/depparse-client.d.ts +79 -0
- package/dist/sa-scoring/depparse-client.js +187 -0
- package/dist/sa-scoring/did-compiler.d.ts +122 -0
- package/dist/sa-scoring/did-compiler.js +286 -0
- package/dist/sa-scoring/drift-monitor.d.ts +84 -0
- package/dist/sa-scoring/drift-monitor.js +186 -0
- package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
- package/dist/sa-scoring/exemplar-bank.js +154 -0
- package/dist/sa-scoring/feedback-store.d.ts +100 -0
- package/dist/sa-scoring/feedback-store.js +156 -0
- package/dist/sa-scoring/index.d.ts +71 -0
- package/dist/sa-scoring/index.js +158 -0
- package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
- package/dist/sa-scoring/layer1-deterministic.js +298 -0
- package/dist/sa-scoring/layer2-structural.d.ts +71 -0
- package/dist/sa-scoring/layer2-structural.js +151 -0
- package/dist/sa-scoring/layer3-llm.d.ts +86 -0
- package/dist/sa-scoring/layer3-llm.js +282 -0
- package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
- package/dist/sa-scoring/rescore-orchestrator.js +47 -0
- package/dist/scheduling/burn-down.d.ts +27 -0
- package/dist/scheduling/burn-down.js +43 -0
- package/dist/scheduling/calibration.d.ts +42 -0
- package/dist/scheduling/calibration.js +150 -0
- package/dist/scheduling/index.d.ts +8 -0
- package/dist/scheduling/index.js +8 -0
- package/dist/scheduling/ledger.d.ts +59 -0
- package/dist/scheduling/ledger.js +216 -0
- package/dist/scheduling/off-peak.d.ts +27 -0
- package/dist/scheduling/off-peak.js +112 -0
- package/dist/scheduling/schedule-decision.d.ts +39 -0
- package/dist/scheduling/schedule-decision.js +89 -0
- package/dist/scheduling/tier-analysis.d.ts +47 -0
- package/dist/scheduling/tier-analysis.js +81 -0
- package/dist/scheduling/types.d.ts +140 -0
- package/dist/scheduling/types.js +11 -0
- package/dist/shared.d.ts +13 -0
- package/dist/shared.js +32 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/state/schema.d.ts +6 -1
- package/dist/state/schema.js +276 -1
- package/dist/state/store.d.ts +71 -1
- package/dist/state/store.js +464 -7
- package/dist/state/types.d.ts +174 -0
- package/dist/types.d.ts +1 -1
- package/dist/validate-agent-output.js +4 -1
- package/dist/watch.js +6 -0
- package/dist/workflow-patterns/artifact-writer.d.ts +16 -0
- package/dist/workflow-patterns/artifact-writer.js +34 -0
- package/dist/workflow-patterns/classifiers.d.ts +10 -0
- package/dist/workflow-patterns/classifiers.js +72 -0
- package/dist/workflow-patterns/detector.d.ts +27 -0
- package/dist/workflow-patterns/detector.js +186 -0
- package/dist/workflow-patterns/index.d.ts +8 -0
- package/dist/workflow-patterns/index.js +7 -0
- package/dist/workflow-patterns/proposal-generator.d.ts +15 -0
- package/dist/workflow-patterns/proposal-generator.js +183 -0
- package/dist/workflow-patterns/telemetry-ingest.d.ts +27 -0
- package/dist/workflow-patterns/telemetry-ingest.js +103 -0
- package/dist/workflow-patterns/types.d.ts +61 -0
- package/dist/workflow-patterns/types.js +11 -0
- package/package.json +2 -2
package/dist/priority.js
CHANGED
|
@@ -132,10 +132,23 @@ function computeHumanCurve(input, weights) {
|
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
134
|
* Cκ — Calibration Coefficient [0.7, 1.3].
|
|
135
|
-
*
|
|
135
|
+
*
|
|
136
|
+
* Category-scoped (RFC-0008 §10 Amendment 6) when `categoryResolver`
|
|
137
|
+
* and `categoryCoefficients` are both present: resolver returns a
|
|
138
|
+
* category label, coefficient is looked up, scalar fallback applies
|
|
139
|
+
* when the category has no entry. Otherwise uses the scalar path
|
|
140
|
+
* unchanged.
|
|
136
141
|
*/
|
|
137
|
-
function computeCalibration(config) {
|
|
138
|
-
|
|
142
|
+
function computeCalibration(input, config) {
|
|
143
|
+
let coeff = config?.calibrationCoefficient ?? 1.0;
|
|
144
|
+
const resolver = config?.categoryResolver;
|
|
145
|
+
const table = config?.categoryCoefficients;
|
|
146
|
+
if (resolver && table) {
|
|
147
|
+
const category = resolver(input);
|
|
148
|
+
if (category && table[category] !== undefined) {
|
|
149
|
+
coeff = table[category];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
139
152
|
return clamp(coeff, CALIBRATION_MIN, CALIBRATION_MAX);
|
|
140
153
|
}
|
|
141
154
|
// ── Confidence ──────────────────────────────────────────────────────
|
|
@@ -143,7 +156,7 @@ function computeCalibration(config) {
|
|
|
143
156
|
* Compute a confidence score [0, 1] based on the fraction of optional
|
|
144
157
|
* input fields that were explicitly provided (not defaulted).
|
|
145
158
|
*/
|
|
146
|
-
function computeConfidence(input) {
|
|
159
|
+
export function computeConfidence(input) {
|
|
147
160
|
let provided = 0;
|
|
148
161
|
for (const field of SCORABLE_FIELDS) {
|
|
149
162
|
if (input[field] !== undefined) {
|
|
@@ -194,7 +207,7 @@ export function computePriority(input, config) {
|
|
|
194
207
|
const executionReality = computeExecutionReality(input);
|
|
195
208
|
const entropyTax = computeEntropyTax(input);
|
|
196
209
|
const humanCurve = computeHumanCurve(input, hcWeights);
|
|
197
|
-
const calibration = computeCalibration(config);
|
|
210
|
+
const calibration = computeCalibration(input, config);
|
|
198
211
|
// ── Composite ─────────────────────────────────────────────────
|
|
199
212
|
const composite = soulAlignment *
|
|
200
213
|
demandPressure *
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta-review pass — filters medium-confidence findings through a
|
|
3
|
+
* lightweight LLM call (Haiku) to reduce false positives.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* High confidence (>0.8) → post directly
|
|
7
|
+
* Medium (0.5-0.8) → meta-review decides keep/drop
|
|
8
|
+
* Low (<0.5) → already suppressed by parseVerdict()
|
|
9
|
+
*/
|
|
10
|
+
import type { ReviewVerdict, ReviewFinding } from './runners/review-agent.js';
|
|
11
|
+
export interface MetaReviewDecision {
|
|
12
|
+
keep: boolean;
|
|
13
|
+
adjustedSeverity?: ReviewFinding['severity'];
|
|
14
|
+
reason: string;
|
|
15
|
+
}
|
|
16
|
+
export interface MetaReviewResult {
|
|
17
|
+
/** The filtered verdict with medium-confidence findings reviewed. */
|
|
18
|
+
verdict: ReviewVerdict;
|
|
19
|
+
/** Decisions for each medium-confidence finding. */
|
|
20
|
+
decisions: Array<{
|
|
21
|
+
finding: ReviewFinding;
|
|
22
|
+
decision: MetaReviewDecision;
|
|
23
|
+
}>;
|
|
24
|
+
/** Count of findings suppressed by meta-review. */
|
|
25
|
+
suppressed: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Run a meta-review pass on medium-confidence findings.
|
|
29
|
+
*
|
|
30
|
+
* @param verdict - The original verdict from a review agent
|
|
31
|
+
* @param principles - Review principles text for context
|
|
32
|
+
* @param callLLM - Function to make a single-turn LLM call (injectable for testing)
|
|
33
|
+
*/
|
|
34
|
+
export declare function metaReview(verdict: ReviewVerdict, principles: string, callLLM: (prompt: string) => Promise<string>): Promise<MetaReviewResult>;
|
|
35
|
+
export interface ReviewFeedback {
|
|
36
|
+
/** PR number. */
|
|
37
|
+
prNumber: number;
|
|
38
|
+
/** Finding that was posted. */
|
|
39
|
+
finding: ReviewFinding;
|
|
40
|
+
/** Human response. */
|
|
41
|
+
signal: 'accepted' | 'dismissed' | 'ignored';
|
|
42
|
+
/** Timestamp. */
|
|
43
|
+
timestamp: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Store for tracking human feedback on review findings.
|
|
47
|
+
* Used to calibrate confidence thresholds over time.
|
|
48
|
+
*/
|
|
49
|
+
export declare class ReviewFeedbackStore {
|
|
50
|
+
private entries;
|
|
51
|
+
record(feedback: ReviewFeedback): void;
|
|
52
|
+
/** Get all feedback entries. */
|
|
53
|
+
getAll(): ReviewFeedback[];
|
|
54
|
+
/** Get precision: accepted / (accepted + dismissed). */
|
|
55
|
+
precision(): number;
|
|
56
|
+
/** Get feedback by category. */
|
|
57
|
+
byCategory(): Record<string, {
|
|
58
|
+
accepted: number;
|
|
59
|
+
dismissed: number;
|
|
60
|
+
ignored: number;
|
|
61
|
+
}>;
|
|
62
|
+
/** Categories with high false-positive rate (dismissed > 50%). */
|
|
63
|
+
highFalsePositiveCategories(): string[];
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=review-meta.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta-review pass — filters medium-confidence findings through a
|
|
3
|
+
* lightweight LLM call (Haiku) to reduce false positives.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* High confidence (>0.8) → post directly
|
|
7
|
+
* Medium (0.5-0.8) → meta-review decides keep/drop
|
|
8
|
+
* Low (<0.5) → already suppressed by parseVerdict()
|
|
9
|
+
*/
|
|
10
|
+
// ── Thresholds ───────────────────────────────────────────────────────
|
|
11
|
+
const HIGH_CONFIDENCE = 0.8;
|
|
12
|
+
// ── Meta-reviewer ────────────────────────────────────────────────────
|
|
13
|
+
/**
|
|
14
|
+
* Run a meta-review pass on medium-confidence findings.
|
|
15
|
+
*
|
|
16
|
+
* @param verdict - The original verdict from a review agent
|
|
17
|
+
* @param principles - Review principles text for context
|
|
18
|
+
* @param callLLM - Function to make a single-turn LLM call (injectable for testing)
|
|
19
|
+
*/
|
|
20
|
+
export async function metaReview(verdict, principles, callLLM) {
|
|
21
|
+
const highConfidence = [];
|
|
22
|
+
const mediumConfidence = [];
|
|
23
|
+
for (const finding of verdict.findings) {
|
|
24
|
+
const conf = finding.confidence ?? 1.0; // legacy findings without confidence pass through
|
|
25
|
+
if (conf >= HIGH_CONFIDENCE) {
|
|
26
|
+
highConfidence.push(finding);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
mediumConfidence.push(finding);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// If no medium-confidence findings, return as-is
|
|
33
|
+
if (mediumConfidence.length === 0) {
|
|
34
|
+
return {
|
|
35
|
+
verdict,
|
|
36
|
+
decisions: [],
|
|
37
|
+
suppressed: 0,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// Review each medium-confidence finding
|
|
41
|
+
const decisions = [];
|
|
42
|
+
const kept = [...highConfidence];
|
|
43
|
+
for (const finding of mediumConfidence) {
|
|
44
|
+
try {
|
|
45
|
+
const decision = await reviewSingleFinding(finding, principles, callLLM);
|
|
46
|
+
decisions.push({ finding, decision });
|
|
47
|
+
if (decision.keep) {
|
|
48
|
+
kept.push({
|
|
49
|
+
...finding,
|
|
50
|
+
severity: decision.adjustedSeverity ?? finding.severity,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Meta-review failure = keep the finding (conservative)
|
|
56
|
+
kept.push(finding);
|
|
57
|
+
decisions.push({
|
|
58
|
+
finding,
|
|
59
|
+
decision: { keep: true, reason: 'Meta-review failed, keeping conservatively' },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
verdict: {
|
|
65
|
+
...verdict,
|
|
66
|
+
findings: kept,
|
|
67
|
+
// If all findings were suppressed, approve
|
|
68
|
+
approved: kept.length === 0 ? true : verdict.approved,
|
|
69
|
+
},
|
|
70
|
+
decisions,
|
|
71
|
+
suppressed: Math.max(0, mediumConfidence.length - (kept.length - highConfidence.length)),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function reviewSingleFinding(finding, principles, callLLM) {
|
|
75
|
+
const prompt = `You are a meta-reviewer evaluating whether a code review finding should be posted to a pull request.
|
|
76
|
+
|
|
77
|
+
## Review Principles
|
|
78
|
+
${principles}
|
|
79
|
+
|
|
80
|
+
## Finding to evaluate
|
|
81
|
+
- Severity: ${finding.severity}
|
|
82
|
+
- Confidence: ${finding.confidence}
|
|
83
|
+
- Category: ${finding.category ?? 'unknown'}
|
|
84
|
+
- File: ${finding.file ?? 'N/A'}
|
|
85
|
+
- Message: ${finding.message}
|
|
86
|
+
${finding.evidence?.failureScenario ? `- Failure scenario: ${finding.evidence.failureScenario}` : '- No failure scenario provided'}
|
|
87
|
+
${finding.evidence?.codePathTraced ? `- Code path: ${finding.evidence.codePathTraced}` : ''}
|
|
88
|
+
|
|
89
|
+
## Decision criteria
|
|
90
|
+
- Is this a real issue or noise?
|
|
91
|
+
- Does the evidence support the severity?
|
|
92
|
+
- Would a senior engineer flag this?
|
|
93
|
+
- Is this something CI already catches?
|
|
94
|
+
|
|
95
|
+
Respond with ONLY a JSON object:
|
|
96
|
+
{"keep": true/false, "adjustedSeverity": "critical|major|minor|suggestion" (optional), "reason": "brief explanation"}`;
|
|
97
|
+
const response = await callLLM(prompt);
|
|
98
|
+
// Parse response
|
|
99
|
+
const cleaned = response.replace(/^```(?:json)?\s*/m, '').replace(/\s*```$/m, '');
|
|
100
|
+
const parsed = JSON.parse(cleaned);
|
|
101
|
+
return {
|
|
102
|
+
keep: Boolean(parsed.keep),
|
|
103
|
+
adjustedSeverity: parsed.adjustedSeverity ?? undefined,
|
|
104
|
+
reason: String(parsed.reason ?? ''),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Store for tracking human feedback on review findings.
|
|
109
|
+
* Used to calibrate confidence thresholds over time.
|
|
110
|
+
*/
|
|
111
|
+
export class ReviewFeedbackStore {
|
|
112
|
+
entries = [];
|
|
113
|
+
record(feedback) {
|
|
114
|
+
this.entries.push(feedback);
|
|
115
|
+
}
|
|
116
|
+
/** Get all feedback entries. */
|
|
117
|
+
getAll() {
|
|
118
|
+
return [...this.entries];
|
|
119
|
+
}
|
|
120
|
+
/** Get precision: accepted / (accepted + dismissed). */
|
|
121
|
+
precision() {
|
|
122
|
+
const accepted = this.entries.filter((e) => e.signal === 'accepted').length;
|
|
123
|
+
const dismissed = this.entries.filter((e) => e.signal === 'dismissed').length;
|
|
124
|
+
const total = accepted + dismissed;
|
|
125
|
+
return total === 0 ? 1.0 : accepted / total;
|
|
126
|
+
}
|
|
127
|
+
/** Get feedback by category. */
|
|
128
|
+
byCategory() {
|
|
129
|
+
const result = {};
|
|
130
|
+
for (const entry of this.entries) {
|
|
131
|
+
const cat = entry.finding.category ?? 'other';
|
|
132
|
+
if (!result[cat])
|
|
133
|
+
result[cat] = { accepted: 0, dismissed: 0, ignored: 0 };
|
|
134
|
+
result[cat][entry.signal]++;
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
/** Categories with high false-positive rate (dismissed > 50%). */
|
|
139
|
+
highFalsePositiveCategories() {
|
|
140
|
+
const cats = this.byCategory();
|
|
141
|
+
return Object.entries(cats)
|
|
142
|
+
.filter(([, v]) => {
|
|
143
|
+
const total = v.accepted + v.dismissed;
|
|
144
|
+
return total >= 3 && v.dismissed / total > 0.5;
|
|
145
|
+
})
|
|
146
|
+
.map(([k]) => k);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=review-meta.js.map
|
package/dist/review.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR Review orchestrator — thin wrapper around ReviewAgentRunner
|
|
3
|
+
* that handles context assembly and verdict extraction.
|
|
4
|
+
*/
|
|
5
|
+
import { ReviewAgentRunner, type ReviewType, type ReviewVerdict, type ReviewAgentConfig } from './runners/review-agent.js';
|
|
6
|
+
import type { Logger } from './logger.js';
|
|
7
|
+
export interface ReviewContext {
|
|
8
|
+
issueTitle: string;
|
|
9
|
+
issueBody: string;
|
|
10
|
+
acceptanceCriteria?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ReviewOptions {
|
|
13
|
+
/** Anthropic API config overrides. */
|
|
14
|
+
apiConfig?: Omit<ReviewAgentConfig, 'reviewType'>;
|
|
15
|
+
/** Logger for diagnostic output. */
|
|
16
|
+
logger?: Logger;
|
|
17
|
+
/** Inject runner for testing. */
|
|
18
|
+
runner?: ReviewAgentRunner;
|
|
19
|
+
/** Review principles text for meta-review context. */
|
|
20
|
+
principles?: string;
|
|
21
|
+
/** LLM caller for meta-review pass. If provided, medium-confidence findings are filtered. */
|
|
22
|
+
metaReviewLLM?: (prompt: string) => Promise<string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Execute a single review agent against a PR diff.
|
|
26
|
+
*
|
|
27
|
+
* @param prNumber - PR number (for logging/identification)
|
|
28
|
+
* @param diff - The full PR diff text
|
|
29
|
+
* @param reviewType - Which review perspective (testing, critic, security)
|
|
30
|
+
* @param context - Issue context for the review
|
|
31
|
+
* @param options - Optional configuration overrides
|
|
32
|
+
* @returns Review verdict with findings
|
|
33
|
+
*/
|
|
34
|
+
export declare function executeReview(prNumber: number, diff: string, reviewType: ReviewType, context: ReviewContext, options?: ReviewOptions): Promise<ReviewVerdict>;
|
|
35
|
+
//# sourceMappingURL=review.d.ts.map
|
package/dist/review.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR Review orchestrator — thin wrapper around ReviewAgentRunner
|
|
3
|
+
* that handles context assembly and verdict extraction.
|
|
4
|
+
*/
|
|
5
|
+
import { ReviewAgentRunner, } from './runners/review-agent.js';
|
|
6
|
+
import { metaReview } from './review-meta.js';
|
|
7
|
+
// ── Public API ───────────────────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* Execute a single review agent against a PR diff.
|
|
10
|
+
*
|
|
11
|
+
* @param prNumber - PR number (for logging/identification)
|
|
12
|
+
* @param diff - The full PR diff text
|
|
13
|
+
* @param reviewType - Which review perspective (testing, critic, security)
|
|
14
|
+
* @param context - Issue context for the review
|
|
15
|
+
* @param options - Optional configuration overrides
|
|
16
|
+
* @returns Review verdict with findings
|
|
17
|
+
*/
|
|
18
|
+
export async function executeReview(prNumber, diff, reviewType, context, options) {
|
|
19
|
+
const logger = options?.logger;
|
|
20
|
+
logger?.info?.(`Starting ${reviewType} review for PR #${prNumber}`);
|
|
21
|
+
const runner = options?.runner ??
|
|
22
|
+
new ReviewAgentRunner({
|
|
23
|
+
...options?.apiConfig,
|
|
24
|
+
reviewType,
|
|
25
|
+
});
|
|
26
|
+
const result = await runner.run({
|
|
27
|
+
issueId: `PR-${prNumber}`,
|
|
28
|
+
issueNumber: prNumber,
|
|
29
|
+
issueTitle: context.issueTitle,
|
|
30
|
+
issueBody: diff,
|
|
31
|
+
workDir: '',
|
|
32
|
+
branch: '',
|
|
33
|
+
constraints: {
|
|
34
|
+
maxFilesPerChange: 0,
|
|
35
|
+
requireTests: false,
|
|
36
|
+
blockedPaths: [],
|
|
37
|
+
},
|
|
38
|
+
// Reuse ciErrors field for acceptance criteria
|
|
39
|
+
ciErrors: context.acceptanceCriteria,
|
|
40
|
+
});
|
|
41
|
+
if (!result.success) {
|
|
42
|
+
logger?.error?.(`${reviewType} review failed: ${result.error}`);
|
|
43
|
+
return {
|
|
44
|
+
type: reviewType,
|
|
45
|
+
approved: false,
|
|
46
|
+
findings: [
|
|
47
|
+
{
|
|
48
|
+
severity: 'critical',
|
|
49
|
+
message: `Review agent failed: ${result.error ?? 'unknown error'}`,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
summary: `${reviewType} review could not be completed`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
let verdict = JSON.parse(result.summary);
|
|
57
|
+
verdict = { ...verdict, type: reviewType };
|
|
58
|
+
// Run meta-review on medium-confidence findings if LLM caller provided
|
|
59
|
+
if (options?.metaReviewLLM && options?.principles) {
|
|
60
|
+
const metaResult = await metaReview(verdict, options.principles, options.metaReviewLLM);
|
|
61
|
+
if (metaResult.suppressed > 0) {
|
|
62
|
+
logger?.info?.(`${reviewType} meta-review: ${metaResult.suppressed} finding(s) suppressed`);
|
|
63
|
+
}
|
|
64
|
+
verdict = metaResult.verdict;
|
|
65
|
+
}
|
|
66
|
+
logger?.info?.(`${reviewType} review complete: ${verdict.approved ? 'APPROVED' : 'CHANGES REQUESTED'} (${verdict.findings.length} findings)`);
|
|
67
|
+
return verdict;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
logger?.error?.(`Failed to parse ${reviewType} verdict from runner output`);
|
|
71
|
+
return {
|
|
72
|
+
type: reviewType,
|
|
73
|
+
approved: false,
|
|
74
|
+
findings: [
|
|
75
|
+
{
|
|
76
|
+
severity: 'critical',
|
|
77
|
+
message: 'Failed to parse review verdict from runner output',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
summary: `${reviewType} review verdict was not valid JSON`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code SDK runner — invokes Claude Code via the Agent SDK's query() API
|
|
3
|
+
* instead of spawning a CLI subprocess.
|
|
4
|
+
*
|
|
5
|
+
* Advantages over ClaudeCodeRunner:
|
|
6
|
+
* - maxBudgetUsd / maxTurns — hard limits enforced by the engine
|
|
7
|
+
* - allowedTools / disallowedTools — fine-grained tool filtering with glob patterns
|
|
8
|
+
* - appendSystemPrompt — inject governance without replacing Claude Code defaults
|
|
9
|
+
* - Structured NDJSON messages — no stdout parsing
|
|
10
|
+
*/
|
|
11
|
+
import type { AgentRunner, AgentContext, AgentResult } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Map agent-role tool names to SDK-compatible tool filter patterns.
|
|
14
|
+
*/
|
|
15
|
+
/** @internal Exported for testing. */
|
|
16
|
+
export declare function mapToolsToSdkFormat(allowedTools?: string[]): string[] | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Build tool deny-list from blocked actions.
|
|
19
|
+
* Converts blockedActions glob patterns to SDK disallowedTools format.
|
|
20
|
+
*/
|
|
21
|
+
/** @internal Exported for testing. */
|
|
22
|
+
export declare function mapBlockedActionsToSdkDenyList(blockedActions?: string[]): string[];
|
|
23
|
+
/**
|
|
24
|
+
* Build governance system prompt appendix from constraints.
|
|
25
|
+
*/
|
|
26
|
+
/** @internal Exported for testing. */
|
|
27
|
+
export declare function buildGovernancePrompt(ctx: AgentContext): string;
|
|
28
|
+
export declare class ClaudeCodeSdkRunner implements AgentRunner {
|
|
29
|
+
run(ctx: AgentContext): Promise<AgentResult>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=claude-code-sdk.d.ts.map
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code SDK runner — invokes Claude Code via the Agent SDK's query() API
|
|
3
|
+
* instead of spawning a CLI subprocess.
|
|
4
|
+
*
|
|
5
|
+
* Advantages over ClaudeCodeRunner:
|
|
6
|
+
* - maxBudgetUsd / maxTurns — hard limits enforced by the engine
|
|
7
|
+
* - allowedTools / disallowedTools — fine-grained tool filtering with glob patterns
|
|
8
|
+
* - appendSystemPrompt — inject governance without replacing Claude Code defaults
|
|
9
|
+
* - Structured NDJSON messages — no stdout parsing
|
|
10
|
+
*/
|
|
11
|
+
import { buildPrompt } from './claude-code.js';
|
|
12
|
+
import { detectChangedFiles, gitExec, runAutoFix, snapshotWorktree } from './git-utils.js';
|
|
13
|
+
import { DEFAULT_MODEL, DEFAULT_ALLOWED_TOOLS, DEFAULT_LINT_COMMAND, DEFAULT_FORMAT_COMMAND, DEFAULT_COMMIT_MESSAGE_TEMPLATE, DEFAULT_COMMIT_CO_AUTHOR, } from '../defaults.js';
|
|
14
|
+
/** Default budget cap per agent run. */
|
|
15
|
+
const DEFAULT_MAX_BUDGET_USD = 5.0;
|
|
16
|
+
/** Default turn limit per agent run. */
|
|
17
|
+
const DEFAULT_MAX_TURNS = 100;
|
|
18
|
+
/**
|
|
19
|
+
* Map agent-role tool names to SDK-compatible tool filter patterns.
|
|
20
|
+
*/
|
|
21
|
+
/** @internal Exported for testing. */
|
|
22
|
+
export function mapToolsToSdkFormat(allowedTools) {
|
|
23
|
+
if (!allowedTools)
|
|
24
|
+
return undefined;
|
|
25
|
+
// SDK accepts tool names directly or glob patterns like Bash(git:*)
|
|
26
|
+
return allowedTools;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build tool deny-list from blocked actions.
|
|
30
|
+
* Converts blockedActions glob patterns to SDK disallowedTools format.
|
|
31
|
+
*/
|
|
32
|
+
/** @internal Exported for testing. */
|
|
33
|
+
export function mapBlockedActionsToSdkDenyList(blockedActions) {
|
|
34
|
+
if (!blockedActions || blockedActions.length === 0)
|
|
35
|
+
return [];
|
|
36
|
+
// Map each blocked action pattern to a Bash() deny rule
|
|
37
|
+
return blockedActions.map((pattern) => `Bash(${pattern})`);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build governance system prompt appendix from constraints.
|
|
41
|
+
*/
|
|
42
|
+
/** @internal Exported for testing. */
|
|
43
|
+
export function buildGovernancePrompt(ctx) {
|
|
44
|
+
const lines = ['## AI-SDLC Governance Constraints\n'];
|
|
45
|
+
if (ctx.constraints.blockedPaths.length > 0) {
|
|
46
|
+
lines.push(`Blocked paths (do NOT modify): ${ctx.constraints.blockedPaths.join(', ')}`);
|
|
47
|
+
}
|
|
48
|
+
if (ctx.constraints.blockedActions && ctx.constraints.blockedActions.length > 0) {
|
|
49
|
+
lines.push(`Blocked actions (NEVER execute): ${ctx.constraints.blockedActions.map((a) => `\`${a}\``).join(', ')}`);
|
|
50
|
+
}
|
|
51
|
+
lines.push(`Max files per change: ${ctx.constraints.maxFilesPerChange}`);
|
|
52
|
+
if (ctx.constraints.requireTests) {
|
|
53
|
+
lines.push('Tests required: every new module must have tests.');
|
|
54
|
+
}
|
|
55
|
+
lines.push('');
|
|
56
|
+
lines.push('**NEVER merge PRs. Only humans merge.**');
|
|
57
|
+
return lines.join('\n');
|
|
58
|
+
}
|
|
59
|
+
export class ClaudeCodeSdkRunner {
|
|
60
|
+
async run(ctx) {
|
|
61
|
+
// Dynamic import — SDK is an optional peer dependency
|
|
62
|
+
let query;
|
|
63
|
+
/* v8 ignore start — dynamic import fails in unit tests (SDK not installed) */
|
|
64
|
+
try {
|
|
65
|
+
const sdk = await import('@anthropic-ai/claude-agent-sdk');
|
|
66
|
+
query = sdk.query;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
filesChanged: [],
|
|
72
|
+
summary: '',
|
|
73
|
+
error: '@anthropic-ai/claude-agent-sdk is not installed. Install it to use the SDK runner: pnpm add @anthropic-ai/claude-agent-sdk',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/* v8 ignore stop */
|
|
77
|
+
const prompt = buildPrompt(ctx);
|
|
78
|
+
const model = ctx.model ?? DEFAULT_MODEL;
|
|
79
|
+
const maxTurns = ctx.constraints.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
80
|
+
const maxBudgetUsd = ctx.constraints.maxBudgetUsd ?? DEFAULT_MAX_BUDGET_USD;
|
|
81
|
+
const allowedTools = mapToolsToSdkFormat(ctx.allowedTools ?? DEFAULT_ALLOWED_TOOLS.split(','));
|
|
82
|
+
const disallowedTools = mapBlockedActionsToSdkDenyList(ctx.constraints.blockedActions);
|
|
83
|
+
const governancePrompt = buildGovernancePrompt(ctx);
|
|
84
|
+
let summary = '';
|
|
85
|
+
let tokenUsage;
|
|
86
|
+
// Capture worktree state before invoking the agent so untracked noise
|
|
87
|
+
// doesn't get swept into the eventual `git add`.
|
|
88
|
+
const baseline = await snapshotWorktree(ctx.workDir);
|
|
89
|
+
/* v8 ignore start — SDK streaming loop requires real SDK connection */
|
|
90
|
+
try {
|
|
91
|
+
const result = query({
|
|
92
|
+
prompt,
|
|
93
|
+
options: {
|
|
94
|
+
model,
|
|
95
|
+
maxTurns,
|
|
96
|
+
maxBudgetUsd,
|
|
97
|
+
appendSystemPrompt: governancePrompt,
|
|
98
|
+
allowedTools,
|
|
99
|
+
disallowedTools: disallowedTools.length > 0 ? disallowedTools : undefined,
|
|
100
|
+
permissionMode: 'acceptEdits',
|
|
101
|
+
cwd: ctx.workDir,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
for await (const msg of result) {
|
|
105
|
+
const msgType = msg.type;
|
|
106
|
+
// Emit progress events
|
|
107
|
+
if (msgType === 'assistant' && ctx.onProgress) {
|
|
108
|
+
const blocks = msg.message?.content;
|
|
109
|
+
if (blocks) {
|
|
110
|
+
for (const block of blocks) {
|
|
111
|
+
if (block.type === 'tool_use') {
|
|
112
|
+
ctx.onProgress({
|
|
113
|
+
type: 'tool_start',
|
|
114
|
+
tool: block.name,
|
|
115
|
+
message: `${block.name}`,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else if (block.type === 'text') {
|
|
119
|
+
summary = (block.text ?? '').slice(0, 2000);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Parse result event for token usage and cost
|
|
125
|
+
if (msgType === 'result') {
|
|
126
|
+
const usage = msg.usage;
|
|
127
|
+
const resultModel = msg.model ?? model;
|
|
128
|
+
if (usage) {
|
|
129
|
+
tokenUsage = {
|
|
130
|
+
inputTokens: usage.input_tokens ?? 0,
|
|
131
|
+
outputTokens: usage.output_tokens ?? 0,
|
|
132
|
+
cacheReadTokens: usage.cache_read_input_tokens,
|
|
133
|
+
model: resultModel,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (ctx.onProgress) {
|
|
137
|
+
ctx.onProgress({
|
|
138
|
+
type: 'cost',
|
|
139
|
+
costUsd: msg.cost_usd,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Check exit reason
|
|
143
|
+
const subtype = msg.subtype;
|
|
144
|
+
if (subtype === 'error_max_turns') {
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
filesChanged: [],
|
|
148
|
+
summary: `Agent hit turn limit (${maxTurns})`,
|
|
149
|
+
error: `Max turns (${maxTurns}) exceeded`,
|
|
150
|
+
tokenUsage,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (subtype === 'error_max_budget_usd') {
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
filesChanged: [],
|
|
157
|
+
summary: `Agent hit budget limit ($${maxBudgetUsd})`,
|
|
158
|
+
error: `Max budget ($${maxBudgetUsd}) exceeded`,
|
|
159
|
+
tokenUsage,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
return {
|
|
167
|
+
success: false,
|
|
168
|
+
filesChanged: [],
|
|
169
|
+
summary: '',
|
|
170
|
+
error: `SDK runner error: ${err.message}`,
|
|
171
|
+
tokenUsage,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/* v8 ignore stop */
|
|
175
|
+
/* v8 ignore start — post-SDK commit/lint logic only runs when SDK succeeds */
|
|
176
|
+
// Detect changed files (same logic as ClaudeCodeRunner), excluding any
|
|
177
|
+
// untracked noise that pre-existed the agent invocation.
|
|
178
|
+
const { filesChanged, agentAlreadyCommitted } = await detectChangedFiles(ctx.workDir, baseline);
|
|
179
|
+
if (filesChanged.length === 0) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
filesChanged: [],
|
|
183
|
+
summary: 'Agent made no changes',
|
|
184
|
+
error: 'No files were modified',
|
|
185
|
+
tokenUsage,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (agentAlreadyCommitted) {
|
|
189
|
+
return {
|
|
190
|
+
success: true,
|
|
191
|
+
filesChanged,
|
|
192
|
+
summary,
|
|
193
|
+
tokenUsage,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Stage only the files the agent touched (NOT `git add -A` — the
|
|
197
|
+
// AISDLC-68 incident showed `add -A` sweeps in pre-existing untracked
|
|
198
|
+
// noise like sqlite working files and unrelated draft files).
|
|
199
|
+
await gitExec(ctx.workDir, ['add', '--', ...filesChanged]);
|
|
200
|
+
const lintCmd = ctx.lintCommand ?? DEFAULT_LINT_COMMAND;
|
|
201
|
+
const fmtCmd = ctx.formatCommand ?? DEFAULT_FORMAT_COMMAND;
|
|
202
|
+
await runAutoFix(ctx.workDir, lintCmd, fmtCmd);
|
|
203
|
+
await gitExec(ctx.workDir, ['add', '--', ...filesChanged]);
|
|
204
|
+
const tmpl = ctx.commitMessageTemplate ?? DEFAULT_COMMIT_MESSAGE_TEMPLATE;
|
|
205
|
+
const coAuthor = ctx.commitCoAuthor ?? DEFAULT_COMMIT_CO_AUTHOR;
|
|
206
|
+
const commitMsg = tmpl
|
|
207
|
+
.replace(/\{issueNumber\}/g, ctx.issueId)
|
|
208
|
+
.replace(/\{issueTitle\}/g, ctx.issueTitle);
|
|
209
|
+
try {
|
|
210
|
+
await gitExec(ctx.workDir, ['commit', '-m', `${commitMsg}\n\nCo-Authored-By: ${coAuthor}`]);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Pre-commit hook failure — auto-fix and retry once
|
|
214
|
+
await runAutoFix(ctx.workDir, lintCmd, fmtCmd);
|
|
215
|
+
await gitExec(ctx.workDir, ['add', '--', ...filesChanged]);
|
|
216
|
+
try {
|
|
217
|
+
await gitExec(ctx.workDir, ['commit', '-m', `${commitMsg}\n\nCo-Authored-By: ${coAuthor}`]);
|
|
218
|
+
}
|
|
219
|
+
catch (retryErr) {
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
filesChanged,
|
|
223
|
+
summary,
|
|
224
|
+
error: `Commit failed after auto-fix retry: ${retryErr.message}`,
|
|
225
|
+
tokenUsage,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
success: true,
|
|
231
|
+
filesChanged,
|
|
232
|
+
summary,
|
|
233
|
+
tokenUsage,
|
|
234
|
+
};
|
|
235
|
+
/* v8 ignore stop */
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=claude-code-sdk.js.map
|
|
@@ -9,6 +9,9 @@ export declare function buildPrompt(ctx: AgentContext): string;
|
|
|
9
9
|
* Claude Code CLI outputs token info to stderr in various formats.
|
|
10
10
|
*/
|
|
11
11
|
export declare function parseTokenUsage(stderr: string, model: string): TokenUsage | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Run lint --fix and format commands (best-effort) so pre-commit hooks pass.
|
|
14
|
+
*/
|
|
12
15
|
export declare class ClaudeCodeRunner implements AgentRunner {
|
|
13
16
|
run(ctx: AgentContext): Promise<AgentResult>;
|
|
14
17
|
}
|