@supaku/agentfactory-linear 0.7.18 → 0.7.19

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.
@@ -0,0 +1,292 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { CircuitBreaker, DEFAULT_CIRCUIT_BREAKER_CONFIG } from './circuit-breaker.js';
3
+ import { CircuitOpenError } from './errors.js';
4
+ describe('CircuitBreaker', () => {
5
+ beforeEach(() => {
6
+ vi.useFakeTimers();
7
+ });
8
+ afterEach(() => {
9
+ vi.useRealTimers();
10
+ });
11
+ // ========================================================================
12
+ // Construction & defaults
13
+ // ========================================================================
14
+ it('starts in closed state', () => {
15
+ const cb = new CircuitBreaker();
16
+ expect(cb.state).toBe('closed');
17
+ });
18
+ it('uses default config when none provided', () => {
19
+ const cb = new CircuitBreaker();
20
+ const status = cb.getStatus();
21
+ expect(status.state).toBe('closed');
22
+ expect(status.consecutiveFailures).toBe(0);
23
+ expect(status.currentResetTimeoutMs).toBe(DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs);
24
+ });
25
+ it('accepts custom config', () => {
26
+ const cb = new CircuitBreaker({ failureThreshold: 5, resetTimeoutMs: 30_000 });
27
+ // Trip it 4 times — should still be closed
28
+ for (let i = 0; i < 4; i++) {
29
+ cb.recordAuthFailure(401);
30
+ }
31
+ expect(cb.state).toBe('closed');
32
+ // 5th failure trips it
33
+ cb.recordAuthFailure(401);
34
+ expect(cb.state).toBe('open');
35
+ });
36
+ // ========================================================================
37
+ // canProceed
38
+ // ========================================================================
39
+ it('allows calls when closed', () => {
40
+ const cb = new CircuitBreaker();
41
+ expect(cb.canProceed()).toBe(true);
42
+ });
43
+ it('blocks calls when open', () => {
44
+ const cb = new CircuitBreaker({ failureThreshold: 1 });
45
+ cb.recordAuthFailure(401);
46
+ expect(cb.state).toBe('open');
47
+ expect(cb.canProceed()).toBe(false);
48
+ });
49
+ it('allows one probe call when half-open', () => {
50
+ const cb = new CircuitBreaker({ failureThreshold: 1, resetTimeoutMs: 1000 });
51
+ cb.recordAuthFailure(401);
52
+ expect(cb.state).toBe('open');
53
+ // Advance past reset timeout
54
+ vi.advanceTimersByTime(1001);
55
+ expect(cb.state).toBe('half-open');
56
+ // First call should be allowed (probe)
57
+ expect(cb.canProceed()).toBe(true);
58
+ // Second call should be blocked (probe already in-flight)
59
+ expect(cb.canProceed()).toBe(false);
60
+ });
61
+ // ========================================================================
62
+ // State transitions: closed → open
63
+ // ========================================================================
64
+ it('trips after consecutive auth failures reach threshold', () => {
65
+ const cb = new CircuitBreaker({ failureThreshold: 2 });
66
+ cb.recordAuthFailure(400);
67
+ expect(cb.state).toBe('closed');
68
+ cb.recordAuthFailure(401);
69
+ expect(cb.state).toBe('open');
70
+ });
71
+ it('ignores non-auth status codes for failure counting', () => {
72
+ const cb = new CircuitBreaker({ failureThreshold: 2 });
73
+ cb.recordAuthFailure(500); // not in authErrorCodes
74
+ cb.recordAuthFailure(502);
75
+ expect(cb.state).toBe('closed');
76
+ expect(cb.getStatus().consecutiveFailures).toBe(0);
77
+ });
78
+ it('resets failure count on success', () => {
79
+ const cb = new CircuitBreaker({ failureThreshold: 3 });
80
+ cb.recordAuthFailure(401); // 1
81
+ cb.recordAuthFailure(403); // 2
82
+ cb.recordSuccess(); // reset to 0
83
+ cb.recordAuthFailure(400); // 1 — should NOT trip
84
+ expect(cb.state).toBe('closed');
85
+ });
86
+ // ========================================================================
87
+ // State transitions: open → half-open
88
+ // ========================================================================
89
+ it('transitions from open to half-open after resetTimeoutMs', () => {
90
+ const cb = new CircuitBreaker({ failureThreshold: 1, resetTimeoutMs: 5000 });
91
+ cb.recordAuthFailure(401);
92
+ expect(cb.state).toBe('open');
93
+ // Not enough time
94
+ vi.advanceTimersByTime(4999);
95
+ expect(cb.state).toBe('open');
96
+ // Exactly enough time
97
+ vi.advanceTimersByTime(1);
98
+ expect(cb.state).toBe('half-open');
99
+ });
100
+ // ========================================================================
101
+ // State transitions: half-open → closed (probe success)
102
+ // ========================================================================
103
+ it('closes circuit on successful probe in half-open', () => {
104
+ const cb = new CircuitBreaker({ failureThreshold: 1, resetTimeoutMs: 1000 });
105
+ cb.recordAuthFailure(401);
106
+ vi.advanceTimersByTime(1001);
107
+ expect(cb.state).toBe('half-open');
108
+ // Probe succeeds
109
+ cb.canProceed(); // acquire probe
110
+ cb.recordSuccess();
111
+ expect(cb.state).toBe('closed');
112
+ expect(cb.getStatus().consecutiveFailures).toBe(0);
113
+ });
114
+ // ========================================================================
115
+ // State transitions: half-open → open (probe failure + exponential backoff)
116
+ // ========================================================================
117
+ it('reopens circuit on failed probe with exponential backoff', () => {
118
+ const cb = new CircuitBreaker({
119
+ failureThreshold: 1,
120
+ resetTimeoutMs: 1000,
121
+ maxResetTimeoutMs: 16000,
122
+ backoffMultiplier: 2,
123
+ });
124
+ // First trip
125
+ cb.recordAuthFailure(401);
126
+ expect(cb.state).toBe('open');
127
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(1000);
128
+ // Wait for half-open
129
+ vi.advanceTimersByTime(1001);
130
+ expect(cb.state).toBe('half-open');
131
+ // Probe fails → reopen with backoff
132
+ cb.canProceed();
133
+ cb.recordAuthFailure(401);
134
+ expect(cb.state).toBe('open');
135
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(2000); // 1000 * 2
136
+ // Wait 2000ms for next half-open
137
+ vi.advanceTimersByTime(2001);
138
+ expect(cb.state).toBe('half-open');
139
+ // Probe fails again → further backoff
140
+ cb.canProceed();
141
+ cb.recordAuthFailure(401);
142
+ expect(cb.state).toBe('open');
143
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(4000); // 2000 * 2
144
+ });
145
+ it('caps reset timeout at maxResetTimeoutMs', () => {
146
+ const cb = new CircuitBreaker({
147
+ failureThreshold: 1,
148
+ resetTimeoutMs: 1000,
149
+ maxResetTimeoutMs: 3000,
150
+ backoffMultiplier: 2,
151
+ });
152
+ // Trip → open (1000ms)
153
+ cb.recordAuthFailure(401);
154
+ vi.advanceTimersByTime(1001);
155
+ // Probe fail → 2000ms
156
+ cb.canProceed();
157
+ cb.recordAuthFailure(401);
158
+ vi.advanceTimersByTime(2001);
159
+ // Probe fail → 3000ms (capped at max)
160
+ cb.canProceed();
161
+ cb.recordAuthFailure(401);
162
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(3000);
163
+ vi.advanceTimersByTime(3001);
164
+ // Probe fail → still 3000ms (capped)
165
+ cb.canProceed();
166
+ cb.recordAuthFailure(401);
167
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(3000);
168
+ });
169
+ it('resets backoff on successful recovery', () => {
170
+ const cb = new CircuitBreaker({
171
+ failureThreshold: 1,
172
+ resetTimeoutMs: 1000,
173
+ maxResetTimeoutMs: 16000,
174
+ backoffMultiplier: 2,
175
+ });
176
+ // Trip and backoff to 2000ms
177
+ cb.recordAuthFailure(401);
178
+ vi.advanceTimersByTime(1001);
179
+ cb.canProceed();
180
+ cb.recordAuthFailure(401);
181
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(2000);
182
+ // Recover
183
+ vi.advanceTimersByTime(2001);
184
+ cb.canProceed();
185
+ cb.recordSuccess();
186
+ expect(cb.state).toBe('closed');
187
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(1000); // reset to original
188
+ });
189
+ // ========================================================================
190
+ // reset()
191
+ // ========================================================================
192
+ it('reset() returns to closed from any state', () => {
193
+ const cb = new CircuitBreaker({ failureThreshold: 1 });
194
+ cb.recordAuthFailure(401);
195
+ expect(cb.state).toBe('open');
196
+ cb.reset();
197
+ expect(cb.state).toBe('closed');
198
+ expect(cb.getStatus().consecutiveFailures).toBe(0);
199
+ expect(cb.getStatus().currentResetTimeoutMs).toBe(DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs);
200
+ });
201
+ // ========================================================================
202
+ // isAuthError
203
+ // ========================================================================
204
+ it('detects auth errors by HTTP status code', () => {
205
+ const cb = new CircuitBreaker();
206
+ expect(cb.isAuthError({ status: 400 })).toBe(true);
207
+ expect(cb.isAuthError({ status: 401 })).toBe(true);
208
+ expect(cb.isAuthError({ status: 403 })).toBe(true);
209
+ expect(cb.isAuthError({ statusCode: 401 })).toBe(true);
210
+ expect(cb.isAuthError({ response: { status: 403 } })).toBe(true);
211
+ });
212
+ it('does not flag non-auth status codes', () => {
213
+ const cb = new CircuitBreaker();
214
+ expect(cb.isAuthError({ status: 200 })).toBe(false);
215
+ expect(cb.isAuthError({ status: 404 })).toBe(false);
216
+ expect(cb.isAuthError({ status: 500 })).toBe(false);
217
+ expect(cb.isAuthError({ status: 429 })).toBe(false); // rate limit is handled separately
218
+ });
219
+ it('detects GraphQL RATELIMITED error code', () => {
220
+ const cb = new CircuitBreaker();
221
+ // Direct extensions.code
222
+ expect(cb.isAuthError({ extensions: { code: 'RATELIMITED' } })).toBe(true);
223
+ // Nested errors array
224
+ expect(cb.isAuthError({
225
+ errors: [{ extensions: { code: 'RATELIMITED' } }],
226
+ })).toBe(true);
227
+ // In response body
228
+ expect(cb.isAuthError({
229
+ response: {
230
+ body: {
231
+ errors: [{ extensions: { code: 'RATELIMITED' } }],
232
+ },
233
+ },
234
+ })).toBe(true);
235
+ // In response data (alternative shape)
236
+ expect(cb.isAuthError({
237
+ response: {
238
+ data: {
239
+ errors: [{ extensions: { code: 'RATELIMITED' } }],
240
+ },
241
+ },
242
+ })).toBe(true);
243
+ });
244
+ it('detects auth errors by message pattern', () => {
245
+ const cb = new CircuitBreaker();
246
+ expect(cb.isAuthError({ message: 'Access denied - Only app users can create agent activities' })).toBe(true);
247
+ expect(cb.isAuthError({ message: 'Unauthorized request' })).toBe(true);
248
+ expect(cb.isAuthError({ message: 'Forbidden: insufficient permissions' })).toBe(true);
249
+ });
250
+ it('rejects non-error inputs', () => {
251
+ const cb = new CircuitBreaker();
252
+ expect(cb.isAuthError(null)).toBe(false);
253
+ expect(cb.isAuthError(undefined)).toBe(false);
254
+ expect(cb.isAuthError('string')).toBe(false);
255
+ expect(cb.isAuthError(42)).toBe(false);
256
+ });
257
+ it('detects RATELIMITED in error message', () => {
258
+ const cb = new CircuitBreaker();
259
+ expect(cb.isAuthError({ message: 'GraphQL Error: RATELIMITED' })).toBe(true);
260
+ });
261
+ // ========================================================================
262
+ // createOpenError
263
+ // ========================================================================
264
+ it('creates a CircuitOpenError with remaining time info', () => {
265
+ const cb = new CircuitBreaker({ failureThreshold: 1, resetTimeoutMs: 10_000 });
266
+ cb.recordAuthFailure(401);
267
+ // 3 seconds have passed
268
+ vi.advanceTimersByTime(3000);
269
+ const error = cb.createOpenError();
270
+ expect(error).toBeInstanceOf(CircuitOpenError);
271
+ expect(error.code).toBe('CIRCUIT_OPEN');
272
+ expect(error.retryAfterMs).toBeGreaterThan(0);
273
+ expect(error.retryAfterMs).toBeLessThanOrEqual(7000);
274
+ expect(error.message).toMatch(/Circuit breaker is open/);
275
+ });
276
+ // ========================================================================
277
+ // getStatus diagnostic info
278
+ // ========================================================================
279
+ it('provides diagnostic status info', () => {
280
+ const cb = new CircuitBreaker({ failureThreshold: 1, resetTimeoutMs: 5000 });
281
+ let status = cb.getStatus();
282
+ expect(status.state).toBe('closed');
283
+ expect(status.consecutiveFailures).toBe(0);
284
+ expect(status.msSinceOpened).toBeNull();
285
+ cb.recordAuthFailure(401);
286
+ vi.advanceTimersByTime(2000);
287
+ status = cb.getStatus();
288
+ expect(status.state).toBe('open');
289
+ expect(status.consecutiveFailures).toBe(1);
290
+ expect(status.msSinceOpened).toBeGreaterThanOrEqual(2000);
291
+ });
292
+ });
@@ -54,6 +54,14 @@ export declare class LinearStatusTransitionError extends LinearAgentError {
54
54
  readonly toStatus: string;
55
55
  constructor(message: string, issueId: string, fromStatus: string, toStatus: string);
56
56
  }
57
+ /**
58
+ * Error thrown when the circuit breaker is open.
59
+ * All API calls are blocked to prevent wasting rate limit quota.
60
+ */
61
+ export declare class CircuitOpenError extends LinearAgentError {
62
+ readonly retryAfterMs: number;
63
+ constructor(message: string, retryAfterMs: number);
64
+ }
57
65
  /**
58
66
  * Error thrown when agent spawning fails
59
67
  */
@@ -72,6 +80,10 @@ export declare function isLinearAgentError(error: unknown): error is LinearAgent
72
80
  * Type guard to check if an error is an AgentSpawnError
73
81
  */
74
82
  export declare function isAgentSpawnError(error: unknown): error is AgentSpawnError;
83
+ /**
84
+ * Type guard to check if an error is a CircuitOpenError
85
+ */
86
+ export declare function isCircuitOpenError(error: unknown): error is CircuitOpenError;
75
87
  /**
76
88
  * Type guard to check if an error is retryable
77
89
  */
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,IAAI,EAAE,MAAM;aACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjD,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAQpD;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;aAGhC,UAAU,EAAE,MAAM;aAClB,QAAQ,CAAC,EAAE,OAAO;gBAFlC,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,OAAO,YAAA;CAKrC;AAED;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,gBAAgB;aAG3C,QAAQ,EAAE,MAAM;aAChB,SAAS,EAAE,KAAK;gBAFhC,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,KAAK;CAQnC;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,gBAAgB;aAGpC,SAAS,CAAC,EAAE,MAAM;aAClB,OAAO,CAAC,EAAE,MAAM;gBAFhC,OAAO,EAAE,MAAM,EACC,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,OAAO,CAAC,EAAE,MAAM,YAAA;CAKnC;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,gBAAgB;aAGrC,YAAY,EAAE,MAAM;aACpB,SAAS,CAAC,EAAE,MAAM;gBAFlC,OAAO,EAAE,MAAM,EACC,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,YAAA;CAKrC;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,gBAAgB;aACN,SAAS,CAAC,EAAE,MAAM;gBAAnD,OAAO,EAAE,MAAM,EAAkB,SAAS,CAAC,EAAE,MAAM,YAAA;CAIhE;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,gBAAgB;aAG7C,OAAO,EAAE,MAAM;aACf,UAAU,EAAE,MAAM;aAClB,QAAQ,EAAE,MAAM;gBAHhC,OAAO,EAAE,MAAM,EACC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM;CASnC;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,gBAAgB;aAGjC,OAAO,EAAE,MAAM;aACf,SAAS,CAAC,EAAE,MAAM;aAClB,WAAW,EAAE,OAAO;aACpB,KAAK,CAAC,EAAE,KAAK;gBAJ7B,OAAO,EAAE,MAAM,EACC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,WAAW,GAAE,OAAe,EAC5B,KAAK,CAAC,EAAE,KAAK,YAAA;CAUhC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAE1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,oBAAoB,GAAE,MAAM,EAA8B,GACzD,OAAO,CAkBT"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,IAAI,EAAE,MAAM;aACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjD,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAQpD;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;aAGhC,UAAU,EAAE,MAAM;aAClB,QAAQ,CAAC,EAAE,OAAO;gBAFlC,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,OAAO,YAAA;CAKrC;AAED;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,gBAAgB;aAG3C,QAAQ,EAAE,MAAM;aAChB,SAAS,EAAE,KAAK;gBAFhC,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,KAAK;CAQnC;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,gBAAgB;aAGpC,SAAS,CAAC,EAAE,MAAM;aAClB,OAAO,CAAC,EAAE,MAAM;gBAFhC,OAAO,EAAE,MAAM,EACC,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,OAAO,CAAC,EAAE,MAAM,YAAA;CAKnC;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,gBAAgB;aAGrC,YAAY,EAAE,MAAM;aACpB,SAAS,CAAC,EAAE,MAAM;gBAFlC,OAAO,EAAE,MAAM,EACC,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,YAAA;CAKrC;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,gBAAgB;aACN,SAAS,CAAC,EAAE,MAAM;gBAAnD,OAAO,EAAE,MAAM,EAAkB,SAAS,CAAC,EAAE,MAAM,YAAA;CAIhE;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,gBAAgB;aAG7C,OAAO,EAAE,MAAM;aACf,UAAU,EAAE,MAAM;aAClB,QAAQ,EAAE,MAAM;gBAHhC,OAAO,EAAE,MAAM,EACC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM;CASnC;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,gBAAgB;aAGlC,YAAY,EAAE,MAAM;gBADpC,OAAO,EAAE,MAAM,EACC,YAAY,EAAE,MAAM;CAKvC;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,gBAAgB;aAGjC,OAAO,EAAE,MAAM;aACf,SAAS,CAAC,EAAE,MAAM;aAClB,WAAW,EAAE,OAAO;aACpB,KAAK,CAAC,EAAE,KAAK;gBAJ7B,OAAO,EAAE,MAAM,EACC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,WAAW,GAAE,OAAe,EAC5B,KAAK,CAAC,EAAE,KAAK,YAAA;CAUhC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAE1E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,oBAAoB,GAAE,MAAM,EAA8B,GACzD,OAAO,CAkBT"}
@@ -99,6 +99,18 @@ export class LinearStatusTransitionError extends LinearAgentError {
99
99
  this.name = 'LinearStatusTransitionError';
100
100
  }
101
101
  }
102
+ /**
103
+ * Error thrown when the circuit breaker is open.
104
+ * All API calls are blocked to prevent wasting rate limit quota.
105
+ */
106
+ export class CircuitOpenError extends LinearAgentError {
107
+ retryAfterMs;
108
+ constructor(message, retryAfterMs) {
109
+ super(message, 'CIRCUIT_OPEN', { retryAfterMs });
110
+ this.retryAfterMs = retryAfterMs;
111
+ this.name = 'CircuitOpenError';
112
+ }
113
+ }
102
114
  /**
103
115
  * Error thrown when agent spawning fails
104
116
  */
@@ -133,6 +145,12 @@ export function isLinearAgentError(error) {
133
145
  export function isAgentSpawnError(error) {
134
146
  return error instanceof AgentSpawnError;
135
147
  }
148
+ /**
149
+ * Type guard to check if an error is a CircuitOpenError
150
+ */
151
+ export function isCircuitOpenError(error) {
152
+ return error instanceof CircuitOpenError;
153
+ }
136
154
  /**
137
155
  * Type guard to check if an error is retryable
138
156
  */
@@ -1,7 +1,7 @@
1
- export type { AgentSessionState, AgentActivityType, AgentActivitySignal, AgentActivityContent, AgentActivityContentPayload, ThoughtActivityContent, ActionActivityContent, ResponseActivityContent, ElicitationActivityContent, ErrorActivityContent, PromptActivityContent, AgentActivityCreateInput, AgentActivityResult, CreateActivityOptions, AgentPlanItemState, AgentPlanItem, AgentPlan, AgentSignals, LinearAgentClientConfig, RetryConfig, LinearWorkflowStatus, StatusMapping, AgentSessionConfig, SessionOperationResult, AgentSessionExternalUrl, AgentSessionUpdateInput, AgentSessionUpdateResult, AgentSessionCreateOnIssueInput, AgentSessionCreateResult, AgentWorkType, IssueRelationType, IssueRelationCreateInput, IssueRelationResult, IssueRelationBatchResult, IssueRelationInfo, IssueRelationsResult, SubIssueGraphNode, SubIssueGraph, SubIssueStatus, } from './types.js';
1
+ export type { AgentSessionState, AgentActivityType, AgentActivitySignal, AgentActivityContent, AgentActivityContentPayload, ThoughtActivityContent, ActionActivityContent, ResponseActivityContent, ElicitationActivityContent, ErrorActivityContent, PromptActivityContent, AgentActivityCreateInput, AgentActivityResult, CreateActivityOptions, AgentPlanItemState, AgentPlanItem, AgentPlan, AgentSignals, LinearAgentClientConfig, RetryConfig, LinearWorkflowStatus, StatusMapping, AgentSessionConfig, SessionOperationResult, AgentSessionExternalUrl, AgentSessionUpdateInput, AgentSessionUpdateResult, AgentSessionCreateOnIssueInput, AgentSessionCreateResult, AgentWorkType, IssueRelationType, IssueRelationCreateInput, IssueRelationResult, IssueRelationBatchResult, IssueRelationInfo, IssueRelationsResult, SubIssueGraphNode, SubIssueGraph, SubIssueStatus, RateLimiterStrategy, CircuitBreakerStrategy, CircuitBreakerConfig, } from './types.js';
2
2
  export { STATUS_WORK_TYPE_MAP, WORK_TYPE_START_STATUS, WORK_TYPE_COMPLETE_STATUS, WORK_TYPE_FAIL_STATUS, WORK_TYPE_ALLOWED_STATUSES, STATUS_VALID_WORK_TYPES, TERMINAL_STATUSES, validateWorkTypeForStatus, getValidWorkTypesForStatus, } from './types.js';
3
3
  export type { WorkTypeValidationResult } from './types.js';
4
- export { LinearAgentError, LinearApiError, LinearRetryExhaustedError, LinearSessionError, LinearActivityError, LinearPlanError, LinearStatusTransitionError, AgentSpawnError, isLinearAgentError, isRetryableError, isAgentSpawnError, } from './errors.js';
4
+ export { LinearAgentError, LinearApiError, LinearRetryExhaustedError, LinearSessionError, LinearActivityError, LinearPlanError, LinearStatusTransitionError, AgentSpawnError, CircuitOpenError, isLinearAgentError, isRetryableError, isAgentSpawnError, isCircuitOpenError, } from './errors.js';
5
5
  export { DEFAULT_RETRY_CONFIG, sleep, calculateDelay, withRetry, createRetryWrapper, } from './retry.js';
6
6
  export type { RetryContext, RetryCallback, WithRetryOptions } from './retry.js';
7
7
  export { LINEAR_COMMENT_MAX_LENGTH, TRUNCATION_MARKER, MAX_COMPLETION_COMMENTS, COMMENT_OVERHEAD, CONTINUATION_MARKER, getDefaultTeamId, getDefaultTeamName, LINEAR_PROJECTS, LINEAR_LABELS, ENVIRONMENT_ISSUE_TYPES, } from './constants.js';
@@ -12,6 +12,11 @@ export { parseCheckboxes, updateCheckbox, updateCheckboxByText, updateCheckboxes
12
12
  export type { CheckboxItem, CheckboxUpdate } from './checkbox-utils.js';
13
13
  export { TokenBucket, DEFAULT_RATE_LIMIT_CONFIG, extractRetryAfterMs } from './rate-limiter.js';
14
14
  export type { TokenBucketConfig } from './rate-limiter.js';
15
+ export { CircuitBreaker, DEFAULT_CIRCUIT_BREAKER_CONFIG } from './circuit-breaker.js';
16
+ export type { CircuitState } from './circuit-breaker.js';
17
+ export type { ProxyRequest, ProxyResponse, IssueTrackerMethod, SerializedIssue, SerializedComment, SerializedViewer, SerializedTeam, ProxyHealthStatus, } from './issue-tracker-proxy.js';
18
+ export { ProxyIssueTrackerClient, createProxyClientIfConfigured } from './proxy-client.js';
19
+ export type { ProxyClientConfig } from './proxy-client.js';
15
20
  export { LinearAgentClient, createLinearAgentClient } from './agent-client.js';
16
21
  export { AgentSession, createAgentSession } from './agent-session.js';
17
22
  export * from './webhook-types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/dist/src/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Work type mappings for status-based routing
2
2
  export { STATUS_WORK_TYPE_MAP, WORK_TYPE_START_STATUS, WORK_TYPE_COMPLETE_STATUS, WORK_TYPE_FAIL_STATUS, WORK_TYPE_ALLOWED_STATUSES, STATUS_VALID_WORK_TYPES, TERMINAL_STATUSES, validateWorkTypeForStatus, getValidWorkTypesForStatus, } from './types.js';
3
3
  // Errors
4
- export { LinearAgentError, LinearApiError, LinearRetryExhaustedError, LinearSessionError, LinearActivityError, LinearPlanError, LinearStatusTransitionError, AgentSpawnError, isLinearAgentError, isRetryableError, isAgentSpawnError, } from './errors.js';
4
+ export { LinearAgentError, LinearApiError, LinearRetryExhaustedError, LinearSessionError, LinearActivityError, LinearPlanError, LinearStatusTransitionError, AgentSpawnError, CircuitOpenError, isLinearAgentError, isRetryableError, isAgentSpawnError, isCircuitOpenError, } from './errors.js';
5
5
  // Retry utilities
6
6
  export { DEFAULT_RETRY_CONFIG, sleep, calculateDelay, withRetry, createRetryWrapper, } from './retry.js';
7
7
  // Constants
@@ -12,6 +12,10 @@ export { truncateText, buildCompletionComment, splitContentIntoComments, buildCo
12
12
  export { parseCheckboxes, updateCheckbox, updateCheckboxByText, updateCheckboxes, hasCheckboxes, getCheckboxSummary, } from './checkbox-utils.js';
13
13
  // Rate limiter
14
14
  export { TokenBucket, DEFAULT_RATE_LIMIT_CONFIG, extractRetryAfterMs } from './rate-limiter.js';
15
+ // Circuit breaker
16
+ export { CircuitBreaker, DEFAULT_CIRCUIT_BREAKER_CONFIG } from './circuit-breaker.js';
17
+ // Proxy client (routes calls through dashboard instead of Linear directly)
18
+ export { ProxyIssueTrackerClient, createProxyClientIfConfigured } from './proxy-client.js';
15
19
  // Client
16
20
  export { LinearAgentClient, createLinearAgentClient } from './agent-client.js';
17
21
  // Session
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Platform-Agnostic Issue Tracker Proxy Interface
3
+ *
4
+ * Defines the contract between agents/governors and the centralized proxy.
5
+ * Agents call these methods without knowing whether the backend is Linear,
6
+ * Jira, GitHub Issues, or any future platform.
7
+ *
8
+ * The proxy translates these generic operations into platform-specific API calls.
9
+ */
10
+ /**
11
+ * Every proxy request carries authentication and workspace context.
12
+ */
13
+ export interface ProxyRequest {
14
+ /** The operation to perform */
15
+ method: IssueTrackerMethod;
16
+ /** Arguments for the operation (method-specific) */
17
+ args: unknown[];
18
+ /** Workspace/organization ID for multi-tenant routing */
19
+ organizationId?: string;
20
+ }
21
+ /**
22
+ * Standard proxy response envelope.
23
+ */
24
+ export interface ProxyResponse<T = unknown> {
25
+ success: boolean;
26
+ data?: T;
27
+ error?: {
28
+ code: string;
29
+ message: string;
30
+ retryable: boolean;
31
+ };
32
+ /** Rate limit info from the upstream platform */
33
+ quota?: {
34
+ requestsRemaining?: number;
35
+ complexityRemaining?: number;
36
+ resetAt?: number;
37
+ };
38
+ }
39
+ /**
40
+ * All operations that can be routed through the proxy.
41
+ *
42
+ * Named generically (not Linear-specific) so future platforms
43
+ * can implement the same interface.
44
+ */
45
+ export type IssueTrackerMethod = 'getIssue' | 'updateIssue' | 'createIssue' | 'createComment' | 'getIssueComments' | 'getTeamStatuses' | 'updateIssueStatus' | 'createAgentActivity' | 'updateAgentSession' | 'createAgentSessionOnIssue' | 'createIssueRelation' | 'getIssueRelations' | 'deleteIssueRelation' | 'getSubIssues' | 'getSubIssueStatuses' | 'getSubIssueGraph' | 'isParentIssue' | 'isChildIssue' | 'listProjectIssues' | 'getProjectRepositoryUrl' | 'getViewer' | 'getTeam' | 'unassignIssue';
46
+ /**
47
+ * Serialized issue — all relations pre-resolved to plain JSON.
48
+ * No SDK-specific Promise fields or lazy loaders.
49
+ */
50
+ export interface SerializedIssue {
51
+ id: string;
52
+ identifier: string;
53
+ title: string;
54
+ description?: string;
55
+ url: string;
56
+ priority: number;
57
+ state?: {
58
+ id: string;
59
+ name: string;
60
+ type: string;
61
+ };
62
+ labels: Array<{
63
+ id: string;
64
+ name: string;
65
+ }>;
66
+ assignee?: {
67
+ id: string;
68
+ name: string;
69
+ email?: string;
70
+ } | null;
71
+ team?: {
72
+ id: string;
73
+ name: string;
74
+ key: string;
75
+ };
76
+ parent?: {
77
+ id: string;
78
+ identifier: string;
79
+ } | null;
80
+ project?: {
81
+ id: string;
82
+ name: string;
83
+ } | null;
84
+ createdAt: string;
85
+ updatedAt: string;
86
+ }
87
+ /**
88
+ * Serialized comment.
89
+ */
90
+ export interface SerializedComment {
91
+ id: string;
92
+ body: string;
93
+ createdAt: string;
94
+ updatedAt: string;
95
+ user?: {
96
+ id: string;
97
+ name: string;
98
+ } | null;
99
+ }
100
+ /**
101
+ * Serialized viewer (authenticated user).
102
+ */
103
+ export interface SerializedViewer {
104
+ id: string;
105
+ name: string;
106
+ email: string;
107
+ }
108
+ /**
109
+ * Serialized team.
110
+ */
111
+ export interface SerializedTeam {
112
+ id: string;
113
+ name: string;
114
+ key: string;
115
+ }
116
+ /**
117
+ * Health status for the proxy endpoint.
118
+ */
119
+ export interface ProxyHealthStatus {
120
+ /** Whether the proxy can process requests */
121
+ healthy: boolean;
122
+ /** Circuit breaker state */
123
+ circuitBreaker: {
124
+ state: string;
125
+ failures: number;
126
+ msSinceOpened: number | null;
127
+ };
128
+ /** Rate limiter status */
129
+ rateLimiter: {
130
+ availableTokens: number;
131
+ };
132
+ /** Upstream platform quota from response headers */
133
+ quota: {
134
+ requestsRemaining: number | null;
135
+ complexityRemaining: number | null;
136
+ resetAt: number | null;
137
+ updatedAt: number;
138
+ };
139
+ }
140
+ //# sourceMappingURL=issue-tracker-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-tracker-proxy.d.ts","sourceRoot":"","sources":["../../src/issue-tracker-proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Platform-Agnostic Issue Tracker Proxy Interface
3
+ *
4
+ * Defines the contract between agents/governors and the centralized proxy.
5
+ * Agents call these methods without knowing whether the backend is Linear,
6
+ * Jira, GitHub Issues, or any future platform.
7
+ *
8
+ * The proxy translates these generic operations into platform-specific API calls.
9
+ */
10
+ export {};