@weiyentan/opencode-plugin-awx 0.2.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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/dist/auth.d.ts +112 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +180 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/client.d.ts +148 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +334 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/contracts/job-detail.d.ts +141 -0
  12. package/dist/contracts/job-detail.d.ts.map +1 -0
  13. package/dist/contracts/job-detail.js +98 -0
  14. package/dist/contracts/job-detail.js.map +1 -0
  15. package/dist/contracts/sync-project.d.ts +31 -0
  16. package/dist/contracts/sync-project.d.ts.map +1 -0
  17. package/dist/contracts/sync-project.js +30 -0
  18. package/dist/contracts/sync-project.js.map +1 -0
  19. package/dist/index.d.ts +16 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +754 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/job-status.d.ts +116 -0
  24. package/dist/job-status.d.ts.map +1 -0
  25. package/dist/job-status.js +168 -0
  26. package/dist/job-status.js.map +1 -0
  27. package/dist/launch.d.ts +76 -0
  28. package/dist/launch.d.ts.map +1 -0
  29. package/dist/launch.js +133 -0
  30. package/dist/launch.js.map +1 -0
  31. package/dist/list-projects.d.ts +63 -0
  32. package/dist/list-projects.d.ts.map +1 -0
  33. package/dist/list-projects.js +84 -0
  34. package/dist/list-projects.js.map +1 -0
  35. package/dist/list-templates.d.ts +60 -0
  36. package/dist/list-templates.d.ts.map +1 -0
  37. package/dist/list-templates.js +120 -0
  38. package/dist/list-templates.js.map +1 -0
  39. package/dist/metrics.d.ts +174 -0
  40. package/dist/metrics.d.ts.map +1 -0
  41. package/dist/metrics.js +275 -0
  42. package/dist/metrics.js.map +1 -0
  43. package/dist/transforms.d.ts +52 -0
  44. package/dist/transforms.d.ts.map +1 -0
  45. package/dist/transforms.js +108 -0
  46. package/dist/transforms.js.map +1 -0
  47. package/package.json +56 -0
@@ -0,0 +1,148 @@
1
+ /**
2
+ * client.ts — HTTP middleware pipeline for the AWX plugin.
3
+ *
4
+ * Composes five middleware concerns into a single request pipeline:
5
+ * signal → timeout → breaker gate → fetch → retry/backoff
6
+ *
7
+ * ## Pipeline
8
+ *
9
+ * 1. Combine ToolContext.abort signal + timeout signal
10
+ * 2. Circuit breaker gate (per-tool)
11
+ * 3. Native fetch with Authorization header
12
+ * 4. Response handling: 2xx pass, 4xx no retry, 5xx exponential backoff
13
+ *
14
+ * ## Reference
15
+ *
16
+ * - ADR 0006: Connection Resilience Parameters
17
+ * - docs/client-middleware-design.md
18
+ */
19
+ import { MetricsStore } from "./metrics.js";
20
+ /**
21
+ * Calculate the exponential backoff delay for a given retry attempt.
22
+ *
23
+ * Formula: base * multiplier^attempt + random(0, jitterRatio * calculated)
24
+ *
25
+ * Attempt 0 → 1000ms + 0-500ms jitter
26
+ * Attempt 1 → 2000ms + 0-1000ms jitter
27
+ * Attempt 2 → 4000ms + 0-2000ms jitter
28
+ *
29
+ * @param attempt 0-based retry attempt index
30
+ * @returns Delay in milliseconds
31
+ */
32
+ export declare function calcBackoff(attempt: number): number;
33
+ /**
34
+ * Sleep for a given duration, aborting immediately if the signal fires.
35
+ *
36
+ * Used during retry backoff so that an abort (ToolContext.abort or timeout)
37
+ * cancels the wait immediately instead of waiting for the backoff to elapse.
38
+ *
39
+ * @param ms Duration in milliseconds
40
+ * @param signal Optional AbortSignal — abort listener fires, wait cancels
41
+ */
42
+ export declare function sleepWithAbort(ms: number, signal?: AbortSignal): Promise<void>;
43
+ /**
44
+ * Create an AbortSignal that triggers after the specified timeout.
45
+ *
46
+ * Uses `setTimeout` + `AbortController` rather than `AbortSignal.timeout()`
47
+ * for Node 18 compatibility and to ensure compatibility with vitest fake
48
+ * timers (the native `AbortSignal.timeout()` uses internal Node.js timers
49
+ * that cannot be mocked by vitest).
50
+ */
51
+ export declare function createTimeoutSignal(ms: number): {
52
+ signal: AbortSignal;
53
+ clear: () => void;
54
+ };
55
+ /** Options for createClient */
56
+ export interface ClientOptions {
57
+ /** Request timeout in milliseconds (default: 30_000) */
58
+ timeoutMs?: number;
59
+ /** Maximum retries on 5xx (default: 3) */
60
+ maxRetries?: number;
61
+ /** Circuit breaker trip threshold — consecutive errors before opening (default: 5) */
62
+ circuitBreakerThreshold?: number;
63
+ /** Circuit breaker cooldown in ms (default: 30_000) */
64
+ circuitBreakerCooldownMs?: number;
65
+ /**
66
+ * Optional shared MetricsStore for plugin-level persistence lifecycle.
67
+ * If not provided, a new MetricsStore is created internally.
68
+ * Pass the plugin-level store here so that periodic persist and
69
+ * init-time load are effective across all tools.
70
+ */
71
+ metricsStore?: MetricsStore;
72
+ }
73
+ /** The AWX HTTP client returned by createClient */
74
+ export interface AwxClient {
75
+ /**
76
+ * Send an HTTP request through the middleware pipeline.
77
+ *
78
+ * @param toolName Per-tool circuit breaker identifier
79
+ * @param path API path (e.g., "/api/v2/job_templates/")
80
+ * @param init Fetch options (method, body, headers)
81
+ * @param abortSignal Optional ToolContext.abort signal for cancellation
82
+ */
83
+ request(toolName: string, path: string, init?: RequestInit, abortSignal?: AbortSignal): Promise<Response>;
84
+ }
85
+ /** Circuit breaker state */
86
+ export type BreakerStateKind = "closed" | "open" | "half-open";
87
+ /** Per-tool circuit breaker state */
88
+ export interface BreakerState {
89
+ state: BreakerStateKind;
90
+ failureCount: number;
91
+ cooldownUntil: number | null;
92
+ }
93
+ /**
94
+ * Circuit breaker for per-tool request resilience.
95
+ *
96
+ * - **CLOSED**: Normal operation, requests pass through.
97
+ * - **OPEN**: Tripped after N consecutive failures. Requests rejected immediately.
98
+ * - **HALF-OPEN**: After cooldown elapses, one probe request is allowed.
99
+ * Success → CLOSED, Failure → OPEN again.
100
+ *
101
+ * Uses `Date.now()` for time which works with vitest fake timers
102
+ * (vi.useFakeTimers() mocks Date by default).
103
+ */
104
+ export declare class CircuitBreaker {
105
+ private state;
106
+ private failureCount;
107
+ private cooldownUntil;
108
+ private readonly tripThreshold;
109
+ private readonly cooldownMs;
110
+ /**
111
+ * @param tripThreshold Consecutive failures before opening (default: 5)
112
+ * @param cooldownMs Milliseconds before transitioning OPEN → HALF-OPEN (default: 30_000)
113
+ */
114
+ constructor(tripThreshold?: number, cooldownMs?: number);
115
+ /**
116
+ * Try to acquire permission to make a request through the breaker.
117
+ *
118
+ * Has a side effect: if OPEN and cooldown has elapsed, transitions to
119
+ * HALF-OPEN to allow a probe request.
120
+ *
121
+ * - OPEN: Returns false if still in cooldown. If cooldown elapsed, transitions
122
+ * to HALF-OPEN and returns true (probe allowed).
123
+ * - HALF-OPEN or CLOSED: Returns true.
124
+ */
125
+ tryAcquire(): boolean;
126
+ /** Record a successful request — resets the breaker to CLOSED. */
127
+ recordSuccess(): void;
128
+ /**
129
+ * Record a failed request.
130
+ *
131
+ * Increments the failure counter. If the trip threshold is reached, opens the
132
+ * breaker and sets the cooldown timer.
133
+ *
134
+ * In HALF-OPEN state, a single failure immediately re-opens the breaker.
135
+ */
136
+ recordFailure(): void;
137
+ /** Get the current breaker state (for testing/diagnostics). */
138
+ getState(): BreakerState;
139
+ }
140
+ /**
141
+ * Create an AWX HTTP client with middleware pipeline.
142
+ *
143
+ * @param baseUrl The AAP base URL (e.g., "https://example.com")
144
+ * @param token Bearer token (PAT) for Authorization header
145
+ * @param opts Optional client configuration
146
+ */
147
+ export declare function createClient(baseUrl: string, token: string, opts?: ClientOptions): AwxClient;
148
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkB5C;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAInD;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAID;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAU1F;AA2BD,+BAA+B;AAC/B,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sFAAsF;IACtF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,uDAAuD;IACvD,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,mDAAmD;AACnD,MAAM,WAAW,SAAS;IACxB;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,WAAW,EAClB,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAID,4BAA4B;AAC5B,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE/D,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,gBAAgB,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC;;;OAGG;gBACS,aAAa,SAAI,EAAE,UAAU,SAAS;IAKlD;;;;;;;;;OASG;IACH,UAAU,IAAI,OAAO;IAYrB,kEAAkE;IAClE,aAAa,IAAI,IAAI;IAMrB;;;;;;;OAOG;IACH,aAAa,IAAI,IAAI;IAarB,+DAA+D;IAC/D,QAAQ,IAAI,YAAY;CAOzB;AAID;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,aAAa,GACnB,SAAS,CAgKX"}
package/dist/client.js ADDED
@@ -0,0 +1,334 @@
1
+ /**
2
+ * client.ts — HTTP middleware pipeline for the AWX plugin.
3
+ *
4
+ * Composes five middleware concerns into a single request pipeline:
5
+ * signal → timeout → breaker gate → fetch → retry/backoff
6
+ *
7
+ * ## Pipeline
8
+ *
9
+ * 1. Combine ToolContext.abort signal + timeout signal
10
+ * 2. Circuit breaker gate (per-tool)
11
+ * 3. Native fetch with Authorization header
12
+ * 4. Response handling: 2xx pass, 4xx no retry, 5xx exponential backoff
13
+ *
14
+ * ## Reference
15
+ *
16
+ * - ADR 0006: Connection Resilience Parameters
17
+ * - docs/client-middleware-design.md
18
+ */
19
+ import { MetricsStore } from "./metrics.js";
20
+ /* ── Retry / Backoff parameters ─────────────────────────────────── */
21
+ /** Default max retries (3 retries = 4 total attempts) */
22
+ const DEFAULT_MAX_RETRIES = 3;
23
+ /** Base backoff delay in milliseconds */
24
+ const BACKOFF_BASE_MS = 1000;
25
+ /** Backoff multiplier (exponential) */
26
+ const BACKOFF_MULTIPLIER = 2;
27
+ /** Jitter range: 0 to 50% of calculated delay */
28
+ const JITTER_RATIO = 0.5;
29
+ /* ── Pure utility functions ────────────────────────────────────── */
30
+ /**
31
+ * Calculate the exponential backoff delay for a given retry attempt.
32
+ *
33
+ * Formula: base * multiplier^attempt + random(0, jitterRatio * calculated)
34
+ *
35
+ * Attempt 0 → 1000ms + 0-500ms jitter
36
+ * Attempt 1 → 2000ms + 0-1000ms jitter
37
+ * Attempt 2 → 4000ms + 0-2000ms jitter
38
+ *
39
+ * @param attempt 0-based retry attempt index
40
+ * @returns Delay in milliseconds
41
+ */
42
+ export function calcBackoff(attempt) {
43
+ const base = BACKOFF_BASE_MS * Math.pow(BACKOFF_MULTIPLIER, attempt);
44
+ const jitter = Math.random() * base * JITTER_RATIO;
45
+ return Math.round(base + jitter);
46
+ }
47
+ /**
48
+ * Sleep for a given duration, aborting immediately if the signal fires.
49
+ *
50
+ * Used during retry backoff so that an abort (ToolContext.abort or timeout)
51
+ * cancels the wait immediately instead of waiting for the backoff to elapse.
52
+ *
53
+ * @param ms Duration in milliseconds
54
+ * @param signal Optional AbortSignal — abort listener fires, wait cancels
55
+ */
56
+ export async function sleepWithAbort(ms, signal) {
57
+ if (signal?.aborted) {
58
+ throw signal.reason ?? new DOMException("Aborted", "AbortError");
59
+ }
60
+ return new Promise((resolve, reject) => {
61
+ const onAbort = () => {
62
+ clearTimeout(timer);
63
+ reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
64
+ };
65
+ const timer = setTimeout(() => {
66
+ resolve();
67
+ signal?.removeEventListener("abort", onAbort);
68
+ }, ms);
69
+ if (!signal)
70
+ return;
71
+ signal.addEventListener("abort", onAbort, { once: true });
72
+ });
73
+ }
74
+ /* ── Node 18 Compatibility Helpers ─────────────────────────────── */
75
+ /**
76
+ * Create an AbortSignal that triggers after the specified timeout.
77
+ *
78
+ * Uses `setTimeout` + `AbortController` rather than `AbortSignal.timeout()`
79
+ * for Node 18 compatibility and to ensure compatibility with vitest fake
80
+ * timers (the native `AbortSignal.timeout()` uses internal Node.js timers
81
+ * that cannot be mocked by vitest).
82
+ */
83
+ export function createTimeoutSignal(ms) {
84
+ const controller = new AbortController();
85
+ const timer = setTimeout(() => controller.abort(new DOMException("The operation timed out.", "TimeoutError")), ms);
86
+ return {
87
+ signal: controller.signal,
88
+ clear: () => clearTimeout(timer),
89
+ };
90
+ }
91
+ /**
92
+ * Combine multiple AbortSignals into one — aborts if ANY source signal aborts.
93
+ *
94
+ * Uses `AbortSignal.any()` on Node 20+ (where it is natively available),
95
+ * and falls back to manual event wiring on Node 18.
96
+ */
97
+ function anyAbortSignal(signals) {
98
+ if (typeof AbortSignal.any === "function") {
99
+ return AbortSignal.any(signals);
100
+ }
101
+ const controller = new AbortController();
102
+ for (const signal of signals) {
103
+ if (signal.aborted) {
104
+ controller.abort(signal.reason ?? new DOMException("Aborted", "AbortError"));
105
+ return controller.signal;
106
+ }
107
+ signal.addEventListener("abort", () => {
108
+ controller.abort(signal.reason ?? new DOMException("Aborted", "AbortError"));
109
+ }, { once: true });
110
+ }
111
+ return controller.signal;
112
+ }
113
+ /**
114
+ * Circuit breaker for per-tool request resilience.
115
+ *
116
+ * - **CLOSED**: Normal operation, requests pass through.
117
+ * - **OPEN**: Tripped after N consecutive failures. Requests rejected immediately.
118
+ * - **HALF-OPEN**: After cooldown elapses, one probe request is allowed.
119
+ * Success → CLOSED, Failure → OPEN again.
120
+ *
121
+ * Uses `Date.now()` for time which works with vitest fake timers
122
+ * (vi.useFakeTimers() mocks Date by default).
123
+ */
124
+ export class CircuitBreaker {
125
+ state = "closed";
126
+ failureCount = 0;
127
+ cooldownUntil = null;
128
+ tripThreshold;
129
+ cooldownMs;
130
+ /**
131
+ * @param tripThreshold Consecutive failures before opening (default: 5)
132
+ * @param cooldownMs Milliseconds before transitioning OPEN → HALF-OPEN (default: 30_000)
133
+ */
134
+ constructor(tripThreshold = 5, cooldownMs = 30_000) {
135
+ this.tripThreshold = tripThreshold;
136
+ this.cooldownMs = cooldownMs;
137
+ }
138
+ /**
139
+ * Try to acquire permission to make a request through the breaker.
140
+ *
141
+ * Has a side effect: if OPEN and cooldown has elapsed, transitions to
142
+ * HALF-OPEN to allow a probe request.
143
+ *
144
+ * - OPEN: Returns false if still in cooldown. If cooldown elapsed, transitions
145
+ * to HALF-OPEN and returns true (probe allowed).
146
+ * - HALF-OPEN or CLOSED: Returns true.
147
+ */
148
+ tryAcquire() {
149
+ if (this.state === "open") {
150
+ const now = Date.now();
151
+ if (this.cooldownUntil !== null && now >= this.cooldownUntil) {
152
+ this.state = "half-open";
153
+ return true;
154
+ }
155
+ return false;
156
+ }
157
+ return true;
158
+ }
159
+ /** Record a successful request — resets the breaker to CLOSED. */
160
+ recordSuccess() {
161
+ this.state = "closed";
162
+ this.failureCount = 0;
163
+ this.cooldownUntil = null;
164
+ }
165
+ /**
166
+ * Record a failed request.
167
+ *
168
+ * Increments the failure counter. If the trip threshold is reached, opens the
169
+ * breaker and sets the cooldown timer.
170
+ *
171
+ * In HALF-OPEN state, a single failure immediately re-opens the breaker.
172
+ */
173
+ recordFailure() {
174
+ this.failureCount++;
175
+ if (this.failureCount >= this.tripThreshold) {
176
+ this.state = "open";
177
+ this.cooldownUntil = Date.now() + this.cooldownMs;
178
+ }
179
+ else if (this.state === "half-open") {
180
+ // Half-open failure → back to open with new cooldown
181
+ this.state = "open";
182
+ this.cooldownUntil = Date.now() + this.cooldownMs;
183
+ }
184
+ }
185
+ /** Get the current breaker state (for testing/diagnostics). */
186
+ getState() {
187
+ return {
188
+ state: this.state,
189
+ failureCount: this.failureCount,
190
+ cooldownUntil: this.cooldownUntil,
191
+ };
192
+ }
193
+ }
194
+ /* ── Factory ───────────────────────────────────────────────────── */
195
+ /**
196
+ * Create an AWX HTTP client with middleware pipeline.
197
+ *
198
+ * @param baseUrl The AAP base URL (e.g., "https://example.com")
199
+ * @param token Bearer token (PAT) for Authorization header
200
+ * @param opts Optional client configuration
201
+ */
202
+ export function createClient(baseUrl, token, opts) {
203
+ const normalizedBase = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
204
+ const timeoutMs = opts?.timeoutMs ?? 30_000;
205
+ const maxRetries = opts?.maxRetries ?? DEFAULT_MAX_RETRIES;
206
+ const breakerThreshold = opts?.circuitBreakerThreshold ?? 5;
207
+ const breakerCooldownMs = opts?.circuitBreakerCooldownMs ?? 30_000;
208
+ // Per-tool circuit breakers
209
+ const breakers = new Map();
210
+ /** Get or create a circuit breaker for a tool */
211
+ function breakerFor(toolName) {
212
+ let breaker = breakers.get(toolName);
213
+ if (!breaker) {
214
+ breaker = new CircuitBreaker(breakerThreshold, breakerCooldownMs);
215
+ breakers.set(toolName, breaker);
216
+ }
217
+ return breaker;
218
+ }
219
+ // Shared metrics store instance (use injected store or create new one)
220
+ const metrics = opts?.metricsStore ?? new MetricsStore();
221
+ /** Create a spec-compliant 503 Response for when the circuit breaker is open */
222
+ function circuitOpenResponse() {
223
+ const body = JSON.stringify({
224
+ code: "CIRCUIT_OPEN",
225
+ message: "AWX circuit breaker is open — AAP may be unreachable. Try again in 30s.",
226
+ retryable: true,
227
+ });
228
+ return new Response(body, {
229
+ status: 503,
230
+ statusText: "Circuit breaker open",
231
+ headers: { "Content-Type": "application/json" },
232
+ });
233
+ }
234
+ return {
235
+ async request(toolName, path, init, abortSignal) {
236
+ const start = Date.now();
237
+ // Build full URL
238
+ const url = `${normalizedBase}${path.startsWith("/") ? path.slice(1) : path}`;
239
+ // Combine abort signals: ToolContext.abort + timeout
240
+ const { signal: timeoutSignal, clear: clearTimeout_ } = createTimeoutSignal(timeoutMs);
241
+ const combinedSignal = abortSignal
242
+ ? anyAbortSignal([abortSignal, timeoutSignal])
243
+ : timeoutSignal;
244
+ // Build headers (plain object for testability — fetch accepts both)
245
+ const headers = {
246
+ Accept: "application/json",
247
+ Authorization: `Bearer ${token}`,
248
+ };
249
+ // Merge caller-supplied headers (caller wins on conflicts)
250
+ if (init?.headers) {
251
+ const callerHeaders = init.headers instanceof Headers
252
+ ? Object.fromEntries(init.headers.entries())
253
+ : Array.isArray(init.headers)
254
+ ? Object.fromEntries(init.headers)
255
+ : init.headers;
256
+ Object.assign(headers, callerHeaders);
257
+ }
258
+ const fetchInit = {
259
+ method: init?.method ?? "GET",
260
+ headers,
261
+ body: init?.body,
262
+ signal: combinedSignal,
263
+ };
264
+ const breaker = breakerFor(toolName);
265
+ // ── Track outcome for metrics ──
266
+ let recordedError = false;
267
+ // ── Middleware pipeline ──
268
+ try {
269
+ // ── Retry loop with exponential backoff + circuit breaker ──
270
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
271
+ // ── Circuit breaker gate (checked before every attempt) ──
272
+ if (!breaker.tryAcquire()) {
273
+ // Breaker is open — fail fast, no fetch
274
+ recordedError = true;
275
+ return circuitOpenResponse();
276
+ }
277
+ try {
278
+ const response = await fetch(url, fetchInit);
279
+ // 2xx — success, reset breaker, return immediately
280
+ if (response.ok) {
281
+ breaker.recordSuccess();
282
+ return response;
283
+ }
284
+ // Non-2xx outcome — will record error in finally block
285
+ recordedError = true;
286
+ // 4xx — client error, do NOT retry, do NOT trip circuit breaker
287
+ if (response.status >= 400 && response.status < 500) {
288
+ if (response.status === 401) {
289
+ metrics.recordTokenExpiry(toolName);
290
+ }
291
+ return response;
292
+ }
293
+ // 5xx — server error, record failure, retry if attempts remain
294
+ breaker.recordFailure();
295
+ if (attempt < maxRetries) {
296
+ const delay = calcBackoff(attempt);
297
+ await sleepWithAbort(delay, combinedSignal);
298
+ continue;
299
+ }
300
+ // Max retries exhausted — return the last response
301
+ return response;
302
+ }
303
+ catch (err) {
304
+ // AbortError — propagate immediately, do NOT retry
305
+ if (err instanceof DOMException && err.name === "AbortError") {
306
+ throw err;
307
+ }
308
+ // Network or other error — count as failure, retry if attempts remain
309
+ recordedError = true;
310
+ breaker.recordFailure();
311
+ if (attempt < maxRetries) {
312
+ const delay = calcBackoff(attempt);
313
+ await sleepWithAbort(delay, combinedSignal);
314
+ continue;
315
+ }
316
+ // Max retries exhausted — throw the error
317
+ throw err;
318
+ }
319
+ }
320
+ // Unreachable — all paths above either return or throw
321
+ throw new Error("Unreachable: retry loop exhausted");
322
+ }
323
+ finally {
324
+ const duration = Date.now() - start;
325
+ metrics.recordCall(toolName, duration);
326
+ if (recordedError) {
327
+ metrics.recordError(toolName);
328
+ }
329
+ clearTimeout_();
330
+ }
331
+ },
332
+ };
333
+ }
334
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * AWX Job Detail Output Contract — v1.0
3
+ *
4
+ * Canonical TypeScript representation of the `awx_job_detail.py` v1.0 output schema.
5
+ * Every job-related tool MUST return output matching this contract.
6
+ *
7
+ * This file provides **both**:
8
+ * - Zod schemas for runtime validation (e.g., API response parsing)
9
+ * - Inferred TypeScript types for static type checking
10
+ *
11
+ * The contract has been verified against fixture snapshots in `tests/contracts/__snapshots__/`.
12
+ *
13
+ * ## Schema Fields
14
+ *
15
+ * - **schema_version**: Always "1.0"
16
+ * - **job**: Core job metadata (id, name, status, timestamps, etc.)
17
+ * - **related**: Resolved names (not URLs) for related AWX resources
18
+ * - **host_status_counts**: Count of hosts in each Ansible state — NOT `host_summary`
19
+ * - **derived**: Boolean flags computed from raw data — NOT `extra_vars_summary`
20
+ * - **warnings / errors**: String arrays for user-facing messages
21
+ * - **stdout** (optional): Full job stdout text
22
+ * - **raw_events** (optional): Raw AWX job events array
23
+ *
24
+ * ## Field Naming Convention
25
+ *
26
+ * - Use `host_status_counts` — NOT `host_summary`
27
+ * - Use `derived` — NOT `extra_vars_summary`
28
+ * - `related` fields are resolved names, not raw URLs
29
+ * - `job.limit` is the AWX job limit (host pattern), not a pagination value
30
+ *
31
+ * ## Snapshot Testing
32
+ *
33
+ * Fixture JSON files in `tests/fixtures/` serve as contract snapshots.
34
+ * When the Python `awx_job_detail.py` v1.0 output contract changes,
35
+ * regenerate the fixtures (see README.md for instructions) and re-run
36
+ * tests to verify schema compatibility.
37
+ *
38
+ * ## Regeneration
39
+ *
40
+ * To regenerate the contract snapshots after fixture changes:
41
+ * ```bash
42
+ * python3 scripts/generate-snapshots.py
43
+ * ```
44
+ */
45
+ import { z } from "zod";
46
+ export declare const JobCoreSchema: z.ZodObject<{
47
+ id: z.ZodNumber;
48
+ name: z.ZodString;
49
+ status: z.ZodString;
50
+ failed: z.ZodBoolean;
51
+ job_type: z.ZodString;
52
+ playbook: z.ZodString;
53
+ created: z.ZodString;
54
+ started: z.ZodNullable<z.ZodString>;
55
+ finished: z.ZodNullable<z.ZodString>;
56
+ elapsed: z.ZodNullable<z.ZodNumber>;
57
+ execution_node: z.ZodString;
58
+ controller_node: z.ZodString;
59
+ scm_branch: z.ZodString;
60
+ verbosity: z.ZodNumber;
61
+ forks: z.ZodNullable<z.ZodNumber>;
62
+ limit: z.ZodString;
63
+ }, z.core.$strip>;
64
+ export declare const RelatedSchema: z.ZodObject<{
65
+ inventory_name: z.ZodString;
66
+ project_name: z.ZodString;
67
+ job_template_name: z.ZodString;
68
+ instance_group_name: z.ZodString;
69
+ created_by: z.ZodString;
70
+ credential_names: z.ZodArray<z.ZodString>;
71
+ label_names: z.ZodArray<z.ZodString>;
72
+ }, z.core.$strip>;
73
+ export declare const HostStatusCountsSchema: z.ZodObject<{
74
+ ok: z.ZodNumber;
75
+ failed: z.ZodNumber;
76
+ skipped: z.ZodNumber;
77
+ changed: z.ZodNumber;
78
+ unreachable: z.ZodNumber;
79
+ }, z.core.$strip>;
80
+ export declare const DerivedSchema: z.ZodObject<{
81
+ is_successful: z.ZodBoolean;
82
+ is_failed: z.ZodBoolean;
83
+ has_unreachable_hosts: z.ZodBoolean;
84
+ }, z.core.$strip>;
85
+ export declare const JobDetailOutputSchema: z.ZodObject<{
86
+ schema_version: z.ZodLiteral<"1.0">;
87
+ job: z.ZodObject<{
88
+ id: z.ZodNumber;
89
+ name: z.ZodString;
90
+ status: z.ZodString;
91
+ failed: z.ZodBoolean;
92
+ job_type: z.ZodString;
93
+ playbook: z.ZodString;
94
+ created: z.ZodString;
95
+ started: z.ZodNullable<z.ZodString>;
96
+ finished: z.ZodNullable<z.ZodString>;
97
+ elapsed: z.ZodNullable<z.ZodNumber>;
98
+ execution_node: z.ZodString;
99
+ controller_node: z.ZodString;
100
+ scm_branch: z.ZodString;
101
+ verbosity: z.ZodNumber;
102
+ forks: z.ZodNullable<z.ZodNumber>;
103
+ limit: z.ZodString;
104
+ }, z.core.$strip>;
105
+ related: z.ZodObject<{
106
+ inventory_name: z.ZodString;
107
+ project_name: z.ZodString;
108
+ job_template_name: z.ZodString;
109
+ instance_group_name: z.ZodString;
110
+ created_by: z.ZodString;
111
+ credential_names: z.ZodArray<z.ZodString>;
112
+ label_names: z.ZodArray<z.ZodString>;
113
+ }, z.core.$strip>;
114
+ host_status_counts: z.ZodObject<{
115
+ ok: z.ZodNumber;
116
+ failed: z.ZodNumber;
117
+ skipped: z.ZodNumber;
118
+ changed: z.ZodNumber;
119
+ unreachable: z.ZodNumber;
120
+ }, z.core.$strip>;
121
+ derived: z.ZodObject<{
122
+ is_successful: z.ZodBoolean;
123
+ is_failed: z.ZodBoolean;
124
+ has_unreachable_hosts: z.ZodBoolean;
125
+ }, z.core.$strip>;
126
+ warnings: z.ZodArray<z.ZodString>;
127
+ errors: z.ZodArray<z.ZodString>;
128
+ stdout: z.ZodOptional<z.ZodString>;
129
+ raw_events: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
130
+ }, z.core.$strip>;
131
+ /** Core job metadata fields */
132
+ export type JobCore = z.infer<typeof JobCoreSchema>;
133
+ /** Resolved names for related AWX resources */
134
+ export type Related = z.infer<typeof RelatedSchema>;
135
+ /** Count of hosts in each Ansible state */
136
+ export type HostStatusCounts = z.infer<typeof HostStatusCountsSchema>;
137
+ /** Computed boolean flags */
138
+ export type Derived = z.infer<typeof DerivedSchema>;
139
+ /** Top-level JobDetailOutput contract (v1.0) */
140
+ export type JobDetailOutput = z.infer<typeof JobDetailOutputSchema>;
141
+ //# sourceMappingURL=job-detail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-detail.d.ts","sourceRoot":"","sources":["../../src/contracts/job-detail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;iBAiBxB,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;;;;iBAQxB,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;iBAMjC,CAAC;AAEH,eAAO,MAAM,aAAa;;;;iBAIxB,CAAC;AAIH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUhC,CAAC;AAIH,+BAA+B;AAC/B,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,+CAA+C;AAC/C,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,2CAA2C;AAC3C,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,6BAA6B;AAC7B,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,gDAAgD;AAChD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}