@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.
- package/dist/src/agent-client-project-repo.test.js +2 -0
- package/dist/src/agent-client.d.ts +9 -4
- package/dist/src/agent-client.d.ts.map +1 -1
- package/dist/src/agent-client.js +100 -25
- package/dist/src/circuit-breaker.d.ts +75 -0
- package/dist/src/circuit-breaker.d.ts.map +1 -0
- package/dist/src/circuit-breaker.js +231 -0
- package/dist/src/circuit-breaker.test.d.ts +2 -0
- package/dist/src/circuit-breaker.test.d.ts.map +1 -0
- package/dist/src/circuit-breaker.test.js +292 -0
- package/dist/src/errors.d.ts +12 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +18 -0
- package/dist/src/index.d.ts +7 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -1
- package/dist/src/issue-tracker-proxy.d.ts +140 -0
- package/dist/src/issue-tracker-proxy.d.ts.map +1 -0
- package/dist/src/issue-tracker-proxy.js +10 -0
- package/dist/src/proxy-client.d.ts +103 -0
- package/dist/src/proxy-client.d.ts.map +1 -0
- package/dist/src/proxy-client.js +191 -0
- package/dist/src/types.d.ts +50 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
+
});
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/src/errors.d.ts.map
CHANGED
|
@@ -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"}
|
package/dist/src/errors.js
CHANGED
|
@@ -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
|
*/
|
package/dist/src/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,SAAS,EACT,YAAY,EACZ,uBAAuB,EACvB,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,kBAAkB,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,8BAA8B,EAC9B,wBAAwB,EACxB,aAAa,EAEb,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,wBAAwB,EACxB,iBAAiB,EACjB,oBAAoB,EAEpB,iBAAiB,EACjB,aAAa,EACb,cAAc,
|
|
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 {};
|