@ai-sdlc/orchestrator 0.4.0 → 0.6.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 (72) hide show
  1. package/dist/action-enforcement.d.ts +26 -0
  2. package/dist/action-enforcement.js +70 -0
  3. package/dist/adapters.d.ts +18 -3
  4. package/dist/adapters.js +92 -2
  5. package/dist/admission-score.d.ts +58 -0
  6. package/dist/admission-score.js +164 -0
  7. package/dist/cli/commands/init.js +4 -8
  8. package/dist/cli/commands/run.js +2 -2
  9. package/dist/config.d.ts +3 -0
  10. package/dist/config.js +14 -5
  11. package/dist/cycle-utils.d.ts +51 -0
  12. package/dist/cycle-utils.js +77 -0
  13. package/dist/defaults.d.ts +5 -0
  14. package/dist/defaults.js +5 -0
  15. package/dist/execute.d.ts +5 -2
  16. package/dist/execute.js +212 -62
  17. package/dist/fix-ci.js +45 -13
  18. package/dist/fix-review.d.ts +66 -0
  19. package/dist/fix-review.js +441 -0
  20. package/dist/index.d.ts +14 -4
  21. package/dist/index.js +18 -3
  22. package/dist/orchestrator.d.ts +1 -1
  23. package/dist/orchestrator.js +31 -9
  24. package/dist/pipeline-cycle-detector.d.ts +70 -0
  25. package/dist/pipeline-cycle-detector.js +111 -0
  26. package/dist/plugin.d.ts +9 -3
  27. package/dist/priority.d.ts +28 -0
  28. package/dist/priority.js +230 -0
  29. package/dist/review.d.ts +31 -0
  30. package/dist/review.js +74 -0
  31. package/dist/runners/claude-code.js +367 -35
  32. package/dist/runners/codex.js +15 -4
  33. package/dist/runners/copilot.js +15 -4
  34. package/dist/runners/cursor.js +15 -4
  35. package/dist/runners/generic-llm.js +1 -1
  36. package/dist/runners/index.d.ts +3 -1
  37. package/dist/runners/index.js +2 -0
  38. package/dist/runners/review-agent.d.ts +47 -0
  39. package/dist/runners/review-agent.js +220 -0
  40. package/dist/runners/security-triage.d.ts +43 -0
  41. package/dist/runners/security-triage.js +158 -0
  42. package/dist/runners/types.d.ts +24 -1
  43. package/dist/security.d.ts +8 -3
  44. package/dist/security.js +13 -2
  45. package/dist/shared.d.ts +17 -0
  46. package/dist/shared.js +27 -0
  47. package/dist/state/index.d.ts +1 -1
  48. package/dist/state/schema.d.ts +4 -1
  49. package/dist/state/schema.js +89 -1
  50. package/dist/state/store.d.ts +31 -1
  51. package/dist/state/store.js +208 -13
  52. package/dist/state/types.d.ts +52 -0
  53. package/dist/triage.d.ts +36 -0
  54. package/dist/triage.js +133 -0
  55. package/dist/types.d.ts +1 -1
  56. package/dist/watch.d.ts +6 -2
  57. package/dist/watch.js +34 -6
  58. package/dist/workflow-patterns/artifact-writer.d.ts +16 -0
  59. package/dist/workflow-patterns/artifact-writer.js +34 -0
  60. package/dist/workflow-patterns/classifiers.d.ts +10 -0
  61. package/dist/workflow-patterns/classifiers.js +72 -0
  62. package/dist/workflow-patterns/detector.d.ts +27 -0
  63. package/dist/workflow-patterns/detector.js +186 -0
  64. package/dist/workflow-patterns/index.d.ts +8 -0
  65. package/dist/workflow-patterns/index.js +7 -0
  66. package/dist/workflow-patterns/proposal-generator.d.ts +15 -0
  67. package/dist/workflow-patterns/proposal-generator.js +183 -0
  68. package/dist/workflow-patterns/telemetry-ingest.d.ts +27 -0
  69. package/dist/workflow-patterns/telemetry-ingest.js +103 -0
  70. package/dist/workflow-patterns/types.d.ts +61 -0
  71. package/dist/workflow-patterns/types.js +11 -0
  72. package/package.json +4 -2
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Product Priority Algorithm (PPA) — composite scoring module.
3
+ *
4
+ * Implements the PPA priority function:
5
+ * P(w) = Sα(w) × Dπ(w) × Mφ(w) × Eρ(w) × (1 − Eτ) × (1 + HC(w)) × Cκ(w)
6
+ *
7
+ * Each dimension maps real-world product signals into a bounded numeric
8
+ * range and the multiplicative composite lets any single zero-score
9
+ * dimension veto the work item.
10
+ *
11
+ * RFC reference: PPA section (priority scoring).
12
+ */
13
+ // ── Constants ───────────────────────────────────────────────────────
14
+ /** Default value used when an input signal is not provided. */
15
+ const DEFAULT_SIGNAL = 0.5;
16
+ /** Market force bounds — tighter than the paper's [0.025, 45]. */
17
+ const MARKET_FORCE_MIN = 0.5;
18
+ const MARKET_FORCE_MAX = 3.0;
19
+ /** Calibration coefficient bounds. */
20
+ const CALIBRATION_MIN = 0.7;
21
+ const CALIBRATION_MAX = 1.3;
22
+ /** Default weights for human curve sub-components. */
23
+ const DEFAULT_HC_WEIGHTS = { explicit: 0.5, consensus: 0.3, decision: 0.2 };
24
+ /**
25
+ * Total number of optional input fields that contribute to confidence.
26
+ * When all are provided confidence = 1; when none are provided confidence
27
+ * equals the ratio of zero provided over this count.
28
+ */
29
+ const SCORABLE_FIELDS = [
30
+ 'soulAlignment',
31
+ 'customerRequestCount',
32
+ 'demandSignal',
33
+ 'bugSeverity',
34
+ 'builderConviction',
35
+ 'techInflection',
36
+ 'competitivePressure',
37
+ 'regulatoryUrgency',
38
+ 'complexity',
39
+ 'budgetUtilization',
40
+ 'dependencyClearance',
41
+ 'competitiveDrift',
42
+ 'marketDivergence',
43
+ 'explicitPriority',
44
+ 'teamConsensus',
45
+ 'meetingDecision',
46
+ ];
47
+ // ── Helpers ─────────────────────────────────────────────────────────
48
+ /** Clamp a value to [min, max]. */
49
+ function clamp(value, min, max) {
50
+ return Math.min(max, Math.max(min, value));
51
+ }
52
+ // ── Dimension Computations ──────────────────────────────────────────
53
+ /**
54
+ * Sα — Soul Alignment [0, 1].
55
+ * How well the work item aligns with the product's core mission.
56
+ */
57
+ function computeSoulAlignment(input) {
58
+ return clamp(input.soulAlignment ?? DEFAULT_SIGNAL, 0, 1);
59
+ }
60
+ /**
61
+ * Dπ — Demand Pressure [0, 1.5].
62
+ * Blends customer requests, recency-weighted demand, bug severity, and
63
+ * builder conviction into a single demand signal.
64
+ */
65
+ function computeDemandPressure(input) {
66
+ const requestSignal = input.customerRequestCount !== undefined
67
+ ? Math.min(1, input.customerRequestCount / 10)
68
+ : DEFAULT_SIGNAL;
69
+ const demandSignal = input.demandSignal ?? DEFAULT_SIGNAL;
70
+ const severitySignal = input.bugSeverity !== undefined ? input.bugSeverity / 5 : 0; // no bug severity means no bug boost
71
+ const conviction = input.builderConviction ?? DEFAULT_SIGNAL;
72
+ // Weighted blend, scaled to [0, 1.5]
73
+ const raw = requestSignal * 0.3 + demandSignal * 0.3 + severitySignal * 0.2 + conviction * 0.2;
74
+ return clamp(raw * 1.5, 0, 1.5);
75
+ }
76
+ /**
77
+ * Mφ — Market Force [0.5, 3.0].
78
+ * Captures technology inflection, competitive pressure, and regulatory
79
+ * urgency as a multiplicative amplifier.
80
+ */
81
+ function computeMarketForce(input) {
82
+ const tech = input.techInflection ?? DEFAULT_SIGNAL;
83
+ const competitive = input.competitivePressure ?? DEFAULT_SIGNAL;
84
+ const regulatory = input.regulatoryUrgency ?? DEFAULT_SIGNAL;
85
+ // Average of the three signals, scaled to the bounded range
86
+ const avg = (tech + competitive + regulatory) / 3;
87
+ const scaled = MARKET_FORCE_MIN + avg * (MARKET_FORCE_MAX - MARKET_FORCE_MIN);
88
+ return clamp(scaled, MARKET_FORCE_MIN, MARKET_FORCE_MAX);
89
+ }
90
+ /**
91
+ * Eρ — Execution Reality [0, 1].
92
+ * Factors in complexity (inverse), budget headroom, and dependency
93
+ * clearance to express how feasible execution is right now.
94
+ */
95
+ function computeExecutionReality(input) {
96
+ // Complexity 1-10 → inverse feasibility (1 = easy, 10 = very hard)
97
+ const complexityFeasibility = input.complexity !== undefined ? 1 - (input.complexity - 1) / 9 : DEFAULT_SIGNAL;
98
+ // Budget utilization: higher usage → less headroom → lower score
99
+ const budgetHeadroom = input.budgetUtilization !== undefined
100
+ ? 1 - clamp(input.budgetUtilization / 100, 0, 1)
101
+ : DEFAULT_SIGNAL;
102
+ const depClearance = input.dependencyClearance ?? DEFAULT_SIGNAL;
103
+ const raw = complexityFeasibility * 0.4 + budgetHeadroom * 0.3 + depClearance * 0.3;
104
+ return clamp(raw, 0, 1);
105
+ }
106
+ /**
107
+ * Eτ — Entropy Tax [0, 1].
108
+ * Captures competitive drift and market divergence. Higher entropy means
109
+ * the work item is becoming less relevant over time.
110
+ */
111
+ function computeEntropyTax(input) {
112
+ const drift = input.competitiveDrift ?? 0; // default: no drift
113
+ const divergence = input.marketDivergence ?? 0; // default: no divergence
114
+ const raw = (drift + divergence) / 2;
115
+ return clamp(raw, 0, 1);
116
+ }
117
+ /**
118
+ * HC — Human Curve [-1, 1].
119
+ * Blends explicit priority, team consensus, and meeting decisions through
120
+ * tanh to produce a bounded human signal.
121
+ */
122
+ function computeHumanCurve(input, weights) {
123
+ const explicit = input.explicitPriority ?? DEFAULT_SIGNAL;
124
+ const consensus = input.teamConsensus ?? DEFAULT_SIGNAL;
125
+ const decision = input.meetingDecision ?? DEFAULT_SIGNAL;
126
+ // Center around 0.5 so default inputs produce ~0 HC
127
+ const centered = (explicit - 0.5) * weights.explicit +
128
+ (consensus - 0.5) * weights.consensus +
129
+ (decision - 0.5) * weights.decision;
130
+ // Scale up so full-range inputs can reach [-1, 1] through tanh
131
+ return Math.tanh(centered * 2);
132
+ }
133
+ /**
134
+ * Cκ — Calibration Coefficient [0.7, 1.3].
135
+ * A tuning knob that lets operators scale the final score up or down.
136
+ */
137
+ function computeCalibration(config) {
138
+ const coeff = config?.calibrationCoefficient ?? 1.0;
139
+ return clamp(coeff, CALIBRATION_MIN, CALIBRATION_MAX);
140
+ }
141
+ // ── Confidence ──────────────────────────────────────────────────────
142
+ /**
143
+ * Compute a confidence score [0, 1] based on the fraction of optional
144
+ * input fields that were explicitly provided (not defaulted).
145
+ */
146
+ function computeConfidence(input) {
147
+ let provided = 0;
148
+ for (const field of SCORABLE_FIELDS) {
149
+ if (input[field] !== undefined) {
150
+ provided++;
151
+ }
152
+ }
153
+ return provided / SCORABLE_FIELDS.length;
154
+ }
155
+ // ── Public API ──────────────────────────────────────────────────────
156
+ /**
157
+ * Compute the PPA composite priority score for a single work item.
158
+ *
159
+ * P(w) = Sα × Dπ × Mφ × Eρ × (1 − Eτ) × (1 + HC) × Cκ
160
+ */
161
+ export function computePriority(input, config) {
162
+ const timestamp = new Date().toISOString();
163
+ // ── Override path ──────────────────────────────────────────────
164
+ if (input.override) {
165
+ return {
166
+ composite: Infinity,
167
+ dimensions: {
168
+ soulAlignment: 1,
169
+ demandPressure: 1.5,
170
+ marketForce: MARKET_FORCE_MAX,
171
+ executionReality: 1,
172
+ entropyTax: 0,
173
+ humanCurve: 1,
174
+ calibration: 1,
175
+ },
176
+ confidence: 1,
177
+ timestamp,
178
+ override: {
179
+ reason: input.overrideReason ?? 'No reason provided',
180
+ expiry: input.overrideExpiry,
181
+ },
182
+ };
183
+ }
184
+ // ── Resolve HC weights ─────────────────────────────────────────
185
+ const hcWeights = {
186
+ explicit: config?.humanCurveWeights?.explicit ?? DEFAULT_HC_WEIGHTS.explicit,
187
+ consensus: config?.humanCurveWeights?.consensus ?? DEFAULT_HC_WEIGHTS.consensus,
188
+ decision: config?.humanCurveWeights?.decision ?? DEFAULT_HC_WEIGHTS.decision,
189
+ };
190
+ // ── Compute each dimension ────────────────────────────────────
191
+ const soulAlignment = computeSoulAlignment(input);
192
+ const demandPressure = computeDemandPressure(input);
193
+ const marketForce = computeMarketForce(input);
194
+ const executionReality = computeExecutionReality(input);
195
+ const entropyTax = computeEntropyTax(input);
196
+ const humanCurve = computeHumanCurve(input, hcWeights);
197
+ const calibration = computeCalibration(config);
198
+ // ── Composite ─────────────────────────────────────────────────
199
+ const composite = soulAlignment *
200
+ demandPressure *
201
+ marketForce *
202
+ executionReality *
203
+ (1 - entropyTax) *
204
+ (1 + humanCurve) *
205
+ calibration;
206
+ return {
207
+ composite,
208
+ dimensions: {
209
+ soulAlignment,
210
+ demandPressure,
211
+ marketForce,
212
+ executionReality,
213
+ entropyTax,
214
+ humanCurve,
215
+ calibration,
216
+ },
217
+ confidence: computeConfidence(input),
218
+ timestamp,
219
+ };
220
+ }
221
+ /**
222
+ * Score and rank multiple work items by descending composite priority.
223
+ * Override items (composite = Infinity) always sort first.
224
+ */
225
+ export function rankWorkItems(items, config) {
226
+ return items
227
+ .map((item) => ({ ...item, score: computePriority(item, config) }))
228
+ .sort((a, b) => b.score.composite - a.score.composite);
229
+ }
230
+ //# sourceMappingURL=priority.js.map
@@ -0,0 +1,31 @@
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
+ }
20
+ /**
21
+ * Execute a single review agent against a PR diff.
22
+ *
23
+ * @param prNumber - PR number (for logging/identification)
24
+ * @param diff - The full PR diff text
25
+ * @param reviewType - Which review perspective (testing, critic, security)
26
+ * @param context - Issue context for the review
27
+ * @param options - Optional configuration overrides
28
+ * @returns Review verdict with findings
29
+ */
30
+ export declare function executeReview(prNumber: number, diff: string, reviewType: ReviewType, context: ReviewContext, options?: ReviewOptions): Promise<ReviewVerdict>;
31
+ //# sourceMappingURL=review.d.ts.map
package/dist/review.js ADDED
@@ -0,0 +1,74 @@
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
+ // ── Public API ───────────────────────────────────────────────────────
7
+ /**
8
+ * Execute a single review agent against a PR diff.
9
+ *
10
+ * @param prNumber - PR number (for logging/identification)
11
+ * @param diff - The full PR diff text
12
+ * @param reviewType - Which review perspective (testing, critic, security)
13
+ * @param context - Issue context for the review
14
+ * @param options - Optional configuration overrides
15
+ * @returns Review verdict with findings
16
+ */
17
+ export async function executeReview(prNumber, diff, reviewType, context, options) {
18
+ const logger = options?.logger;
19
+ logger?.info?.(`Starting ${reviewType} review for PR #${prNumber}`);
20
+ const runner = options?.runner ??
21
+ new ReviewAgentRunner({
22
+ ...options?.apiConfig,
23
+ reviewType,
24
+ });
25
+ const result = await runner.run({
26
+ issueId: `PR-${prNumber}`,
27
+ issueNumber: prNumber,
28
+ issueTitle: context.issueTitle,
29
+ issueBody: diff,
30
+ workDir: '',
31
+ branch: '',
32
+ constraints: {
33
+ maxFilesPerChange: 0,
34
+ requireTests: false,
35
+ blockedPaths: [],
36
+ },
37
+ // Reuse ciErrors field for acceptance criteria
38
+ ciErrors: context.acceptanceCriteria,
39
+ });
40
+ if (!result.success) {
41
+ logger?.error?.(`${reviewType} review failed: ${result.error}`);
42
+ return {
43
+ type: reviewType,
44
+ approved: false,
45
+ findings: [
46
+ {
47
+ severity: 'critical',
48
+ message: `Review agent failed: ${result.error ?? 'unknown error'}`,
49
+ },
50
+ ],
51
+ summary: `${reviewType} review could not be completed`,
52
+ };
53
+ }
54
+ try {
55
+ const verdict = JSON.parse(result.summary);
56
+ logger?.info?.(`${reviewType} review complete: ${verdict.approved ? 'APPROVED' : 'CHANGES REQUESTED'} (${verdict.findings.length} findings)`);
57
+ return { ...verdict, type: reviewType };
58
+ }
59
+ catch {
60
+ logger?.error?.(`Failed to parse ${reviewType} verdict from runner output`);
61
+ return {
62
+ type: reviewType,
63
+ approved: false,
64
+ findings: [
65
+ {
66
+ severity: 'critical',
67
+ message: 'Failed to parse review verdict from runner output',
68
+ },
69
+ ],
70
+ summary: `${reviewType} review verdict was not valid JSON`,
71
+ };
72
+ }
73
+ }
74
+ //# sourceMappingURL=review.js.map