@cat-factory/gates 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Igor Savin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ import type { GateContext, GateDefinition } from '@cat-factory/kernel';
2
+ /**
3
+ * CI gate: poll the PR head's check runs; escalate to a `ci-fixer` on red CI. A
4
+ * pass-through until {@link wireCiStatusProvider} supplies a provider.
5
+ */
6
+ export declare const ciGate: (ctx: GateContext) => GateDefinition;
7
+ /**
8
+ * Conflicts gate: check PR mergeability; escalate to a `conflict-resolver` on conflict. A
9
+ * pass-through until {@link wireMergeabilityProvider} supplies a provider.
10
+ */
11
+ export declare const conflictsGate: (_ctx: GateContext) => GateDefinition;
12
+ /**
13
+ * Post-release-health gate: after deploy, watch the release's Datadog monitors/SLOs over a
14
+ * window; escalate to the `on-call` agent on a regression. The on-call agent INVESTIGATES
15
+ * (it makes no commits and doesn't change prod), so its completion is resolved specially via
16
+ * {@link GateDefinition.resolveHelperCompletion} — it must NOT re-probe (that would just
17
+ * regress again and burn the budget). A pass-through until {@link wireReleaseHealthProvider}.
18
+ */
19
+ export declare const postReleaseHealthGate: (ctx: GateContext) => GateDefinition;
20
+ //# sourceMappingURL=gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EAKf,MAAM,qBAAqB,CAAA;AAwC5B;;;GAGG;AACH,eAAO,MAAM,MAAM,QAAS,WAAW,KAAG,cA+CxC,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,SAAU,WAAW,KAAG,cA6BhD,CAAA;AAiEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,QAAS,WAAW,KAAG,cAwIvD,CAAA"}
package/dist/gates.js ADDED
@@ -0,0 +1,276 @@
1
+ import { aggregateCi, CI_AGENT_KIND, CI_FIXER_AGENT_KIND, classifyReleaseHealth, CONFLICT_RESOLVER_AGENT_KIND, CONFLICTS_AGENT_KIND, DEFAULT_MERGE_PRESET, describeFailingChecks, describeRegressedSignals, isCiGreen, listFailingChecks, ON_CALL_AGENT_KIND, POST_RELEASE_HEALTH_AGENT_KIND, renderReleaseEvidence, } from '@cat-factory/kernel';
2
+ import { parseOnCallAssessment } from '@cat-factory/contracts';
3
+ import { getCiStatusProvider, getIncidentEnrichment, getMergeabilityProvider, getReleaseHealthProvider, } from './providers.js';
4
+ /**
5
+ * Conflict-resolver attempt cap. Unlike CI (where each fixer round gets fresh red-check
6
+ * output to act on), a conflict retry re-merges the SAME base and gets no new signal, so a
7
+ * large budget just burns containers re-attempting the same conflict (observed in prod: 10
8
+ * attempts, head SHA never moved, run failed). Cap it low and fail fast to a
9
+ * manual-resolution message instead of churning to CI's default of 10.
10
+ */
11
+ const CONFLICT_RESOLVER_MAX_ATTEMPTS = 3;
12
+ /** Format a 0..1 score as a rounded percentage for notification copy. */
13
+ function pct(score) {
14
+ return `${Math.round(score * 100)}%`;
15
+ }
16
+ /**
17
+ * CI gate: poll the PR head's check runs; escalate to a `ci-fixer` on red CI. A
18
+ * pass-through until {@link wireCiStatusProvider} supplies a provider.
19
+ */
20
+ export const ciGate = (ctx) => ({
21
+ kind: CI_AGENT_KIND,
22
+ helperKind: CI_FIXER_AGENT_KIND,
23
+ wired: () => !!getCiStatusProvider(),
24
+ unwiredOutput: 'CI gate skipped (no CI status provider configured).',
25
+ probe: async (workspaceId, blockId) => {
26
+ const report = await getCiStatusProvider().getStatus(workspaceId, blockId);
27
+ const verdict = aggregateCi(report.checks);
28
+ if (isCiGreen(verdict)) {
29
+ return {
30
+ status: 'pass',
31
+ headSha: report.headSha,
32
+ passOutput: verdict === 'none'
33
+ ? 'CI gate passed: no checks configured for the PR head.'
34
+ : `CI gate passed: ${report.checks.length} check(s) green.`,
35
+ };
36
+ }
37
+ if (verdict === 'pending')
38
+ return { status: 'pending', headSha: report.headSha };
39
+ return {
40
+ status: 'fail',
41
+ headSha: report.headSha,
42
+ failureSummary: describeFailingChecks(report.checks),
43
+ failingChecks: listFailingChecks(report.checks),
44
+ };
45
+ },
46
+ // Surface the failing-check summary to the fixer as resolved context.
47
+ helperPriorOutput: (summary) => ({ agentKind: CI_AGENT_KIND, output: summary }),
48
+ onExhausted: async ({ workspaceId, instance, block, step, summary }) => {
49
+ const attempts = step.gate?.attempts ?? 0;
50
+ await ctx.raiseNotification(workspaceId, {
51
+ type: 'ci_failed',
52
+ blockId: block.id,
53
+ executionId: instance.id,
54
+ title: `CI is still failing for "${block.title}"`,
55
+ body: `The CI-fixer agent tried ${attempts} time(s) but CI is still red. ${summary ?? ''} ` +
56
+ `Take a look and retry the run once fixed.`,
57
+ payload: {
58
+ ...(block.pullRequest?.url ? { prUrl: block.pullRequest.url } : {}),
59
+ pipelineName: instance.pipelineName,
60
+ },
61
+ });
62
+ return {
63
+ error: `CI did not pass after ${attempts} CI-fixer attempt(s). ${summary ?? ''}`.trim(),
64
+ };
65
+ },
66
+ });
67
+ /**
68
+ * Conflicts gate: check PR mergeability; escalate to a `conflict-resolver` on conflict. A
69
+ * pass-through until {@link wireMergeabilityProvider} supplies a provider.
70
+ */
71
+ export const conflictsGate = (_ctx) => ({
72
+ kind: CONFLICTS_AGENT_KIND,
73
+ helperKind: CONFLICT_RESOLVER_AGENT_KIND,
74
+ wired: () => !!getMergeabilityProvider(),
75
+ unwiredOutput: 'Conflict gate skipped (no mergeability provider configured).',
76
+ attemptBudget: () => CONFLICT_RESOLVER_MAX_ATTEMPTS,
77
+ probe: async (workspaceId, blockId) => {
78
+ const report = await getMergeabilityProvider().getMergeability(workspaceId, blockId);
79
+ // No PR resolved, or it merges cleanly → nothing to do; advance.
80
+ if (report.headSha === null || report.verdict === 'mergeable') {
81
+ return {
82
+ status: 'pass',
83
+ headSha: report.headSha,
84
+ passOutput: report.headSha === null
85
+ ? 'Conflict gate passed: no open PR to gate.'
86
+ : 'Conflict gate passed: the PR merges cleanly with its base.',
87
+ };
88
+ }
89
+ // GitHub still computing mergeability → keep polling.
90
+ if (report.verdict === 'unknown')
91
+ return { status: 'pending', headSha: report.headSha };
92
+ return { status: 'fail', headSha: report.headSha };
93
+ },
94
+ onExhausted: async ({ step }) => ({
95
+ error: `The pull request still conflicts with its base after ` +
96
+ `${step.gate?.attempts ?? 0} conflict-resolver attempt(s). Resolve the conflict ` +
97
+ `manually, then retry the run.`,
98
+ }),
99
+ });
100
+ /** Raise a `release_regression` notification carrying the on-call assessment + signals. */
101
+ async function raiseReleaseRegression(ctx, workspaceId, args, assessment, signals, summary) {
102
+ const { instance, block } = args;
103
+ const body = assessment
104
+ ? `Post-release monitoring flagged a regression after this PR shipped. On-call recommends ` +
105
+ `**${assessment.recommendation}** (culprit confidence ${pct(assessment.culpritConfidence)}). ` +
106
+ `${assessment.rationale}`
107
+ : `Post-release monitoring flagged a regression after this PR shipped. ${summary} ` +
108
+ `Investigate before deciding whether to revert.`;
109
+ await ctx.raiseNotification(workspaceId, {
110
+ type: 'release_regression',
111
+ blockId: block.id,
112
+ executionId: instance.id,
113
+ title: `Release regression for "${block.title}"`,
114
+ body,
115
+ payload: {
116
+ ...(assessment ? { onCallAssessment: assessment } : {}),
117
+ ...(signals.length ? { releaseSignals: signals } : {}),
118
+ ...(block.pullRequest?.url ? { prUrl: block.pullRequest.url } : {}),
119
+ pipelineName: instance.pipelineName,
120
+ },
121
+ });
122
+ }
123
+ /**
124
+ * Best-effort: annotate an incident PagerDuty / incident.io already opened (from the same
125
+ * monitors/SLOs) with the on-call investigation. NOT alerting — those systems already
126
+ * paged. A no-op when no provider is wired or no matching incident exists.
127
+ */
128
+ async function enrichIncident(workspaceId, args, assessment, signals, since) {
129
+ const incidentEnrichment = getIncidentEnrichment();
130
+ if (!incidentEnrichment)
131
+ return;
132
+ const { block } = args;
133
+ const update = {
134
+ title: `Regression suspected from "${block.title}"`,
135
+ body: assessment
136
+ ? `${assessment.rationale} (recommendation: ${assessment.recommendation}, culprit confidence ${pct(assessment.culpritConfidence)})`
137
+ : 'cat-factory on-call investigated a post-release regression suspected from this change.',
138
+ ...(block.pullRequest?.url ? { prUrl: block.pullRequest.url } : {}),
139
+ };
140
+ try {
141
+ await incidentEnrichment.enrich({ workspaceId, signalIds: signals.map((s) => s.id), since }, update);
142
+ }
143
+ catch {
144
+ // best-effort: a failing enrichment must not block the run or the notification
145
+ }
146
+ }
147
+ /**
148
+ * Post-release-health gate: after deploy, watch the release's Datadog monitors/SLOs over a
149
+ * window; escalate to the `on-call` agent on a regression. The on-call agent INVESTIGATES
150
+ * (it makes no commits and doesn't change prod), so its completion is resolved specially via
151
+ * {@link GateDefinition.resolveHelperCompletion} — it must NOT re-probe (that would just
152
+ * regress again and burn the budget). A pass-through until {@link wireReleaseHealthProvider}.
153
+ */
154
+ export const postReleaseHealthGate = (ctx) => ({
155
+ kind: POST_RELEASE_HEALTH_AGENT_KIND,
156
+ helperKind: ON_CALL_AGENT_KIND,
157
+ wired: () => !!getReleaseHealthProvider(),
158
+ unwiredOutput: 'Post-release health gate skipped (no release-health provider configured).',
159
+ attemptBudget: (preset) => preset.releaseMaxAttempts,
160
+ // Running out of poll budget while still watching means the window outlasted the driver's
161
+ // budget with NO regression observed — a healthy pass, not a timeout.
162
+ pollExhaustion: 'pass',
163
+ probe: async (workspaceId, blockId, gateState) => {
164
+ // Only watch a release that actually SHIPPED. The merger sets the block `done` when it
165
+ // merges for real, but leaves it `pr_ready` when it raises a review without merging — and
166
+ // a no-merger pipeline also never auto-merges. There is nothing deployed to watch in
167
+ // those cases, so pass through immediately instead of polling Datadog (and possibly
168
+ // escalating an on-call investigation) for a change that was never released.
169
+ const block = await ctx.getBlock(workspaceId, blockId);
170
+ if (!block || block.status !== 'done') {
171
+ return {
172
+ status: 'pass',
173
+ headSha: null,
174
+ passOutput: 'Post-release health gate skipped: the PR was not merged (nothing deployed to watch).',
175
+ };
176
+ }
177
+ const since = gateState.watchSince ?? ctx.clock.now();
178
+ const report = await getReleaseHealthProvider().probe(workspaceId, blockId, since);
179
+ // No signals configured for this block → nothing to watch; advance immediately (don't
180
+ // park for the whole window on an unmapped release).
181
+ if (report.signals.length === 0) {
182
+ return {
183
+ status: 'pass',
184
+ headSha: null,
185
+ passOutput: 'Post-release health gate passed: no monitors/SLOs configured for this release.',
186
+ };
187
+ }
188
+ // The watch window is resolved ONCE on first entry and stashed on the gate state (see
189
+ // evaluateGate), so the probe doesn't re-load the block + re-resolve the merge preset on
190
+ // every poll over the window.
191
+ const windowMinutes = gateState.watchWindowMinutes ?? DEFAULT_MERGE_PRESET.releaseWatchWindowMinutes;
192
+ const windowElapsed = ctx.clock.now() - since >= windowMinutes * 60_000;
193
+ const verdict = classifyReleaseHealth({ report, windowElapsed });
194
+ if (verdict === 'pass') {
195
+ return {
196
+ status: 'pass',
197
+ headSha: null,
198
+ passOutput: `Post-release health gate passed: ${report.signals.length} signal(s) healthy through the watch window.`,
199
+ };
200
+ }
201
+ if (verdict === 'pending')
202
+ return { status: 'pending', headSha: null };
203
+ return {
204
+ status: 'fail',
205
+ headSha: null,
206
+ failureSummary: describeRegressedSignals(report.signals),
207
+ };
208
+ },
209
+ // The on-call agent gets the full evidence bundle (regressed signals + recent error logs),
210
+ // gathered fresh at dispatch.
211
+ gatherHelperPriorOutputs: async (workspaceId, blockId, gateState) => {
212
+ const since = gateState.watchSince ?? ctx.clock.now();
213
+ const evidence = await getReleaseHealthProvider().gatherEvidence(workspaceId, blockId, since);
214
+ // Stash the regressed signals on the gate state so the on-call COMPLETION handler
215
+ // (resolveHelperCompletion) builds the notification + incident enrichment from the SAME
216
+ // evidence the agent investigated — rather than re-reading Datadog a third time. The
217
+ // caller spreads `...step.gate` right after, so this mutation persists.
218
+ gateState.regressedSignals = evidence.regressedSignals;
219
+ return [{ agentKind: POST_RELEASE_HEALTH_AGENT_KIND, output: renderReleaseEvidence(evidence) }];
220
+ },
221
+ onExhausted: async ({ workspaceId, instance, block, step, summary }) => {
222
+ // Reached when releaseMaxAttempts is 0 (operator disabled the on-call investigation) or
223
+ // there is no async executor to escalate to — a FAILED investigation is handled by
224
+ // resolveHelperCompletion, not here. Alert a human via the notification (with any signals
225
+ // already captured), then flag the run.
226
+ await raiseReleaseRegression(ctx, workspaceId, { instance, block }, null, step.gate?.regressedSignals ?? [], summary ?? '');
227
+ return {
228
+ error: `Post-release health regressed and no on-call investigation was configured. ${summary ?? ''}`.trim(),
229
+ };
230
+ },
231
+ // The on-call helper INVESTIGATES — it changes nothing the precheck would re-observe — so on
232
+ // its completion (or failure) we resolve specially instead of re-probing: raise the
233
+ // `release_regression` notification (from the signals stashed at escalation), enrich any open
234
+ // incident, and finish the gate step so the run completes for a human to act out-of-band.
235
+ resolveHelperCompletion: async ({ workspaceId, instance, block, step, result }) => {
236
+ const investigationFailed = result.state === 'failed';
237
+ let assessment = null;
238
+ if (result.state === 'done') {
239
+ try {
240
+ assessment = parseOnCallAssessment(result.result.onCallAssessment);
241
+ }
242
+ catch {
243
+ assessment = null;
244
+ }
245
+ }
246
+ // Reuse the regressed signals captured when the gate escalated (see
247
+ // gatherHelperPriorOutputs) so the notification + incident enrichment reflect exactly what
248
+ // the on-call agent investigated. Only fall back to a fresh gather if they weren't
249
+ // persisted (e.g. an older parked run).
250
+ const since = step.gate?.watchSince ?? ctx.clock.now();
251
+ let regressedSignals = step.gate?.regressedSignals ?? [];
252
+ const provider = getReleaseHealthProvider();
253
+ if (regressedSignals.length === 0 && provider) {
254
+ try {
255
+ const evidence = await provider.gatherEvidence(workspaceId, block.id, since);
256
+ regressedSignals = evidence.regressedSignals;
257
+ }
258
+ catch {
259
+ // best-effort: the assessment + summary still drive the notification
260
+ }
261
+ }
262
+ const baseSummary = step.gate?.lastFailureSummary ?? '';
263
+ const summary = investigationFailed
264
+ ? `${baseSummary} The automated on-call investigation could not complete, so no culprit assessment is available — investigate manually.`.trim()
265
+ : baseSummary;
266
+ await raiseReleaseRegression(ctx, workspaceId, { instance, block }, assessment, regressedSignals, summary);
267
+ await enrichIncident(workspaceId, { block }, assessment, regressedSignals, since);
268
+ const output = assessment
269
+ ? `On-call investigation: ${assessment.recommendation} (culprit confidence ${pct(assessment.culpritConfidence)}). ${assessment.rationale}`
270
+ : investigationFailed
271
+ ? 'On-call investigation did not complete; raised a release-regression notification for manual triage.'
272
+ : 'On-call investigation completed; see the release-regression notification.';
273
+ return { output };
274
+ },
275
+ });
276
+ //# sourceMappingURL=gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.js","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { wireCiStatusProvider, wireMergeabilityProvider, wireReleaseHealthProvider, wireIncidentEnrichment, clearGateProviders, } from './providers.js';
2
+ export { ciGate, conflictsGate, postReleaseHealthGate } from './gates.js';
3
+ /**
4
+ * Register the built-in gate suite. Idempotent (the registry replaces by kind), so importing
5
+ * the package and calling this explicitly are safe to combine. Called automatically as an
6
+ * import side effect below.
7
+ */
8
+ export declare function registerBuiltinGates(): void;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4BA,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEzE;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAI3C"}
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ import { CI_AGENT_KIND, CONFLICTS_AGENT_KIND, POST_RELEASE_HEALTH_AGENT_KIND, registerGate, } from '@cat-factory/kernel';
2
+ import { ciGate, conflictsGate, postReleaseHealthGate } from './gates.js';
3
+ // ---------------------------------------------------------------------------
4
+ // The built-in polling-gate suite, authored ENTIRELY through the public gate-registry
5
+ // seam (`registerGate`) — depending only on @cat-factory/kernel + @cat-factory/contracts,
6
+ // never on the engine. This is the dogfood: if the platform's own CI / conflict /
7
+ // post-release-health gates can be expressed as an external package, so can any
8
+ // deployment's. The engine no longer hard-codes them; it merges whatever gates are
9
+ // registered when its ExecutionService first builds its gate registry.
10
+ //
11
+ // A deployment opts in by importing this package once for its side effect, then wiring each
12
+ // gate's provider at startup:
13
+ //
14
+ // import '@cat-factory/gates'
15
+ // wireCiStatusProvider(new GitHubCiStatusProvider(...))
16
+ // wireMergeabilityProvider(new GitHubMergeabilityProvider(...))
17
+ // wireReleaseHealthProvider(new RegistryReleaseHealthProvider(...))
18
+ // wireIncidentEnrichment(new CompositeIncidentEnrichmentProvider(...))
19
+ //
20
+ // Until a gate's provider is wired it is a harmless pass-through, so a bare import is safe.
21
+ // ---------------------------------------------------------------------------
22
+ export { wireCiStatusProvider, wireMergeabilityProvider, wireReleaseHealthProvider, wireIncidentEnrichment, clearGateProviders, } from './providers.js';
23
+ export { ciGate, conflictsGate, postReleaseHealthGate } from './gates.js';
24
+ /**
25
+ * Register the built-in gate suite. Idempotent (the registry replaces by kind), so importing
26
+ * the package and calling this explicitly are safe to combine. Called automatically as an
27
+ * import side effect below.
28
+ */
29
+ export function registerBuiltinGates() {
30
+ registerGate(CI_AGENT_KIND, ciGate);
31
+ registerGate(CONFLICTS_AGENT_KIND, conflictsGate);
32
+ registerGate(POST_RELEASE_HEALTH_AGENT_KIND, postReleaseHealthGate);
33
+ }
34
+ // Side-effect registration: `import '@cat-factory/gates'` is enough.
35
+ registerBuiltinGates();
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,8BAA8B,EAC9B,YAAY,GACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEzE,8EAA8E;AAC9E,sFAAsF;AACtF,0FAA0F;AAC1F,kFAAkF;AAClF,gFAAgF;AAChF,mFAAmF;AACnF,uEAAuE;AACvE,EAAE;AACF,4FAA4F;AAC5F,8BAA8B;AAC9B,EAAE;AACF,gCAAgC;AAChC,0DAA0D;AAC1D,kEAAkE;AAClE,sEAAsE;AACtE,yEAAyE;AACzE,EAAE;AACF,4FAA4F;AAC5F,8EAA8E;AAE9E,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEzE;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;IACnC,YAAY,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAA;IACjD,YAAY,CAAC,8BAA8B,EAAE,qBAAqB,CAAC,CAAA;AACrE,CAAC;AAED,qEAAqE;AACrE,oBAAoB,EAAE,CAAA"}
@@ -0,0 +1,16 @@
1
+ import type { CiStatusProvider, IncidentEnrichmentProvider, PullRequestMergeabilityProvider, ReleaseHealthProvider } from '@cat-factory/kernel';
2
+ /** Wire (or clear, with `undefined`) the CI check-runs source the `ci` gate probes. */
3
+ export declare function wireCiStatusProvider(provider: CiStatusProvider | undefined): void;
4
+ /** Wire (or clear) the PR-mergeability source the `conflicts` gate probes. */
5
+ export declare function wireMergeabilityProvider(provider: PullRequestMergeabilityProvider | undefined): void;
6
+ /** Wire (or clear) the release-health source the `post-release-health` gate probes. */
7
+ export declare function wireReleaseHealthProvider(provider: ReleaseHealthProvider | undefined): void;
8
+ /** Wire (or clear) the incident-enrichment source the on-call escalation annotates. */
9
+ export declare function wireIncidentEnrichment(provider: IncidentEnrichmentProvider | undefined): void;
10
+ export declare const getCiStatusProvider: () => CiStatusProvider | undefined;
11
+ export declare const getMergeabilityProvider: () => PullRequestMergeabilityProvider | undefined;
12
+ export declare const getReleaseHealthProvider: () => ReleaseHealthProvider | undefined;
13
+ export declare const getIncidentEnrichment: () => IncidentEnrichmentProvider | undefined;
14
+ /** Clear every wired provider. Intended for tests that exercise the gates in isolation. */
15
+ export declare function clearGateProviders(): void;
16
+ //# sourceMappingURL=providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,+BAA+B,EAC/B,qBAAqB,EACtB,MAAM,qBAAqB,CAAA;AAiB5B,uFAAuF;AACvF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAEjF;AAED,8EAA8E;AAC9E,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,+BAA+B,GAAG,SAAS,GACpD,IAAI,CAEN;AAED,uFAAuF;AACvF,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,GAAG,IAAI,CAE3F;AAED,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,0BAA0B,GAAG,SAAS,GAAG,IAAI,CAE7F;AAGD,eAAO,MAAM,mBAAmB,QAAO,gBAAgB,GAAG,SAA6B,CAAA;AACvF,eAAO,MAAM,uBAAuB,QAAO,+BAA+B,GAAG,SACvD,CAAA;AACtB,eAAO,MAAM,wBAAwB,QAAO,qBAAqB,GAAG,SAC7C,CAAA;AACvB,eAAO,MAAM,qBAAqB,QAAO,0BAA0B,GAAG,SAClD,CAAA;AAEpB,2FAA2F;AAC3F,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
@@ -0,0 +1,42 @@
1
+ // The data sources the built-in gates probe are module-level handles a deployment wires at
2
+ // startup (exactly like a custom gate wires its own provider — see
3
+ // `@cat-factory/example-custom-agent`'s `wireLicenseProvider`). The gate factories close
4
+ // over these; until a provider is wired its gate is a harmless pass-through (`wired()`
5
+ // returns false), so a bare `import '@cat-factory/gates'` is always safe.
6
+ //
7
+ // This is the whole point of the externalization: the engine no longer holds these
8
+ // providers. A facade constructs its impl (GitHubCiStatusProvider, RegistryReleaseHealth…)
9
+ // and hands it here, instead of threading it through the engine's constructor.
10
+ let ciStatusProvider;
11
+ let mergeabilityProvider;
12
+ let releaseHealthProvider;
13
+ let incidentEnrichment;
14
+ /** Wire (or clear, with `undefined`) the CI check-runs source the `ci` gate probes. */
15
+ export function wireCiStatusProvider(provider) {
16
+ ciStatusProvider = provider;
17
+ }
18
+ /** Wire (or clear) the PR-mergeability source the `conflicts` gate probes. */
19
+ export function wireMergeabilityProvider(provider) {
20
+ mergeabilityProvider = provider;
21
+ }
22
+ /** Wire (or clear) the release-health source the `post-release-health` gate probes. */
23
+ export function wireReleaseHealthProvider(provider) {
24
+ releaseHealthProvider = provider;
25
+ }
26
+ /** Wire (or clear) the incident-enrichment source the on-call escalation annotates. */
27
+ export function wireIncidentEnrichment(provider) {
28
+ incidentEnrichment = provider;
29
+ }
30
+ // Internal accessors the gate factories read at probe time (after startup wiring).
31
+ export const getCiStatusProvider = () => ciStatusProvider;
32
+ export const getMergeabilityProvider = () => mergeabilityProvider;
33
+ export const getReleaseHealthProvider = () => releaseHealthProvider;
34
+ export const getIncidentEnrichment = () => incidentEnrichment;
35
+ /** Clear every wired provider. Intended for tests that exercise the gates in isolation. */
36
+ export function clearGateProviders() {
37
+ ciStatusProvider = undefined;
38
+ mergeabilityProvider = undefined;
39
+ releaseHealthProvider = undefined;
40
+ incidentEnrichment = undefined;
41
+ }
42
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"AAOA,2FAA2F;AAC3F,mEAAmE;AACnE,yFAAyF;AACzF,uFAAuF;AACvF,0EAA0E;AAC1E,EAAE;AACF,mFAAmF;AACnF,2FAA2F;AAC3F,+EAA+E;AAE/E,IAAI,gBAA8C,CAAA;AAClD,IAAI,oBAAiE,CAAA;AACrE,IAAI,qBAAwD,CAAA;AAC5D,IAAI,kBAA0D,CAAA;AAE9D,uFAAuF;AACvF,MAAM,UAAU,oBAAoB,CAAC,QAAsC;IACzE,gBAAgB,GAAG,QAAQ,CAAA;AAC7B,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,wBAAwB,CACtC,QAAqD;IAErD,oBAAoB,GAAG,QAAQ,CAAA;AACjC,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,yBAAyB,CAAC,QAA2C;IACnF,qBAAqB,GAAG,QAAQ,CAAA;AAClC,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,sBAAsB,CAAC,QAAgD;IACrF,kBAAkB,GAAG,QAAQ,CAAA;AAC/B,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAiC,EAAE,CAAC,gBAAgB,CAAA;AACvF,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAgD,EAAE,CACvF,oBAAoB,CAAA;AACtB,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAsC,EAAE,CAC9E,qBAAqB,CAAA;AACvB,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAA2C,EAAE,CAChF,kBAAkB,CAAA;AAEpB,2FAA2F;AAC3F,MAAM,UAAU,kBAAkB;IAChC,gBAAgB,GAAG,SAAS,CAAA;IAC5B,oBAAoB,GAAG,SAAS,CAAA;IAChC,qBAAqB,GAAG,SAAS,CAAA;IACjC,kBAAkB,GAAG,SAAS,CAAA;AAChC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@cat-factory/gates",
3
+ "version": "0.0.0",
4
+ "description": "The built-in polling-gate suite (CI, merge-conflicts, post-release health + the on-call escalation) for the Agent Architecture Board, authored entirely through the public gate-registry seam — depends only on @cat-factory/kernel + @cat-factory/contracts, never the engine. A deployment imports it for side effect and wires each gate's provider via the exported wireX handles.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/kibertoad/cat-factory.git",
8
+ "directory": "backend/packages/gates"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "type": "module",
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "dependencies": {
27
+ "@cat-factory/contracts": "0.23.0",
28
+ "@cat-factory/kernel": "0.24.0"
29
+ },
30
+ "devDependencies": {
31
+ "typescript": "7.0.1-rc",
32
+ "vitest": "^4.1.9"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -b tsconfig.build.json",
36
+ "typecheck": "tsc -p tsconfig.json --noEmit",
37
+ "test": "vitest",
38
+ "test:run": "vitest run"
39
+ }
40
+ }