@ai-sdlc/orchestrator 0.1.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 (203) hide show
  1. package/dist/adapters.d.ts +60 -0
  2. package/dist/adapters.js +160 -0
  3. package/dist/admission.d.ts +49 -0
  4. package/dist/admission.js +90 -0
  5. package/dist/analysis/analyzer.d.ts +10 -0
  6. package/dist/analysis/analyzer.js +67 -0
  7. package/dist/analysis/complexity-scorer.d.ts +24 -0
  8. package/dist/analysis/complexity-scorer.js +39 -0
  9. package/dist/analysis/context-builder.d.ts +14 -0
  10. package/dist/analysis/context-builder.js +79 -0
  11. package/dist/analysis/convention-detector.d.ts +9 -0
  12. package/dist/analysis/convention-detector.js +177 -0
  13. package/dist/analysis/dependency-parser.d.ts +17 -0
  14. package/dist/analysis/dependency-parser.js +167 -0
  15. package/dist/analysis/file-walker.d.ts +18 -0
  16. package/dist/analysis/file-walker.js +158 -0
  17. package/dist/analysis/hotspot-analyzer.d.ts +28 -0
  18. package/dist/analysis/hotspot-analyzer.js +85 -0
  19. package/dist/analysis/index.d.ts +13 -0
  20. package/dist/analysis/index.js +12 -0
  21. package/dist/analysis/pattern-detector.d.ts +10 -0
  22. package/dist/analysis/pattern-detector.js +86 -0
  23. package/dist/analysis/types.d.ts +94 -0
  24. package/dist/analysis/types.js +5 -0
  25. package/dist/audit-archival.d.ts +48 -0
  26. package/dist/audit-archival.js +72 -0
  27. package/dist/audit-export.d.ts +45 -0
  28. package/dist/audit-export.js +100 -0
  29. package/dist/audit-extended.d.ts +28 -0
  30. package/dist/audit-extended.js +38 -0
  31. package/dist/audit-scheduler.d.ts +32 -0
  32. package/dist/audit-scheduler.js +52 -0
  33. package/dist/audit-sqlite-sink.d.ts +11 -0
  34. package/dist/audit-sqlite-sink.js +51 -0
  35. package/dist/autonomy-tracker.d.ts +76 -0
  36. package/dist/autonomy-tracker.js +277 -0
  37. package/dist/check-runs.d.ts +37 -0
  38. package/dist/check-runs.js +72 -0
  39. package/dist/cli/commands/agents.d.ts +6 -0
  40. package/dist/cli/commands/agents.js +33 -0
  41. package/dist/cli/commands/complexity.d.ts +6 -0
  42. package/dist/cli/commands/complexity.js +35 -0
  43. package/dist/cli/commands/cost.d.ts +6 -0
  44. package/dist/cli/commands/cost.js +53 -0
  45. package/dist/cli/commands/dashboard.d.ts +9 -0
  46. package/dist/cli/commands/dashboard.js +50 -0
  47. package/dist/cli/commands/health.d.ts +6 -0
  48. package/dist/cli/commands/health.js +33 -0
  49. package/dist/cli/commands/init.d.ts +6 -0
  50. package/dist/cli/commands/init.js +127 -0
  51. package/dist/cli/commands/routing.d.ts +6 -0
  52. package/dist/cli/commands/routing.js +46 -0
  53. package/dist/cli/commands/run.d.ts +6 -0
  54. package/dist/cli/commands/run.js +36 -0
  55. package/dist/cli/commands/start.d.ts +6 -0
  56. package/dist/cli/commands/start.js +26 -0
  57. package/dist/cli/commands/status.d.ts +6 -0
  58. package/dist/cli/commands/status.js +34 -0
  59. package/dist/cli/dashboard-renderer.d.ts +24 -0
  60. package/dist/cli/dashboard-renderer.js +129 -0
  61. package/dist/cli/formatters/index.d.ts +6 -0
  62. package/dist/cli/formatters/index.js +18 -0
  63. package/dist/cli/formatters/json.d.ts +5 -0
  64. package/dist/cli/formatters/json.js +7 -0
  65. package/dist/cli/formatters/minimal.d.ts +5 -0
  66. package/dist/cli/formatters/minimal.js +36 -0
  67. package/dist/cli/formatters/table.d.ts +5 -0
  68. package/dist/cli/formatters/table.js +184 -0
  69. package/dist/cli/index.d.ts +6 -0
  70. package/dist/cli/index.js +35 -0
  71. package/dist/compliance-extended.d.ts +41 -0
  72. package/dist/compliance-extended.js +58 -0
  73. package/dist/config.d.ts +26 -0
  74. package/dist/config.js +66 -0
  75. package/dist/context-enrichment.d.ts +33 -0
  76. package/dist/context-enrichment.js +125 -0
  77. package/dist/cost-governance.d.ts +22 -0
  78. package/dist/cost-governance.js +106 -0
  79. package/dist/cost-tracker.d.ts +75 -0
  80. package/dist/cost-tracker.js +177 -0
  81. package/dist/defaults.d.ts +140 -0
  82. package/dist/defaults.js +218 -0
  83. package/dist/deploy/flyio-target.d.ts +19 -0
  84. package/dist/deploy/flyio-target.js +114 -0
  85. package/dist/deploy/index.d.ts +15 -0
  86. package/dist/deploy/index.js +11 -0
  87. package/dist/deploy/kubernetes-target.d.ts +25 -0
  88. package/dist/deploy/kubernetes-target.js +124 -0
  89. package/dist/deploy/metrics-collector.d.ts +31 -0
  90. package/dist/deploy/metrics-collector.js +75 -0
  91. package/dist/deploy/rollout-controller.d.ts +42 -0
  92. package/dist/deploy/rollout-controller.js +192 -0
  93. package/dist/deploy/rollout-types.d.ts +86 -0
  94. package/dist/deploy/rollout-types.js +5 -0
  95. package/dist/deploy/types.d.ts +47 -0
  96. package/dist/deploy/types.js +5 -0
  97. package/dist/deploy/vercel-target.d.ts +16 -0
  98. package/dist/deploy/vercel-target.js +115 -0
  99. package/dist/discovery.d.ts +26 -0
  100. package/dist/discovery.js +46 -0
  101. package/dist/episodic-enhanced.d.ts +88 -0
  102. package/dist/episodic-enhanced.js +212 -0
  103. package/dist/execute.d.ts +81 -0
  104. package/dist/execute.js +703 -0
  105. package/dist/fix-ci.d.ts +61 -0
  106. package/dist/fix-ci.js +380 -0
  107. package/dist/handoff-executor.d.ts +61 -0
  108. package/dist/handoff-executor.js +119 -0
  109. package/dist/index.d.ts +70 -0
  110. package/dist/index.js +87 -0
  111. package/dist/instrumented.d.ts +27 -0
  112. package/dist/instrumented.js +34 -0
  113. package/dist/logger.d.ts +17 -0
  114. package/dist/logger.js +37 -0
  115. package/dist/multi-repo/impact-analyzer.d.ts +22 -0
  116. package/dist/multi-repo/impact-analyzer.js +95 -0
  117. package/dist/multi-repo/index.d.ts +5 -0
  118. package/dist/multi-repo/index.js +4 -0
  119. package/dist/multi-repo/monorepo-detector.d.ts +16 -0
  120. package/dist/multi-repo/monorepo-detector.js +246 -0
  121. package/dist/multi-repo/service-map-builder.d.ts +24 -0
  122. package/dist/multi-repo/service-map-builder.js +235 -0
  123. package/dist/multi-repo/types.d.ts +54 -0
  124. package/dist/multi-repo/types.js +5 -0
  125. package/dist/notifications/index.d.ts +4 -0
  126. package/dist/notifications/index.js +4 -0
  127. package/dist/notifications/notification-router.d.ts +62 -0
  128. package/dist/notifications/notification-router.js +206 -0
  129. package/dist/notifications/slack-messenger.d.ts +26 -0
  130. package/dist/notifications/slack-messenger.js +69 -0
  131. package/dist/notifications/teams-messenger.d.ts +21 -0
  132. package/dist/notifications/teams-messenger.js +85 -0
  133. package/dist/notifications.d.ts +13 -0
  134. package/dist/notifications.js +15 -0
  135. package/dist/orchestration.d.ts +20 -0
  136. package/dist/orchestration.js +53 -0
  137. package/dist/orchestrator.d.ts +160 -0
  138. package/dist/orchestrator.js +372 -0
  139. package/dist/otel-exporter.d.ts +37 -0
  140. package/dist/otel-exporter.js +128 -0
  141. package/dist/plugin.d.ts +45 -0
  142. package/dist/plugin.js +8 -0
  143. package/dist/policy-evaluators.d.ts +40 -0
  144. package/dist/policy-evaluators.js +57 -0
  145. package/dist/process-escalation.d.ts +38 -0
  146. package/dist/process-escalation.js +129 -0
  147. package/dist/progressive-gates.d.ts +54 -0
  148. package/dist/progressive-gates.js +135 -0
  149. package/dist/provenance.d.ts +29 -0
  150. package/dist/provenance.js +61 -0
  151. package/dist/reconcilers.d.ts +28 -0
  152. package/dist/reconcilers.js +37 -0
  153. package/dist/runners/claude-code.d.ts +17 -0
  154. package/dist/runners/claude-code.js +200 -0
  155. package/dist/runners/codex.d.ts +19 -0
  156. package/dist/runners/codex.js +153 -0
  157. package/dist/runners/copilot-stub.d.ts +9 -0
  158. package/dist/runners/copilot-stub.js +15 -0
  159. package/dist/runners/copilot.d.ts +15 -0
  160. package/dist/runners/copilot.js +119 -0
  161. package/dist/runners/cursor-stub.d.ts +9 -0
  162. package/dist/runners/cursor-stub.js +15 -0
  163. package/dist/runners/cursor.d.ts +20 -0
  164. package/dist/runners/cursor.js +140 -0
  165. package/dist/runners/devin-stub.d.ts +9 -0
  166. package/dist/runners/devin-stub.js +15 -0
  167. package/dist/runners/generic-llm.d.ts +51 -0
  168. package/dist/runners/generic-llm.js +125 -0
  169. package/dist/runners/index.d.ts +8 -0
  170. package/dist/runners/index.js +7 -0
  171. package/dist/runners/runner-registry.d.ts +50 -0
  172. package/dist/runners/runner-registry.js +156 -0
  173. package/dist/runners/types.d.ts +59 -0
  174. package/dist/runners/types.js +7 -0
  175. package/dist/security.d.ts +51 -0
  176. package/dist/security.js +70 -0
  177. package/dist/shared.d.ts +134 -0
  178. package/dist/shared.js +284 -0
  179. package/dist/state/index.d.ts +4 -0
  180. package/dist/state/index.js +3 -0
  181. package/dist/state/schema.d.ts +16 -0
  182. package/dist/state/schema.js +264 -0
  183. package/dist/state/store.d.ts +109 -0
  184. package/dist/state/store.js +644 -0
  185. package/dist/state/types.d.ts +190 -0
  186. package/dist/state/types.js +5 -0
  187. package/dist/structured-logger.d.ts +20 -0
  188. package/dist/structured-logger.js +64 -0
  189. package/dist/task-decomposer.d.ts +61 -0
  190. package/dist/task-decomposer.js +265 -0
  191. package/dist/telemetry-extended.d.ts +24 -0
  192. package/dist/telemetry-extended.js +31 -0
  193. package/dist/types.d.ts +9 -0
  194. package/dist/types.js +7 -0
  195. package/dist/validate-agent-output.d.ts +30 -0
  196. package/dist/validate-agent-output.js +81 -0
  197. package/dist/validate-issue.d.ts +25 -0
  198. package/dist/validate-issue.js +102 -0
  199. package/dist/watch.d.ts +43 -0
  200. package/dist/watch.js +99 -0
  201. package/dist/webhook-manager.d.ts +38 -0
  202. package/dist/webhook-manager.js +66 -0
  203. package/package.json +59 -0
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Post-agent output validation — enforces guardrails before push.
3
+ *
4
+ * Pure validation module with no side effects (fully testable).
5
+ */
6
+ export interface ValidationContext {
7
+ filesChanged: string[];
8
+ workDir: string;
9
+ constraints: {
10
+ maxFilesPerChange: number;
11
+ requireTests: boolean;
12
+ blockedPaths: string[];
13
+ };
14
+ guardrails: {
15
+ maxLinesPerPR?: number;
16
+ };
17
+ }
18
+ export interface ValidationViolation {
19
+ rule: string;
20
+ message: string;
21
+ }
22
+ export interface ValidationResult {
23
+ passed: boolean;
24
+ violations: ValidationViolation[];
25
+ }
26
+ /**
27
+ * Validate agent output against guardrails and constraints.
28
+ */
29
+ export declare function validateAgentOutput(ctx: ValidationContext): Promise<ValidationResult>;
30
+ //# sourceMappingURL=validate-agent-output.d.ts.map
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Post-agent output validation — enforces guardrails before push.
3
+ *
4
+ * Pure validation module with no side effects (fully testable).
5
+ */
6
+ import { execFile } from 'node:child_process';
7
+ /**
8
+ * Match a file path against a blocked-path pattern.
9
+ * Supports simple glob suffixes: `foo/**` matches anything under `foo/`.
10
+ */
11
+ function matchesBlockedPath(filePath, pattern) {
12
+ const base = pattern.replace(/\/?\*\*$/, '');
13
+ return filePath === base || filePath.startsWith(base.endsWith('/') ? base : `${base}/`);
14
+ }
15
+ /**
16
+ * Parse total changed lines from `git diff --stat` output.
17
+ * The last line looks like: ` 3 files changed, 40 insertions(+), 12 deletions(-)`
18
+ */
19
+ function parseDiffStatLines(diffStat) {
20
+ const match = diffStat.match(/(\d+)\s+insertions?\(\+\)(?:,\s*(\d+)\s+deletions?\(-\))?/);
21
+ if (!match) {
22
+ // Try deletions-only format: `1 file changed, 5 deletions(-)`
23
+ const delOnly = diffStat.match(/(\d+)\s+deletions?\(-\)/);
24
+ return delOnly ? Number(delOnly[1]) : 0;
25
+ }
26
+ return Number(match[1]) + (match[2] ? Number(match[2]) : 0);
27
+ }
28
+ /**
29
+ * Validate agent output against guardrails and constraints.
30
+ */
31
+ export async function validateAgentOutput(ctx) {
32
+ const violations = [];
33
+ // 1. Blocked paths
34
+ for (const file of ctx.filesChanged) {
35
+ for (const pattern of ctx.constraints.blockedPaths) {
36
+ if (matchesBlockedPath(file, pattern)) {
37
+ violations.push({
38
+ rule: 'blocked-path',
39
+ message: `File \`${file}\` matches blocked path \`${pattern}\``,
40
+ });
41
+ }
42
+ }
43
+ }
44
+ // 2. File count
45
+ if (ctx.filesChanged.length > ctx.constraints.maxFilesPerChange) {
46
+ violations.push({
47
+ rule: 'max-files',
48
+ message: `Changed ${ctx.filesChanged.length} files (max ${ctx.constraints.maxFilesPerChange})`,
49
+ });
50
+ }
51
+ // 3. Max lines per PR
52
+ if (ctx.guardrails.maxLinesPerPR !== undefined) {
53
+ const stdout = await new Promise((resolve, reject) => {
54
+ execFile('git', ['diff', '--stat', 'HEAD~1'], { cwd: ctx.workDir }, (err, out) => {
55
+ if (err)
56
+ reject(err);
57
+ else
58
+ resolve(out);
59
+ });
60
+ });
61
+ const totalLines = parseDiffStatLines(stdout);
62
+ if (totalLines > ctx.guardrails.maxLinesPerPR) {
63
+ violations.push({
64
+ rule: 'max-lines',
65
+ message: `Changed ${totalLines} lines (max ${ctx.guardrails.maxLinesPerPR})`,
66
+ });
67
+ }
68
+ }
69
+ // 4. Require tests
70
+ if (ctx.constraints.requireTests) {
71
+ const hasTestFile = ctx.filesChanged.some((f) => /\.test\./.test(f) || /\.spec\./.test(f));
72
+ if (!hasTestFile) {
73
+ violations.push({
74
+ rule: 'require-tests',
75
+ message: 'No test file found in changed files',
76
+ });
77
+ }
78
+ }
79
+ return { passed: violations.length === 0, violations };
80
+ }
81
+ //# sourceMappingURL=validate-agent-output.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Validates a GitHub issue against quality gates using the reference
3
+ * implementation's enforcement engine, with optional expression and LLM
4
+ * evaluation extensions.
5
+ */
6
+ import { enforce, type EnforcementResult, type QualityGate, type Issue, type ExpressionEvaluator, type LLMEvaluator } from '@ai-sdlc/reference';
7
+ /**
8
+ * Validate an issue against the loaded QualityGate resource.
9
+ * An optional enforceFn can be provided (e.g. instrumented enforcement).
10
+ * Extra metrics (e.g. cost metrics) are merged into the evaluation context.
11
+ */
12
+ export declare function validateIssue(issue: Issue, qualityGate: QualityGate, enforceFn?: typeof enforce, extraMetrics?: Record<string, number>): EnforcementResult;
13
+ /**
14
+ * Extended validation that also evaluates expression and LLM gate rules.
15
+ */
16
+ export declare function validateIssueWithExtensions(issue: Issue, qualityGate: QualityGate, options?: {
17
+ expressionEvaluator?: ExpressionEvaluator;
18
+ llmEvaluator?: LLMEvaluator;
19
+ }): Promise<EnforcementResult>;
20
+ /**
21
+ * Parse complexity from issue body (GitHub issue template format).
22
+ * Returns 0 if not found.
23
+ */
24
+ export declare function parseComplexity(issueBody: string | undefined): number;
25
+ //# sourceMappingURL=validate-issue.d.ts.map
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Validates a GitHub issue against quality gates using the reference
3
+ * implementation's enforcement engine, with optional expression and LLM
4
+ * evaluation extensions.
5
+ */
6
+ import { enforce, evaluateExpressionRule, evaluateLLMRule, } from '@ai-sdlc/reference';
7
+ import { DEFAULT_GITHUB_REPOSITORY } from './defaults.js';
8
+ /**
9
+ * Build an EvaluationContext from an issue, mapping issue metadata
10
+ * to the metrics expected by the quality gate rules.
11
+ */
12
+ function buildEvaluationContext(issue) {
13
+ const hasDescription = issue.description ? issue.description.trim().length : 0;
14
+ const hasAcceptanceCriteria = issue.description
15
+ ? /## Acceptance Criteria/i.test(issue.description)
16
+ ? 1
17
+ : 0
18
+ : 0;
19
+ const complexityMatch = issue.description?.match(/### Complexity\s*\n+\s*(\d+)/i);
20
+ const complexity = complexityMatch ? Number(complexityMatch[1]) : 0;
21
+ return {
22
+ authorType: 'ai-agent',
23
+ repository: DEFAULT_GITHUB_REPOSITORY,
24
+ metrics: {
25
+ 'description-length': hasDescription,
26
+ 'has-acceptance-criteria': hasAcceptanceCriteria,
27
+ complexity,
28
+ },
29
+ };
30
+ }
31
+ /**
32
+ * Validate an issue against the loaded QualityGate resource.
33
+ * An optional enforceFn can be provided (e.g. instrumented enforcement).
34
+ * Extra metrics (e.g. cost metrics) are merged into the evaluation context.
35
+ */
36
+ export function validateIssue(issue, qualityGate, enforceFn, extraMetrics) {
37
+ const ctx = buildEvaluationContext(issue);
38
+ if (extraMetrics) {
39
+ Object.assign(ctx.metrics, extraMetrics);
40
+ }
41
+ return (enforceFn ?? enforce)(qualityGate, ctx);
42
+ }
43
+ /**
44
+ * Extended validation that also evaluates expression and LLM gate rules.
45
+ */
46
+ export async function validateIssueWithExtensions(issue, qualityGate, options) {
47
+ // Start with standard enforcement
48
+ const result = validateIssue(issue, qualityGate);
49
+ // Evaluate expression rules from quality gates
50
+ if (options?.expressionEvaluator) {
51
+ const ctx = buildEvaluationContext(issue);
52
+ for (const gate of qualityGate.spec.gates) {
53
+ if ('expression' in gate.rule) {
54
+ const verdict = evaluateExpressionRule(gate.rule, { ctx }, options.expressionEvaluator);
55
+ if (!verdict.passed) {
56
+ result.allowed = false;
57
+ result.results.push({
58
+ gate: gate.name,
59
+ verdict: 'fail',
60
+ enforcement: gate.enforcement,
61
+ message: verdict.message ??
62
+ `Expression rule failed: ${gate.rule.expression}`,
63
+ });
64
+ }
65
+ }
66
+ }
67
+ }
68
+ // Evaluate LLM rules on issue description
69
+ if (options?.llmEvaluator && issue.description) {
70
+ for (const gate of qualityGate.spec.gates) {
71
+ // Check for LLM evaluation rule pattern (has dimensions and thresholds)
72
+ const rule = gate.rule;
73
+ if ('dimensions' in rule && 'thresholds' in rule) {
74
+ const llmVerdict = await evaluateLLMRule(rule, issue.description, options.llmEvaluator);
75
+ if (!llmVerdict.passed) {
76
+ result.allowed = false;
77
+ const failureDetails = llmVerdict.failures
78
+ .map((f) => `${f.dimension}: ${f.score.toFixed(2)} < ${f.threshold}`)
79
+ .join(', ');
80
+ result.results.push({
81
+ gate: gate.name,
82
+ verdict: 'fail',
83
+ enforcement: gate.enforcement,
84
+ message: `LLM evaluation failed: ${failureDetails}`,
85
+ });
86
+ }
87
+ }
88
+ }
89
+ }
90
+ return result;
91
+ }
92
+ /**
93
+ * Parse complexity from issue body (GitHub issue template format).
94
+ * Returns 0 if not found.
95
+ */
96
+ export function parseComplexity(issueBody) {
97
+ if (!issueBody)
98
+ return 0;
99
+ const match = issueBody.match(/### Complexity\s*\n+\s*(\d+)/i);
100
+ return match ? Number(match[1]) : 0;
101
+ }
102
+ //# sourceMappingURL=validate-issue.js.map
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Reconciler watch mode — wraps executePipeline in a continuous reconciliation loop.
3
+ *
4
+ * Uses ReconcilerLoop + createResourceCache from the reference implementation
5
+ * for level-triggered, idempotent reconciliation with backoff.
6
+ */
7
+ import { type ReconcilerConfig, type ReconcileResult, type Pipeline, type QualityGate, type AutonomyPolicy, type AgentRole, type MetricStore } from '@ai-sdlc/reference';
8
+ import { type ExecuteOptions } from './execute.js';
9
+ export interface WatchOptions {
10
+ /** Override the reconciler config (poll interval, concurrency, backoff). */
11
+ reconcilerConfig?: Partial<ReconcilerConfig>;
12
+ /** Pipeline execution options passed through to executePipeline. */
13
+ executeOptions?: Omit<ExecuteOptions, 'configDir' | 'workDir'>;
14
+ /** Callback invoked when a pipeline reconciliation completes. */
15
+ onReconcile?: (pipelineName: string, result: ReconcileResult) => void;
16
+ /** Optional metric store to instrument reconciliation cycles. */
17
+ metricStore?: MetricStore;
18
+ /** Optional agent roles for pipeline reconciler agent resolution. */
19
+ agents?: Map<string, AgentRole>;
20
+ /** Optional quality gates for gate reconciler evaluation context. */
21
+ qualityGates?: QualityGate[];
22
+ /** Optional autonomy policies for autonomy reconciler evaluation. */
23
+ autonomyPolicies?: AutonomyPolicy[];
24
+ }
25
+ export interface WatchHandle {
26
+ /** Enqueue a pipeline resource for reconciliation. */
27
+ enqueue(pipeline: Pipeline, issueNumber: number): void;
28
+ /** Enqueue a quality gate resource for reconciliation. */
29
+ enqueueGate(gate: QualityGate): void;
30
+ /** Enqueue an autonomy policy resource for reconciliation. */
31
+ enqueueAutonomy(policy: AutonomyPolicy): void;
32
+ /** Stop the reconciliation loop. */
33
+ stop(): void;
34
+ /** Number of items in the queue. */
35
+ readonly queueSize: number;
36
+ /** Number of actively reconciling items. */
37
+ readonly activeCount: number;
38
+ }
39
+ /**
40
+ * Start a reconciler watch loop that continuously processes pipeline resources.
41
+ */
42
+ export declare function startWatch(options?: WatchOptions): WatchHandle;
43
+ //# sourceMappingURL=watch.d.ts.map
package/dist/watch.js ADDED
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Reconciler watch mode — wraps executePipeline in a continuous reconciliation loop.
3
+ *
4
+ * Uses ReconcilerLoop + createResourceCache from the reference implementation
5
+ * for level-triggered, idempotent reconciliation with backoff.
6
+ */
7
+ import { ReconcilerLoop, createResourceCache, instrumentReconciler, } from '@ai-sdlc/reference';
8
+ import { executePipeline } from './execute.js';
9
+ import { createPipelineReconciler, createGateReconciler, createAutonomyReconciler, } from './reconcilers.js';
10
+ /**
11
+ * Start a reconciler watch loop that continuously processes pipeline resources.
12
+ */
13
+ export function startWatch(options = {}) {
14
+ const cache = createResourceCache();
15
+ const issueMap = new Map();
16
+ // H2: Build specialized reconcilers for each resource kind
17
+ const _pipelineReconciler = createPipelineReconciler({
18
+ resolveAgent: (name) => options.agents?.get(name),
19
+ taskFn: async () => ({}),
20
+ });
21
+ const gateReconciler = createGateReconciler({
22
+ getContext: (_gate) => ({ metrics: {}, repository: '', authorType: 'ai-agent' }),
23
+ });
24
+ const autonomyReconciler = createAutonomyReconciler({
25
+ getAgentMetrics: () => undefined,
26
+ getActiveTriggers: () => [],
27
+ });
28
+ // Composite reconciler dispatches by resource kind
29
+ let reconcileFn = async (resource) => {
30
+ switch (resource.kind) {
31
+ case 'Pipeline': {
32
+ const pipeline = resource;
33
+ const issueNumber = issueMap.get(pipeline.metadata.name);
34
+ if (!issueNumber) {
35
+ return {
36
+ type: 'error',
37
+ error: new Error(`No issue number for pipeline ${pipeline.metadata.name}`),
38
+ };
39
+ }
40
+ try {
41
+ await executePipeline(issueNumber, {
42
+ ...options.executeOptions,
43
+ });
44
+ const result = { type: 'success' };
45
+ options.onReconcile?.(pipeline.metadata.name, result);
46
+ return result;
47
+ }
48
+ catch (err) {
49
+ const result = {
50
+ type: 'error',
51
+ error: err instanceof Error ? err : new Error(String(err)),
52
+ };
53
+ options.onReconcile?.(pipeline.metadata.name, result);
54
+ return result;
55
+ }
56
+ }
57
+ case 'QualityGate':
58
+ return gateReconciler(resource);
59
+ case 'AutonomyPolicy':
60
+ return autonomyReconciler(resource);
61
+ default:
62
+ return { type: 'success' };
63
+ }
64
+ };
65
+ // Wrap with instrumentation if metric store is provided
66
+ if (options.metricStore) {
67
+ reconcileFn = instrumentReconciler(reconcileFn, { metricStore: options.metricStore });
68
+ }
69
+ const loop = new ReconcilerLoop(reconcileFn, options.reconcilerConfig);
70
+ loop.start();
71
+ return {
72
+ enqueue(pipeline, issueNumber) {
73
+ issueMap.set(pipeline.metadata.name, issueNumber);
74
+ if (cache.shouldReconcile(pipeline)) {
75
+ loop.enqueue(pipeline);
76
+ }
77
+ },
78
+ enqueueGate(gate) {
79
+ if (cache.shouldReconcile(gate)) {
80
+ loop.enqueue(gate);
81
+ }
82
+ },
83
+ enqueueAutonomy(policy) {
84
+ if (cache.shouldReconcile(policy)) {
85
+ loop.enqueue(policy);
86
+ }
87
+ },
88
+ stop() {
89
+ loop.stop();
90
+ },
91
+ get queueSize() {
92
+ return loop.queueSize;
93
+ },
94
+ get activeCount() {
95
+ return loop.activeCount;
96
+ },
97
+ };
98
+ }
99
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Webhook manager — creates and manages the webhook server,
3
+ * registers providers based on config, and handles lifecycle.
4
+ */
5
+ import { type WebhookServer, type WebhookBridge, type IssueEvent, type PREvent, type BuildEvent } from '@ai-sdlc/reference';
6
+ export interface WebhookManagerConfig {
7
+ /** Port to listen on for webhooks. */
8
+ port: number;
9
+ /** Host to bind to (defaults to '0.0.0.0'). */
10
+ host?: string;
11
+ /** GitHub webhook secret. */
12
+ githubSecret?: string;
13
+ /** GitLab webhook secret token. */
14
+ gitlabSecretToken?: string;
15
+ /** Jira webhook secret. */
16
+ jiraSecret?: string;
17
+ /** Linear webhook signing secret. */
18
+ linearSigningSecret?: string;
19
+ }
20
+ export interface WebhookBridges {
21
+ issues: WebhookBridge<IssueEvent>;
22
+ pullRequests: WebhookBridge<PREvent>;
23
+ builds: WebhookBridge<BuildEvent>;
24
+ }
25
+ export interface WebhookManager {
26
+ /** Start the webhook server. */
27
+ start(): Promise<void>;
28
+ /** Stop the webhook server. */
29
+ stop(): Promise<void>;
30
+ /** Get the configured bridges for event consumption. */
31
+ readonly bridges: WebhookBridges;
32
+ /** Get the underlying server. */
33
+ readonly server: WebhookServer;
34
+ /** Number of registered providers. */
35
+ readonly providerCount: number;
36
+ }
37
+ export declare function createWebhookManager(config: WebhookManagerConfig): WebhookManager;
38
+ //# sourceMappingURL=webhook-manager.d.ts.map
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Webhook manager — creates and manages the webhook server,
3
+ * registers providers based on config, and handles lifecycle.
4
+ */
5
+ import { createWebhookServer, createWebhookBridge, createGitHubWebhookProvider, createGitLabWebhookProvider, createJiraWebhookProvider, createLinearWebhookProvider, transformIssueEvent, transformPREvent, transformBuildEvent, transformGitLabIssueEvent, transformGitLabMREvent, transformGitLabPipelineEvent, transformJiraIssueEvent, transformLinearIssueEvent, } from '@ai-sdlc/reference';
6
+ // ── Implementation ───────────────────────────────────────────────────
7
+ export function createWebhookManager(config) {
8
+ const server = createWebhookServer({ port: config.port, host: config.host });
9
+ // Create unified bridges
10
+ const issueBridge = createWebhookBridge((payload) => {
11
+ // Try each transformer in order
12
+ return (transformIssueEvent(payload) ??
13
+ transformGitLabIssueEvent(payload) ??
14
+ transformJiraIssueEvent(payload) ??
15
+ transformLinearIssueEvent(payload));
16
+ });
17
+ const prBridge = createWebhookBridge((payload) => {
18
+ return transformPREvent(payload) ?? transformGitLabMREvent(payload);
19
+ });
20
+ const buildBridge = createWebhookBridge((payload) => {
21
+ return transformBuildEvent(payload) ?? transformGitLabPipelineEvent(payload);
22
+ });
23
+ const bridges = {
24
+ issues: issueBridge,
25
+ pullRequests: prBridge,
26
+ builds: buildBridge,
27
+ };
28
+ // Register providers based on config
29
+ if (config.githubSecret) {
30
+ const provider = createGitHubWebhookProvider({ secret: config.githubSecret }, { issues: issueBridge, pullRequests: prBridge, builds: buildBridge });
31
+ server.registerProvider(provider);
32
+ }
33
+ if (config.gitlabSecretToken) {
34
+ const provider = createGitLabWebhookProvider({ secretToken: config.gitlabSecretToken }, { issues: issueBridge, mergeRequests: prBridge, pipelines: buildBridge });
35
+ server.registerProvider(provider);
36
+ }
37
+ if (config.jiraSecret) {
38
+ const provider = createJiraWebhookProvider({ secret: config.jiraSecret }, { issues: issueBridge });
39
+ server.registerProvider(provider);
40
+ }
41
+ if (config.linearSigningSecret) {
42
+ const provider = createLinearWebhookProvider({ signingSecret: config.linearSigningSecret }, { issues: issueBridge });
43
+ server.registerProvider(provider);
44
+ }
45
+ return {
46
+ async start() {
47
+ await server.start();
48
+ },
49
+ async stop() {
50
+ issueBridge.close();
51
+ prBridge.close();
52
+ buildBridge.close();
53
+ await server.stop();
54
+ },
55
+ get bridges() {
56
+ return bridges;
57
+ },
58
+ get server() {
59
+ return server;
60
+ },
61
+ get providerCount() {
62
+ return server.providerCount;
63
+ },
64
+ };
65
+ }
66
+ //# sourceMappingURL=webhook-manager.js.map
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@ai-sdlc/orchestrator",
3
+ "version": "0.1.0",
4
+ "description": "AI-SDLC Orchestrator — long-running runtime that drives issues through the complete SDLC with AI agents",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/ai-sdlc-framework/ai-sdlc.git",
9
+ "directory": "orchestrator"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "registry": "https://registry.npmjs.org/"
14
+ },
15
+ "files": ["dist", "!dist/**/*.test.*", "!dist/**/*.map"],
16
+ "type": "module",
17
+ "main": "dist/index.js",
18
+ "types": "dist/index.d.ts",
19
+ "bin": {
20
+ "ai-sdlc": "dist/cli/index.js"
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ },
27
+ "./runners": {
28
+ "types": "./dist/runners/index.d.ts",
29
+ "import": "./dist/runners/index.js"
30
+ },
31
+ "./state": {
32
+ "types": "./dist/state/index.d.ts",
33
+ "import": "./dist/state/index.js"
34
+ },
35
+ "./cli": {
36
+ "types": "./dist/cli/index.d.ts",
37
+ "import": "./dist/cli/index.js"
38
+ }
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "clean": "rm -rf dist *.tsbuildinfo",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest"
45
+ },
46
+ "dependencies": {
47
+ "@ai-sdlc/reference": "workspace:*",
48
+ "better-sqlite3": "^11.0.0",
49
+ "commander": "^12.0.0",
50
+ "yaml": "^2.7.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/better-sqlite3": "^7.6.0",
54
+ "@types/node": "^22.0.0",
55
+ "tsx": "^4.19.0",
56
+ "typescript": "^5.7.0",
57
+ "vitest": "^3.0.0"
58
+ }
59
+ }