lynkr 8.0.0 → 9.0.1

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 (128) hide show
  1. package/.lynkr/telemetry.db +0 -0
  2. package/.lynkr/telemetry.db-shm +0 -0
  3. package/.lynkr/telemetry.db-wal +0 -0
  4. package/README.md +196 -322
  5. package/lynkr-skill.tar.gz +0 -0
  6. package/package.json +4 -3
  7. package/src/api/openai-router.js +64 -13
  8. package/src/api/providers-handler.js +171 -3
  9. package/src/api/router.js +9 -2
  10. package/src/clients/circuit-breaker.js +10 -247
  11. package/src/clients/codex-process.js +342 -0
  12. package/src/clients/codex-utils.js +143 -0
  13. package/src/clients/databricks.js +210 -63
  14. package/src/clients/resilience.js +540 -0
  15. package/src/clients/retry.js +22 -167
  16. package/src/clients/standard-tools.js +23 -0
  17. package/src/config/index.js +77 -0
  18. package/src/context/compression.js +42 -9
  19. package/src/context/distill.js +492 -0
  20. package/src/orchestrator/index.js +48 -8
  21. package/src/routing/complexity-analyzer.js +258 -5
  22. package/src/routing/index.js +12 -2
  23. package/src/routing/latency-tracker.js +148 -0
  24. package/src/routing/model-tiers.js +2 -0
  25. package/src/routing/quality-scorer.js +113 -0
  26. package/src/routing/telemetry.js +464 -0
  27. package/src/server.js +13 -12
  28. package/src/tools/code-graph.js +538 -0
  29. package/src/tools/code-mode.js +304 -0
  30. package/src/tools/index.js +4 -0
  31. package/src/tools/lazy-loader.js +18 -0
  32. package/src/tools/mcp-remote.js +7 -0
  33. package/src/tools/smart-selection.js +11 -0
  34. package/src/tools/tinyfish.js +358 -0
  35. package/src/tools/truncate.js +1 -0
  36. package/src/utils/payload.js +206 -0
  37. package/src/utils/perf-timer.js +80 -0
  38. package/.github/FUNDING.yml +0 -15
  39. package/.github/workflows/README.md +0 -215
  40. package/.github/workflows/ci.yml +0 -69
  41. package/.github/workflows/index.yml +0 -62
  42. package/.github/workflows/web-tools-tests.yml +0 -56
  43. package/CITATIONS.bib +0 -6
  44. package/DEPLOYMENT.md +0 -1001
  45. package/LYNKR-TUI-PLAN.md +0 -984
  46. package/PERFORMANCE-REPORT.md +0 -866
  47. package/PLAN-per-client-model-routing.md +0 -252
  48. package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
  49. package/docs/BingSiteAuth.xml +0 -4
  50. package/docs/docs-style.css +0 -478
  51. package/docs/docs.html +0 -198
  52. package/docs/google5be250e608e6da39.html +0 -1
  53. package/docs/index.html +0 -577
  54. package/docs/index.md +0 -584
  55. package/docs/robots.txt +0 -4
  56. package/docs/sitemap.xml +0 -44
  57. package/docs/style.css +0 -1223
  58. package/docs/toon-integration-spec.md +0 -130
  59. package/documentation/README.md +0 -101
  60. package/documentation/api.md +0 -806
  61. package/documentation/claude-code-cli.md +0 -679
  62. package/documentation/codex-cli.md +0 -397
  63. package/documentation/contributing.md +0 -571
  64. package/documentation/cursor-integration.md +0 -734
  65. package/documentation/docker.md +0 -874
  66. package/documentation/embeddings.md +0 -762
  67. package/documentation/faq.md +0 -713
  68. package/documentation/features.md +0 -403
  69. package/documentation/headroom.md +0 -519
  70. package/documentation/installation.md +0 -758
  71. package/documentation/memory-system.md +0 -476
  72. package/documentation/production.md +0 -636
  73. package/documentation/providers.md +0 -1009
  74. package/documentation/routing.md +0 -476
  75. package/documentation/testing.md +0 -629
  76. package/documentation/token-optimization.md +0 -325
  77. package/documentation/tools.md +0 -697
  78. package/documentation/troubleshooting.md +0 -969
  79. package/final-test.js +0 -33
  80. package/headroom-sidecar/config.py +0 -93
  81. package/headroom-sidecar/requirements.txt +0 -14
  82. package/headroom-sidecar/server.py +0 -451
  83. package/monitor-agents.sh +0 -31
  84. package/scripts/audit-log-reader.js +0 -399
  85. package/scripts/compact-dictionary.js +0 -204
  86. package/scripts/test-deduplication.js +0 -448
  87. package/src/db/database.sqlite +0 -0
  88. package/te +0 -11622
  89. package/test/README.md +0 -212
  90. package/test/azure-openai-config.test.js +0 -213
  91. package/test/azure-openai-error-resilience.test.js +0 -238
  92. package/test/azure-openai-format-conversion.test.js +0 -354
  93. package/test/azure-openai-integration.test.js +0 -287
  94. package/test/azure-openai-routing.test.js +0 -175
  95. package/test/azure-openai-streaming.test.js +0 -171
  96. package/test/bedrock-integration.test.js +0 -457
  97. package/test/comprehensive-test-suite.js +0 -928
  98. package/test/config-validation.test.js +0 -207
  99. package/test/cursor-integration.test.js +0 -484
  100. package/test/format-conversion.test.js +0 -578
  101. package/test/hybrid-routing-integration.test.js +0 -269
  102. package/test/hybrid-routing-performance.test.js +0 -428
  103. package/test/llamacpp-integration.test.js +0 -882
  104. package/test/lmstudio-integration.test.js +0 -347
  105. package/test/memory/extractor.test.js +0 -398
  106. package/test/memory/retriever.test.js +0 -613
  107. package/test/memory/retriever.test.js.bak +0 -585
  108. package/test/memory/search.test.js +0 -537
  109. package/test/memory/search.test.js.bak +0 -389
  110. package/test/memory/store.test.js +0 -344
  111. package/test/memory/store.test.js.bak +0 -312
  112. package/test/memory/surprise.test.js +0 -300
  113. package/test/memory-performance.test.js +0 -472
  114. package/test/openai-integration.test.js +0 -683
  115. package/test/openrouter-error-resilience.test.js +0 -418
  116. package/test/passthrough-mode.test.js +0 -385
  117. package/test/performance-benchmark.js +0 -351
  118. package/test/performance-tests.js +0 -528
  119. package/test/routing.test.js +0 -225
  120. package/test/toon-compression.test.js +0 -131
  121. package/test/web-tools.test.js +0 -329
  122. package/test-agents-simple.js +0 -43
  123. package/test-cli-connection.sh +0 -33
  124. package/test-learning-unit.js +0 -126
  125. package/test-learning.js +0 -112
  126. package/test-parallel-agents.sh +0 -124
  127. package/test-parallel-direct.js +0 -155
  128. package/test-subagents.sh +0 -117
@@ -0,0 +1,540 @@
1
+ const {
2
+ circuitBreaker,
3
+ ConsecutiveBreaker,
4
+ retry,
5
+ handleAll,
6
+ ExponentialBackoff,
7
+ bulkhead,
8
+ timeout,
9
+ wrap,
10
+ CircuitState,
11
+ BrokenCircuitError,
12
+ BulkheadRejectedError,
13
+ TaskCancelledError,
14
+ } = require("cockatiel");
15
+ const logger = require("../logger");
16
+
17
+ // Re-use the existing STATE constant shape
18
+ const STATE = {
19
+ CLOSED: "CLOSED",
20
+ OPEN: "OPEN",
21
+ HALF_OPEN: "HALF_OPEN",
22
+ };
23
+
24
+ /**
25
+ * Map Cockatiel CircuitState enum to our string states
26
+ */
27
+ function mapCircuitState(cockatielState) {
28
+ switch (cockatielState) {
29
+ case CircuitState.Closed:
30
+ return STATE.CLOSED;
31
+ case CircuitState.Open:
32
+ return STATE.OPEN;
33
+ case CircuitState.HalfOpen:
34
+ return STATE.HALF_OPEN;
35
+ default:
36
+ return STATE.CLOSED;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Circuit breaker error — same interface as the original
42
+ */
43
+ class CircuitBreakerError extends Error {
44
+ constructor(message, retryAfter) {
45
+ super(message);
46
+ this.name = "CircuitBreakerError";
47
+ this.retryAfter = retryAfter;
48
+ this.code = "circuit_breaker_open";
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Cockatiel-backed CircuitBreaker adapter.
54
+ * Preserves the same API as the hand-rolled CircuitBreaker class.
55
+ */
56
+ class CockatielCircuitBreaker {
57
+ constructor(name, options = {}) {
58
+ this.name = name;
59
+
60
+ // Configuration (same defaults as original)
61
+ this.failureThreshold = options.failureThreshold || 5;
62
+ this.successThreshold = options.successThreshold || 2;
63
+ this.halfOpenAfter = options.timeout || 60000;
64
+
65
+ // Stats tracking (same shape as original)
66
+ this.stats = {
67
+ totalRequests: 0,
68
+ totalFailures: 0,
69
+ totalSuccesses: 0,
70
+ totalRejected: 0,
71
+ };
72
+
73
+ // Internal counters for getState() compatibility
74
+ this._failureCount = 0;
75
+ this._successCount = 0;
76
+ this._lastStateChange = Date.now();
77
+ this._nextAttempt = Date.now();
78
+
79
+ // Create the Cockatiel circuit breaker policy
80
+ this._policy = circuitBreaker(handleAll, {
81
+ breaker: new ConsecutiveBreaker(this.failureThreshold),
82
+ halfOpenAfter: this.halfOpenAfter,
83
+ });
84
+
85
+ // Wire up events for logging and state tracking
86
+ this._policy.onBreak(() => {
87
+ this._lastStateChange = Date.now();
88
+ this._nextAttempt = Date.now() + this.halfOpenAfter;
89
+ logger.warn(
90
+ {
91
+ circuitBreaker: this.name,
92
+ retryAfter: this.halfOpenAfter,
93
+ },
94
+ "Circuit breaker opened - failing fast"
95
+ );
96
+ });
97
+
98
+ this._policy.onReset(() => {
99
+ this._failureCount = 0;
100
+ this._successCount = 0;
101
+ this._lastStateChange = Date.now();
102
+ logger.info(
103
+ {
104
+ circuitBreaker: this.name,
105
+ },
106
+ "Circuit breaker closed - normal operation resumed"
107
+ );
108
+ });
109
+
110
+ this._policy.onHalfOpen(() => {
111
+ this._successCount = 0;
112
+ this._lastStateChange = Date.now();
113
+ logger.info(
114
+ {
115
+ circuitBreaker: this.name,
116
+ },
117
+ "Circuit breaker half-open - testing service recovery"
118
+ );
119
+ });
120
+
121
+ this._policy.onSuccess(() => {
122
+ this.stats.totalSuccesses++;
123
+ this._failureCount = 0;
124
+ if (this.state === STATE.HALF_OPEN) {
125
+ this._successCount++;
126
+ }
127
+ });
128
+
129
+ this._policy.onFailure(() => {
130
+ this.stats.totalFailures++;
131
+ this._failureCount++;
132
+ this._successCount = 0;
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Current state as a string
138
+ */
139
+ get state() {
140
+ return mapCircuitState(this._policy.state);
141
+ }
142
+
143
+ get failureCount() {
144
+ return this._failureCount;
145
+ }
146
+
147
+ get successCount() {
148
+ return this._successCount;
149
+ }
150
+
151
+ /**
152
+ * Execute function with circuit breaker protection.
153
+ * Translates BrokenCircuitError → CircuitBreakerError for consumers.
154
+ */
155
+ async execute(fn) {
156
+ this.stats.totalRequests++;
157
+
158
+ try {
159
+ return await this._policy.execute(fn);
160
+ } catch (err) {
161
+ if (err instanceof BrokenCircuitError) {
162
+ this.stats.totalRejected++;
163
+ const retryAfter = Math.max(0, this._nextAttempt - Date.now());
164
+ throw new CircuitBreakerError(
165
+ `Circuit breaker ${this.name} is OPEN`,
166
+ retryAfter
167
+ );
168
+ }
169
+ throw err;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Get current state — same shape as original
175
+ */
176
+ getState() {
177
+ return {
178
+ name: this.name,
179
+ state: this.state,
180
+ failureCount: this._failureCount,
181
+ successCount: this._successCount,
182
+ nextAttempt: this._nextAttempt,
183
+ lastStateChange: this._lastStateChange,
184
+ stats: { ...this.stats },
185
+ };
186
+ }
187
+
188
+ /**
189
+ * Manually reset circuit breaker
190
+ */
191
+ reset() {
192
+ // Cockatiel doesn't expose a public reset, but we can create a fresh policy
193
+ this._failureCount = 0;
194
+ this._successCount = 0;
195
+ this._lastStateChange = Date.now();
196
+
197
+ // Recreate the policy to reset state
198
+ const oldPolicy = this._policy;
199
+ this._policy = circuitBreaker(handleAll, {
200
+ breaker: new ConsecutiveBreaker(this.failureThreshold),
201
+ halfOpenAfter: this.halfOpenAfter,
202
+ });
203
+
204
+ // Re-wire events
205
+ this._policy.onBreak(() => {
206
+ this._lastStateChange = Date.now();
207
+ this._nextAttempt = Date.now() + this.halfOpenAfter;
208
+ logger.warn(
209
+ { circuitBreaker: this.name, retryAfter: this.halfOpenAfter },
210
+ "Circuit breaker opened - failing fast"
211
+ );
212
+ });
213
+ this._policy.onReset(() => {
214
+ this._failureCount = 0;
215
+ this._successCount = 0;
216
+ this._lastStateChange = Date.now();
217
+ logger.info({ circuitBreaker: this.name }, "Circuit breaker closed - normal operation resumed");
218
+ });
219
+ this._policy.onHalfOpen(() => {
220
+ this._successCount = 0;
221
+ this._lastStateChange = Date.now();
222
+ logger.info({ circuitBreaker: this.name }, "Circuit breaker half-open - testing service recovery");
223
+ });
224
+ this._policy.onSuccess(() => {
225
+ this.stats.totalSuccesses++;
226
+ this._failureCount = 0;
227
+ if (this.state === STATE.HALF_OPEN) {
228
+ this._successCount++;
229
+ }
230
+ });
231
+ this._policy.onFailure(() => {
232
+ this.stats.totalFailures++;
233
+ this._failureCount++;
234
+ this._successCount = 0;
235
+ });
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Registry — same Map-based pattern as original CircuitBreakerRegistry
241
+ */
242
+ class CockatielRegistry {
243
+ constructor() {
244
+ this.breakers = new Map();
245
+ }
246
+
247
+ get(name, options) {
248
+ if (!this.breakers.has(name)) {
249
+ this.breakers.set(name, new CockatielCircuitBreaker(name, options));
250
+ }
251
+ return this.breakers.get(name);
252
+ }
253
+
254
+ getAll() {
255
+ return Array.from(this.breakers.values()).map((breaker) => breaker.getState());
256
+ }
257
+
258
+ resetAll() {
259
+ for (const breaker of this.breakers.values()) {
260
+ breaker.reset();
261
+ }
262
+ }
263
+ }
264
+
265
+ // Singleton registry
266
+ let registry = null;
267
+
268
+ function getCockatielRegistry() {
269
+ if (!registry) {
270
+ registry = new CockatielRegistry();
271
+ }
272
+ return registry;
273
+ }
274
+
275
+ // --- Retry adapter ---
276
+
277
+ const DEFAULT_RETRY_CONFIG = {
278
+ maxRetries: 3,
279
+ initialDelay: 1000,
280
+ maxDelay: 30000,
281
+ backoffMultiplier: 2,
282
+ jitterFactor: 0.1,
283
+ retryableStatuses: [429, 500, 502, 503, 504],
284
+ retryableErrors: ["ECONNRESET", "ETIMEDOUT", "ENOTFOUND", "ENETUNREACH", "ECONNREFUSED"],
285
+ };
286
+
287
+ /**
288
+ * Check if error/response is retryable (same logic as original)
289
+ */
290
+ function isRetryableCheck(error, response, config) {
291
+ if (response && config.retryableStatuses.includes(response.status)) {
292
+ return true;
293
+ }
294
+ if (error && error.code && config.retryableErrors.includes(error.code)) {
295
+ return true;
296
+ }
297
+ if (error && error.cause?.code && config.retryableErrors.includes(error.cause.code)) {
298
+ return true;
299
+ }
300
+ if (error && (error.name === "FetchError" || error.name === "AbortError")) {
301
+ return true;
302
+ }
303
+ return false;
304
+ }
305
+
306
+ /**
307
+ * Detect if this is a cold start
308
+ */
309
+ function detectColdStart(startTime, endTime, threshold = 5000) {
310
+ return (endTime - startTime) > threshold;
311
+ }
312
+
313
+ /**
314
+ * Sleep helper
315
+ */
316
+ function sleep(ms) {
317
+ return new Promise((resolve) => setTimeout(resolve, ms));
318
+ }
319
+
320
+ /**
321
+ * withCockatielRetry — drop-in replacement for withRetry.
322
+ *
323
+ * Same signature: withCockatielRetry(fn, options)
324
+ * - fn(attempt) is called with the attempt number (0-based)
325
+ * - Returns last response when all retries exhausted (matching original behavior)
326
+ * - Preserves 429 Retry-After header parsing
327
+ */
328
+ async function withCockatielRetry(fn, options = {}) {
329
+ const config = { ...DEFAULT_RETRY_CONFIG, ...options };
330
+ let lastResponse = null;
331
+ let attempt = 0;
332
+
333
+ const retryPolicy = retry(handleAll, {
334
+ maxAttempts: config.maxRetries,
335
+ backoff: new ExponentialBackoff({
336
+ initialDelay: config.initialDelay,
337
+ maxDelay: config.maxDelay,
338
+ exponent: config.backoffMultiplier,
339
+ }),
340
+ });
341
+
342
+ retryPolicy.onRetry(({ attempt: retryAttempt }) => {
343
+ logger.warn(
344
+ { attempt: retryAttempt },
345
+ "Retrying request"
346
+ );
347
+ });
348
+
349
+ // We use a manual approach that mirrors the original withRetry exactly,
350
+ // wrapping Cockatiel's retry for exponential backoff but keeping the
351
+ // response-status-check and 429-Retry-After logic intact.
352
+ // This ensures 100% behavioral compatibility.
353
+
354
+ for (attempt = 0; attempt <= config.maxRetries; attempt++) {
355
+ const startTime = Date.now();
356
+
357
+ try {
358
+ const result = await fn(attempt);
359
+ const endTime = Date.now();
360
+
361
+ if (detectColdStart(startTime, endTime)) {
362
+ logger.warn(
363
+ { attempt, duration: endTime - startTime },
364
+ "Potential cold start detected"
365
+ );
366
+ }
367
+
368
+ // Check if response indicates we should retry
369
+ if (result && isRetryableCheck(null, result, config) && attempt < config.maxRetries) {
370
+ lastResponse = result;
371
+
372
+ if (result.status === 429) {
373
+ const retryAfter = result.headers?.get?.("retry-after");
374
+ let delay;
375
+
376
+ if (retryAfter) {
377
+ const retryAfterNum = parseInt(retryAfter, 10);
378
+ if (!isNaN(retryAfterNum)) {
379
+ delay = retryAfterNum * 1000;
380
+ } else {
381
+ const retryAfterDate = new Date(retryAfter);
382
+ delay = retryAfterDate.getTime() - Date.now();
383
+ }
384
+ } else {
385
+ // Exponential backoff with longer delays for rate limiting
386
+ const baseDelay = 2000 * Math.pow(config.backoffMultiplier, attempt);
387
+ const cappedDelay = Math.min(baseDelay, 60000);
388
+ const jitter = cappedDelay * config.jitterFactor * (Math.random() * 2 - 1);
389
+ delay = Math.max(0, cappedDelay + jitter);
390
+ }
391
+
392
+ logger.warn(
393
+ { attempt, delay, retryAfter: retryAfter || "not specified" },
394
+ "Rate limited (429), retrying after delay"
395
+ );
396
+
397
+ await sleep(delay);
398
+ continue;
399
+ }
400
+
401
+ // Regular retry with exponential backoff
402
+ const baseDelay = config.initialDelay * Math.pow(config.backoffMultiplier, attempt);
403
+ const cappedDelay = Math.min(baseDelay, config.maxDelay);
404
+ const jitter = cappedDelay * config.jitterFactor * (Math.random() * 2 - 1);
405
+ const delay = Math.max(0, cappedDelay + jitter);
406
+
407
+ logger.warn(
408
+ { attempt, status: result.status, delay },
409
+ "Request failed, retrying with backoff"
410
+ );
411
+
412
+ await sleep(delay);
413
+ continue;
414
+ }
415
+
416
+ return result;
417
+ } catch (error) {
418
+ const endTime = Date.now();
419
+
420
+ if (detectColdStart(startTime, endTime)) {
421
+ logger.warn(
422
+ { attempt, duration: endTime - startTime, error: error.message },
423
+ "Potential cold start with error detected"
424
+ );
425
+ }
426
+
427
+ if (isRetryableCheck(error, null, config) && attempt < config.maxRetries) {
428
+ const baseDelay = config.initialDelay * Math.pow(config.backoffMultiplier, attempt);
429
+ const cappedDelay = Math.min(baseDelay, config.maxDelay);
430
+ const jitter = cappedDelay * config.jitterFactor * (Math.random() * 2 - 1);
431
+ const delay = Math.max(0, cappedDelay + jitter);
432
+
433
+ logger.warn(
434
+ { attempt, error: error.message, code: error.code, delay },
435
+ "Request error, retrying with backoff"
436
+ );
437
+
438
+ await sleep(delay);
439
+ continue;
440
+ }
441
+
442
+ throw error;
443
+ }
444
+ }
445
+
446
+ // Max retries exceeded
447
+ if (lastResponse) {
448
+ logger.error(
449
+ { status: lastResponse.status, maxRetries: config.maxRetries },
450
+ "Max retries exceeded"
451
+ );
452
+ return lastResponse;
453
+ }
454
+
455
+ throw new Error("Retry logic failed unexpectedly");
456
+ }
457
+
458
+ // --- Composed provider policy ---
459
+
460
+ /**
461
+ * Create a composed policy: retry + circuit breaker + timeout
462
+ */
463
+ function createProviderPolicy(name, options = {}) {
464
+ const cbOptions = {
465
+ failureThreshold: options.failureThreshold || 5,
466
+ halfOpenAfter: options.halfOpenAfter || 60000,
467
+ };
468
+
469
+ const retryMaxAttempts = options.retryMaxAttempts || 3;
470
+ const timeoutMs = options.timeout || 120000;
471
+
472
+ const cb = circuitBreaker(handleAll, {
473
+ breaker: new ConsecutiveBreaker(cbOptions.failureThreshold),
474
+ halfOpenAfter: cbOptions.halfOpenAfter,
475
+ });
476
+
477
+ const retryPolicy = retry(handleAll, {
478
+ maxAttempts: retryMaxAttempts,
479
+ backoff: new ExponentialBackoff({
480
+ initialDelay: 1000,
481
+ maxDelay: 30000,
482
+ exponent: 2,
483
+ }),
484
+ });
485
+
486
+ const timeoutPolicy = timeout(timeoutMs, "aggressive");
487
+
488
+ retryPolicy.onRetry(({ attempt }) => {
489
+ logger.warn({ provider: name, attempt }, "Retrying provider request");
490
+ });
491
+
492
+ cb.onBreak(() => {
493
+ logger.warn({ provider: name }, "Provider circuit opened");
494
+ });
495
+
496
+ cb.onReset(() => {
497
+ logger.info({ provider: name }, "Provider circuit closed");
498
+ });
499
+
500
+ cb.onHalfOpen(() => {
501
+ logger.info({ provider: name }, "Provider circuit half-open");
502
+ });
503
+
504
+ return wrap(retryPolicy, cb, timeoutPolicy);
505
+ }
506
+
507
+ // --- Bulkhead adapter ---
508
+
509
+ /**
510
+ * Create a Cockatiel bulkhead (replaces Semaphore)
511
+ */
512
+ function createBulkhead(options = {}) {
513
+ const maxConcurrent = options.maxConcurrent || 2;
514
+ const maxQueue = options.maxQueue || 50;
515
+ return bulkhead(maxConcurrent, maxQueue);
516
+ }
517
+
518
+ module.exports = {
519
+ // Circuit breaker
520
+ CockatielCircuitBreaker,
521
+ CircuitBreakerError,
522
+ CockatielRegistry,
523
+ getCockatielRegistry,
524
+ STATE,
525
+
526
+ // Retry
527
+ withCockatielRetry,
528
+ DEFAULT_RETRY_CONFIG,
529
+
530
+ // Composed
531
+ createProviderPolicy,
532
+
533
+ // Bulkhead
534
+ createBulkhead,
535
+
536
+ // Re-exports for internal use
537
+ BrokenCircuitError,
538
+ BulkheadRejectedError,
539
+ TaskCancelledError,
540
+ };