@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.
Files changed (227) hide show
  1. package/dist/action-enforcement.d.ts +26 -0
  2. package/dist/action-enforcement.js +70 -0
  3. package/dist/admission-composite.d.ts +67 -0
  4. package/dist/admission-composite.js +158 -0
  5. package/dist/admission-enrichment.d.ts +142 -0
  6. package/dist/admission-enrichment.js +331 -0
  7. package/dist/admission-hc.d.ts +62 -0
  8. package/dist/admission-hc.js +83 -0
  9. package/dist/admission-score.d.ts +148 -0
  10. package/dist/admission-score.js +237 -0
  11. package/dist/analysis/analyzer.js +3 -2
  12. package/dist/analysis/convention-detector.d.ts +85 -2
  13. package/dist/analysis/convention-detector.js +375 -70
  14. package/dist/analysis/diff-analyzer.d.ts +33 -0
  15. package/dist/analysis/diff-analyzer.js +122 -0
  16. package/dist/analysis/hotspot-analyzer.js +3 -1
  17. package/dist/analysis/index.d.ts +2 -1
  18. package/dist/analysis/index.js +2 -1
  19. package/dist/artifacts/index.d.ts +65 -0
  20. package/dist/artifacts/index.js +142 -0
  21. package/dist/backlog-adapter.d.ts +121 -0
  22. package/dist/backlog-adapter.js +438 -0
  23. package/dist/calibration.d.ts +43 -0
  24. package/dist/calibration.js +76 -0
  25. package/dist/cli/commands/agents.d.ts +24 -0
  26. package/dist/cli/commands/agents.js +66 -1
  27. package/dist/cli/commands/git-remote.d.ts +49 -0
  28. package/dist/cli/commands/git-remote.js +91 -0
  29. package/dist/cli/commands/health.d.ts +4 -0
  30. package/dist/cli/commands/health.js +13 -1
  31. package/dist/cli/commands/init.d.ts +26 -0
  32. package/dist/cli/commands/init.js +164 -22
  33. package/dist/cli/commands/mcp-setup.d.ts +31 -0
  34. package/dist/cli/commands/mcp-setup.js +78 -8
  35. package/dist/cli/formatters/table.js +15 -2
  36. package/dist/cli/index.d.ts +14 -1
  37. package/dist/cli/index.js +81 -20
  38. package/dist/cli/versions.d.ts +57 -0
  39. package/dist/cli/versions.js +128 -0
  40. package/dist/code-area-classifier.d.ts +21 -0
  41. package/dist/code-area-classifier.js +48 -0
  42. package/dist/config.d.ts +33 -1
  43. package/dist/config.js +78 -8
  44. package/dist/cycle-utils.d.ts +51 -0
  45. package/dist/cycle-utils.js +77 -0
  46. package/dist/database/adapters/external.d.ts +24 -0
  47. package/dist/database/adapters/external.js +80 -0
  48. package/dist/database/adapters/neon.d.ts +41 -0
  49. package/dist/database/adapters/neon.js +98 -0
  50. package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
  51. package/dist/database/adapters/pg-snapshot-restore.js +68 -0
  52. package/dist/database/adapters/sqlite-copy.d.ts +32 -0
  53. package/dist/database/adapters/sqlite-copy.js +145 -0
  54. package/dist/database/connection-injection.d.ts +35 -0
  55. package/dist/database/connection-injection.js +93 -0
  56. package/dist/database/index.d.ts +12 -0
  57. package/dist/database/index.js +23 -0
  58. package/dist/database/registry.d.ts +13 -0
  59. package/dist/database/registry.js +27 -0
  60. package/dist/database/topology.d.ts +52 -0
  61. package/dist/database/topology.js +44 -0
  62. package/dist/database/types.d.ts +89 -0
  63. package/dist/database/types.js +26 -0
  64. package/dist/defaults.d.ts +5 -0
  65. package/dist/defaults.js +5 -0
  66. package/dist/design-authority.d.ts +40 -0
  67. package/dist/design-authority.js +71 -0
  68. package/dist/design-lookahead.d.ts +64 -0
  69. package/dist/design-lookahead.js +86 -0
  70. package/dist/design-quality-trend.d.ts +87 -0
  71. package/dist/design-quality-trend.js +190 -0
  72. package/dist/design-system-context.d.ts +46 -0
  73. package/dist/design-system-context.js +80 -0
  74. package/dist/design-system-correction-loop.d.ts +64 -0
  75. package/dist/design-system-correction-loop.js +128 -0
  76. package/dist/design-system-metrics.d.ts +61 -0
  77. package/dist/design-system-metrics.js +104 -0
  78. package/dist/design-system-stewardship.d.ts +22 -0
  79. package/dist/design-system-stewardship.js +85 -0
  80. package/dist/design-system-validation.d.ts +37 -0
  81. package/dist/design-system-validation.js +88 -0
  82. package/dist/dispatch/index.d.ts +4 -0
  83. package/dist/dispatch/index.js +4 -0
  84. package/dist/dispatch/merge-gate.d.ts +46 -0
  85. package/dist/dispatch/merge-gate.js +90 -0
  86. package/dist/dispatch/requeue.d.ts +57 -0
  87. package/dist/dispatch/requeue.js +131 -0
  88. package/dist/dispatch/worker-pool.d.ts +62 -0
  89. package/dist/dispatch/worker-pool.js +60 -0
  90. package/dist/execute.d.ts +40 -0
  91. package/dist/execute.js +295 -30
  92. package/dist/fix-ci.js +40 -3
  93. package/dist/fix-review.d.ts +66 -0
  94. package/dist/fix-review.js +448 -0
  95. package/dist/harness/adapters/claude-code.d.ts +29 -0
  96. package/dist/harness/adapters/claude-code.js +191 -0
  97. package/dist/harness/adapters/codex.d.ts +25 -0
  98. package/dist/harness/adapters/codex.js +61 -0
  99. package/dist/harness/independence.d.ts +51 -0
  100. package/dist/harness/independence.js +67 -0
  101. package/dist/harness/index.d.ts +14 -0
  102. package/dist/harness/index.js +20 -0
  103. package/dist/harness/registry.d.ts +17 -0
  104. package/dist/harness/registry.js +31 -0
  105. package/dist/harness/types.d.ts +123 -0
  106. package/dist/harness/types.js +8 -0
  107. package/dist/harness/version-probe.d.ts +14 -0
  108. package/dist/harness/version-probe.js +123 -0
  109. package/dist/index.d.ts +39 -5
  110. package/dist/index.js +48 -3
  111. package/dist/models/classifier.d.ts +76 -0
  112. package/dist/models/classifier.js +221 -0
  113. package/dist/models/index.d.ts +3 -0
  114. package/dist/models/index.js +3 -0
  115. package/dist/models/registry.d.ts +97 -0
  116. package/dist/models/registry.js +173 -0
  117. package/dist/pillar-breakdown.d.ts +63 -0
  118. package/dist/pillar-breakdown.js +153 -0
  119. package/dist/pipeline-cycle-detector.d.ts +70 -0
  120. package/dist/pipeline-cycle-detector.js +111 -0
  121. package/dist/priority.d.ts +7 -76
  122. package/dist/priority.js +18 -5
  123. package/dist/review-meta.d.ts +65 -0
  124. package/dist/review-meta.js +149 -0
  125. package/dist/review.d.ts +35 -0
  126. package/dist/review.js +84 -0
  127. package/dist/runners/claude-code-sdk.d.ts +31 -0
  128. package/dist/runners/claude-code-sdk.js +238 -0
  129. package/dist/runners/claude-code.d.ts +3 -0
  130. package/dist/runners/claude-code.js +319 -73
  131. package/dist/runners/codex.js +4 -1
  132. package/dist/runners/copilot.js +4 -1
  133. package/dist/runners/cursor.js +4 -1
  134. package/dist/runners/git-utils.d.ts +81 -0
  135. package/dist/runners/git-utils.js +201 -0
  136. package/dist/runners/index.d.ts +5 -1
  137. package/dist/runners/index.js +4 -0
  138. package/dist/runners/review-agent.d.ts +67 -0
  139. package/dist/runners/review-agent.js +350 -0
  140. package/dist/runners/runner-registry.js +10 -0
  141. package/dist/runners/sdk-review-runner.d.ts +65 -0
  142. package/dist/runners/sdk-review-runner.js +185 -0
  143. package/dist/runners/security-triage.d.ts +20 -4
  144. package/dist/runners/security-triage.js +42 -14
  145. package/dist/runners/types.d.ts +25 -0
  146. package/dist/runtime/attestations.d.ts +274 -0
  147. package/dist/runtime/attestations.js +460 -0
  148. package/dist/runtime/git-env.d.ts +53 -0
  149. package/dist/runtime/git-env.js +60 -0
  150. package/dist/runtime/index.d.ts +7 -0
  151. package/dist/runtime/index.js +7 -0
  152. package/dist/runtime/parallelism-flag.d.ts +10 -0
  153. package/dist/runtime/parallelism-flag.js +18 -0
  154. package/dist/runtime/port-allocator.d.ts +21 -0
  155. package/dist/runtime/port-allocator.js +66 -0
  156. package/dist/runtime/worktree-pool.d.ts +86 -0
  157. package/dist/runtime/worktree-pool.js +204 -0
  158. package/dist/runtime/worktree.d.ts +25 -0
  159. package/dist/runtime/worktree.js +111 -0
  160. package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
  161. package/dist/sa-scoring/auto-calibrate.js +107 -0
  162. package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
  163. package/dist/sa-scoring/c1-sa2-computable.js +59 -0
  164. package/dist/sa-scoring/composite.d.ts +107 -0
  165. package/dist/sa-scoring/composite.js +139 -0
  166. package/dist/sa-scoring/depparse-client.d.ts +79 -0
  167. package/dist/sa-scoring/depparse-client.js +187 -0
  168. package/dist/sa-scoring/did-compiler.d.ts +122 -0
  169. package/dist/sa-scoring/did-compiler.js +286 -0
  170. package/dist/sa-scoring/drift-monitor.d.ts +84 -0
  171. package/dist/sa-scoring/drift-monitor.js +186 -0
  172. package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
  173. package/dist/sa-scoring/exemplar-bank.js +154 -0
  174. package/dist/sa-scoring/feedback-store.d.ts +100 -0
  175. package/dist/sa-scoring/feedback-store.js +156 -0
  176. package/dist/sa-scoring/index.d.ts +71 -0
  177. package/dist/sa-scoring/index.js +158 -0
  178. package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
  179. package/dist/sa-scoring/layer1-deterministic.js +298 -0
  180. package/dist/sa-scoring/layer2-structural.d.ts +71 -0
  181. package/dist/sa-scoring/layer2-structural.js +151 -0
  182. package/dist/sa-scoring/layer3-llm.d.ts +86 -0
  183. package/dist/sa-scoring/layer3-llm.js +282 -0
  184. package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
  185. package/dist/sa-scoring/rescore-orchestrator.js +47 -0
  186. package/dist/scheduling/burn-down.d.ts +27 -0
  187. package/dist/scheduling/burn-down.js +43 -0
  188. package/dist/scheduling/calibration.d.ts +42 -0
  189. package/dist/scheduling/calibration.js +150 -0
  190. package/dist/scheduling/index.d.ts +8 -0
  191. package/dist/scheduling/index.js +8 -0
  192. package/dist/scheduling/ledger.d.ts +59 -0
  193. package/dist/scheduling/ledger.js +216 -0
  194. package/dist/scheduling/off-peak.d.ts +27 -0
  195. package/dist/scheduling/off-peak.js +112 -0
  196. package/dist/scheduling/schedule-decision.d.ts +39 -0
  197. package/dist/scheduling/schedule-decision.js +89 -0
  198. package/dist/scheduling/tier-analysis.d.ts +47 -0
  199. package/dist/scheduling/tier-analysis.js +81 -0
  200. package/dist/scheduling/types.d.ts +140 -0
  201. package/dist/scheduling/types.js +11 -0
  202. package/dist/shared.d.ts +13 -0
  203. package/dist/shared.js +32 -0
  204. package/dist/state/index.d.ts +1 -1
  205. package/dist/state/schema.d.ts +6 -1
  206. package/dist/state/schema.js +276 -1
  207. package/dist/state/store.d.ts +71 -1
  208. package/dist/state/store.js +464 -7
  209. package/dist/state/types.d.ts +174 -0
  210. package/dist/types.d.ts +1 -1
  211. package/dist/validate-agent-output.js +4 -1
  212. package/dist/watch.js +6 -0
  213. package/dist/workflow-patterns/artifact-writer.d.ts +16 -0
  214. package/dist/workflow-patterns/artifact-writer.js +34 -0
  215. package/dist/workflow-patterns/classifiers.d.ts +10 -0
  216. package/dist/workflow-patterns/classifiers.js +72 -0
  217. package/dist/workflow-patterns/detector.d.ts +27 -0
  218. package/dist/workflow-patterns/detector.js +186 -0
  219. package/dist/workflow-patterns/index.d.ts +8 -0
  220. package/dist/workflow-patterns/index.js +7 -0
  221. package/dist/workflow-patterns/proposal-generator.d.ts +15 -0
  222. package/dist/workflow-patterns/proposal-generator.js +183 -0
  223. package/dist/workflow-patterns/telemetry-ingest.d.ts +27 -0
  224. package/dist/workflow-patterns/telemetry-ingest.js +103 -0
  225. package/dist/workflow-patterns/types.d.ts +61 -0
  226. package/dist/workflow-patterns/types.js +11 -0
  227. 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
- * A tuning knob that lets operators scale the final score up or down.
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
- const coeff = config?.calibrationCoefficient ?? 1.0;
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
@@ -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
  }