@supaku/agentfactory-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/src/agent-tracking.d.ts +98 -0
- package/dist/src/agent-tracking.d.ts.map +1 -0
- package/dist/src/agent-tracking.js +185 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +16 -0
- package/dist/src/issue-lock.d.ts +126 -0
- package/dist/src/issue-lock.d.ts.map +1 -0
- package/dist/src/issue-lock.js +499 -0
- package/dist/src/redis.d.ts +146 -0
- package/dist/src/redis.d.ts.map +1 -0
- package/dist/src/redis.js +343 -0
- package/dist/src/session-storage.d.ts +144 -0
- package/dist/src/session-storage.d.ts.map +1 -0
- package/dist/src/session-storage.js +349 -0
- package/dist/src/types.d.ts +11 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +7 -0
- package/dist/src/webhook-idempotency.d.ts +44 -0
- package/dist/src/webhook-idempotency.d.ts.map +1 -0
- package/dist/src/webhook-idempotency.js +148 -0
- package/dist/src/work-queue.d.ts +119 -0
- package/dist/src/work-queue.d.ts.map +1 -0
- package/dist/src/work-queue.js +366 -0
- package/dist/src/worker-storage.d.ts +100 -0
- package/dist/src/worker-storage.d.ts.map +1 -0
- package/dist/src/worker-storage.js +283 -0
- package/package.json +61 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import Redis from 'ioredis';
|
|
2
|
+
const log = {
|
|
3
|
+
info: (msg, data) => console.log(`[redis] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
4
|
+
warn: (msg, data) => console.warn(`[redis] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
5
|
+
error: (msg, data) => console.error(`[redis] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
6
|
+
debug: (_msg, _data) => { },
|
|
7
|
+
};
|
|
8
|
+
let _redis = null;
|
|
9
|
+
/**
|
|
10
|
+
* Parse Redis URL using the modern URL class to avoid deprecated url.parse()
|
|
11
|
+
* Supports redis:// and rediss:// (TLS) protocols
|
|
12
|
+
*/
|
|
13
|
+
function parseRedisUrl(redisUrl) {
|
|
14
|
+
const url = new URL(redisUrl);
|
|
15
|
+
const options = {};
|
|
16
|
+
if (url.hostname) {
|
|
17
|
+
options.host = url.hostname;
|
|
18
|
+
}
|
|
19
|
+
if (url.port) {
|
|
20
|
+
options.port = parseInt(url.port, 10);
|
|
21
|
+
}
|
|
22
|
+
if (url.username && url.username !== 'default') {
|
|
23
|
+
options.username = decodeURIComponent(url.username);
|
|
24
|
+
}
|
|
25
|
+
if (url.password) {
|
|
26
|
+
options.password = decodeURIComponent(url.password);
|
|
27
|
+
}
|
|
28
|
+
// Database number from path (e.g., redis://host/0)
|
|
29
|
+
if (url.pathname && url.pathname.length > 1) {
|
|
30
|
+
const db = parseInt(url.pathname.slice(1), 10);
|
|
31
|
+
if (!isNaN(db)) {
|
|
32
|
+
options.db = db;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Enable TLS for rediss:// protocol
|
|
36
|
+
if (url.protocol === 'rediss:') {
|
|
37
|
+
options.tls = {};
|
|
38
|
+
}
|
|
39
|
+
// Parse query parameters (e.g., ?family=6)
|
|
40
|
+
for (const [key, value] of url.searchParams) {
|
|
41
|
+
if (key === 'family') {
|
|
42
|
+
const family = parseInt(value, 10);
|
|
43
|
+
if (!isNaN(family)) {
|
|
44
|
+
options.family = family;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return options;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if Redis is configured via REDIS_URL
|
|
52
|
+
*/
|
|
53
|
+
export function isRedisConfigured() {
|
|
54
|
+
return !!process.env.REDIS_URL;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get the shared Redis client instance
|
|
58
|
+
* Lazily initialized to avoid errors during build
|
|
59
|
+
*/
|
|
60
|
+
export function getRedisClient() {
|
|
61
|
+
if (!_redis) {
|
|
62
|
+
const redisUrl = process.env.REDIS_URL;
|
|
63
|
+
if (!redisUrl) {
|
|
64
|
+
throw new Error('REDIS_URL not set - Redis operations will fail');
|
|
65
|
+
}
|
|
66
|
+
const urlOptions = parseRedisUrl(redisUrl);
|
|
67
|
+
_redis = new Redis({
|
|
68
|
+
...urlOptions,
|
|
69
|
+
maxRetriesPerRequest: 3,
|
|
70
|
+
lazyConnect: true,
|
|
71
|
+
});
|
|
72
|
+
_redis.on('error', (err) => {
|
|
73
|
+
log.error('Redis connection error', { error: err });
|
|
74
|
+
});
|
|
75
|
+
_redis.on('connect', () => {
|
|
76
|
+
log.info('Redis connected');
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return _redis;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Disconnect Redis client (for graceful shutdown)
|
|
83
|
+
*/
|
|
84
|
+
export async function disconnectRedis() {
|
|
85
|
+
if (_redis) {
|
|
86
|
+
await _redis.quit();
|
|
87
|
+
_redis = null;
|
|
88
|
+
log.info('Redis disconnected');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Set a value with optional TTL (seconds)
|
|
93
|
+
*/
|
|
94
|
+
export async function redisSet(key, value, ttlSeconds) {
|
|
95
|
+
const redis = getRedisClient();
|
|
96
|
+
const serialized = JSON.stringify(value);
|
|
97
|
+
if (ttlSeconds) {
|
|
98
|
+
await redis.setex(key, ttlSeconds, serialized);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
await redis.set(key, serialized);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get a typed value
|
|
106
|
+
*/
|
|
107
|
+
export async function redisGet(key) {
|
|
108
|
+
const redis = getRedisClient();
|
|
109
|
+
const value = await redis.get(key);
|
|
110
|
+
if (value === null) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return JSON.parse(value);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Delete a key
|
|
117
|
+
* @returns number of keys deleted (0 or 1)
|
|
118
|
+
*/
|
|
119
|
+
export async function redisDel(key) {
|
|
120
|
+
const redis = getRedisClient();
|
|
121
|
+
return redis.del(key);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check if a key exists
|
|
125
|
+
*/
|
|
126
|
+
export async function redisExists(key) {
|
|
127
|
+
const redis = getRedisClient();
|
|
128
|
+
const result = await redis.exists(key);
|
|
129
|
+
return result === 1;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get keys matching a pattern
|
|
133
|
+
*/
|
|
134
|
+
export async function redisKeys(pattern) {
|
|
135
|
+
const redis = getRedisClient();
|
|
136
|
+
return redis.keys(pattern);
|
|
137
|
+
}
|
|
138
|
+
// ============================================
|
|
139
|
+
// List Operations (for work queue)
|
|
140
|
+
// ============================================
|
|
141
|
+
/**
|
|
142
|
+
* Push value to the right of a list (RPUSH)
|
|
143
|
+
* @returns length of list after push
|
|
144
|
+
*/
|
|
145
|
+
export async function redisRPush(key, value) {
|
|
146
|
+
const redis = getRedisClient();
|
|
147
|
+
return redis.rpush(key, value);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Pop value from the left of a list (LPOP)
|
|
151
|
+
* @returns the popped value or null if list is empty
|
|
152
|
+
*/
|
|
153
|
+
export async function redisLPop(key) {
|
|
154
|
+
const redis = getRedisClient();
|
|
155
|
+
return redis.lpop(key);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get a range of elements from a list (LRANGE)
|
|
159
|
+
* @param start - Start index (0-based, inclusive)
|
|
160
|
+
* @param stop - Stop index (inclusive, -1 for end)
|
|
161
|
+
*/
|
|
162
|
+
export async function redisLRange(key, start, stop) {
|
|
163
|
+
const redis = getRedisClient();
|
|
164
|
+
return redis.lrange(key, start, stop);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the length of a list (LLEN)
|
|
168
|
+
*/
|
|
169
|
+
export async function redisLLen(key) {
|
|
170
|
+
const redis = getRedisClient();
|
|
171
|
+
return redis.llen(key);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Remove elements from a list (LREM)
|
|
175
|
+
* @param count - Number of occurrences to remove (0 = all)
|
|
176
|
+
* @returns number of elements removed
|
|
177
|
+
*/
|
|
178
|
+
export async function redisLRem(key, count, value) {
|
|
179
|
+
const redis = getRedisClient();
|
|
180
|
+
return redis.lrem(key, count, value);
|
|
181
|
+
}
|
|
182
|
+
// ============================================
|
|
183
|
+
// Set Operations (for worker sessions)
|
|
184
|
+
// ============================================
|
|
185
|
+
/**
|
|
186
|
+
* Add member to a set (SADD)
|
|
187
|
+
* @returns number of elements added (0 if already exists)
|
|
188
|
+
*/
|
|
189
|
+
export async function redisSAdd(key, member) {
|
|
190
|
+
const redis = getRedisClient();
|
|
191
|
+
return redis.sadd(key, member);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Remove member from a set (SREM)
|
|
195
|
+
* @returns number of elements removed
|
|
196
|
+
*/
|
|
197
|
+
export async function redisSRem(key, member) {
|
|
198
|
+
const redis = getRedisClient();
|
|
199
|
+
return redis.srem(key, member);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get all members of a set (SMEMBERS)
|
|
203
|
+
*/
|
|
204
|
+
export async function redisSMembers(key) {
|
|
205
|
+
const redis = getRedisClient();
|
|
206
|
+
return redis.smembers(key);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get the number of members in a set (SCARD)
|
|
210
|
+
*/
|
|
211
|
+
export async function redisSCard(key) {
|
|
212
|
+
const redis = getRedisClient();
|
|
213
|
+
return redis.scard(key);
|
|
214
|
+
}
|
|
215
|
+
// ============================================
|
|
216
|
+
// Atomic Operations
|
|
217
|
+
// ============================================
|
|
218
|
+
/**
|
|
219
|
+
* Set a value only if key does not exist (SETNX)
|
|
220
|
+
* @returns true if key was set, false if it already existed
|
|
221
|
+
*/
|
|
222
|
+
export async function redisSetNX(key, value, ttlSeconds) {
|
|
223
|
+
const redis = getRedisClient();
|
|
224
|
+
if (ttlSeconds) {
|
|
225
|
+
// Use SET with NX and EX options for atomic set-if-not-exists with TTL
|
|
226
|
+
const result = await redis.set(key, value, 'EX', ttlSeconds, 'NX');
|
|
227
|
+
return result === 'OK';
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
const result = await redis.setnx(key, value);
|
|
231
|
+
return result === 1;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Set TTL on an existing key (EXPIRE)
|
|
236
|
+
* @returns true if TTL was set, false if key doesn't exist
|
|
237
|
+
*/
|
|
238
|
+
export async function redisExpire(key, ttlSeconds) {
|
|
239
|
+
const redis = getRedisClient();
|
|
240
|
+
const result = await redis.expire(key, ttlSeconds);
|
|
241
|
+
return result === 1;
|
|
242
|
+
}
|
|
243
|
+
// ============================================
|
|
244
|
+
// Sorted Set Operations (for priority queue)
|
|
245
|
+
// ============================================
|
|
246
|
+
/**
|
|
247
|
+
* Add member to a sorted set with score (ZADD)
|
|
248
|
+
* @returns number of elements added (0 if already exists, updates score)
|
|
249
|
+
*/
|
|
250
|
+
export async function redisZAdd(key, score, member) {
|
|
251
|
+
const redis = getRedisClient();
|
|
252
|
+
return redis.zadd(key, score, member);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Remove member from a sorted set (ZREM)
|
|
256
|
+
* @returns number of elements removed
|
|
257
|
+
*/
|
|
258
|
+
export async function redisZRem(key, member) {
|
|
259
|
+
const redis = getRedisClient();
|
|
260
|
+
return redis.zrem(key, member);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get members from sorted set by score range (ZRANGEBYSCORE)
|
|
264
|
+
* Returns members with lowest scores first (highest priority)
|
|
265
|
+
* @param min - Minimum score (use '-inf' for no minimum)
|
|
266
|
+
* @param max - Maximum score (use '+inf' for no maximum)
|
|
267
|
+
* @param limit - Maximum number of results
|
|
268
|
+
*/
|
|
269
|
+
export async function redisZRangeByScore(key, min, max, limit) {
|
|
270
|
+
const redis = getRedisClient();
|
|
271
|
+
if (limit !== undefined) {
|
|
272
|
+
return redis.zrangebyscore(key, min, max, 'LIMIT', 0, limit);
|
|
273
|
+
}
|
|
274
|
+
return redis.zrangebyscore(key, min, max);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get the number of members in a sorted set (ZCARD)
|
|
278
|
+
*/
|
|
279
|
+
export async function redisZCard(key) {
|
|
280
|
+
const redis = getRedisClient();
|
|
281
|
+
return redis.zcard(key);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Pop the member with the lowest score (ZPOPMIN)
|
|
285
|
+
* @returns [member, score] or null if set is empty
|
|
286
|
+
*/
|
|
287
|
+
export async function redisZPopMin(key) {
|
|
288
|
+
const redis = getRedisClient();
|
|
289
|
+
const result = await redis.zpopmin(key);
|
|
290
|
+
if (result && result.length >= 2) {
|
|
291
|
+
return { member: result[0], score: parseFloat(result[1]) };
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
// ============================================
|
|
296
|
+
// Hash Operations (for work item lookup)
|
|
297
|
+
// ============================================
|
|
298
|
+
/**
|
|
299
|
+
* Set a field in a hash (HSET)
|
|
300
|
+
* @returns 1 if field is new, 0 if field existed
|
|
301
|
+
*/
|
|
302
|
+
export async function redisHSet(key, field, value) {
|
|
303
|
+
const redis = getRedisClient();
|
|
304
|
+
return redis.hset(key, field, value);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get a field from a hash (HGET)
|
|
308
|
+
*/
|
|
309
|
+
export async function redisHGet(key, field) {
|
|
310
|
+
const redis = getRedisClient();
|
|
311
|
+
return redis.hget(key, field);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Delete a field from a hash (HDEL)
|
|
315
|
+
* @returns number of fields removed
|
|
316
|
+
*/
|
|
317
|
+
export async function redisHDel(key, field) {
|
|
318
|
+
const redis = getRedisClient();
|
|
319
|
+
return redis.hdel(key, field);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get multiple fields from a hash (HMGET)
|
|
323
|
+
*/
|
|
324
|
+
export async function redisHMGet(key, fields) {
|
|
325
|
+
const redis = getRedisClient();
|
|
326
|
+
if (fields.length === 0)
|
|
327
|
+
return [];
|
|
328
|
+
return redis.hmget(key, ...fields);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get all fields and values from a hash (HGETALL)
|
|
332
|
+
*/
|
|
333
|
+
export async function redisHGetAll(key) {
|
|
334
|
+
const redis = getRedisClient();
|
|
335
|
+
return redis.hgetall(key);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Get the number of fields in a hash (HLEN)
|
|
339
|
+
*/
|
|
340
|
+
export async function redisHLen(key) {
|
|
341
|
+
const redis = getRedisClient();
|
|
342
|
+
return redis.hlen(key);
|
|
343
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { AgentWorkType } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Agent session status
|
|
4
|
+
* - pending: Queued, waiting for a worker to claim
|
|
5
|
+
* - claimed: Worker has claimed but not yet started
|
|
6
|
+
* - running: Agent is actively processing
|
|
7
|
+
* - finalizing: Agent work done, cleanup in progress (worktree removal, orchestrator teardown)
|
|
8
|
+
* - completed: Agent finished successfully (all cleanup done)
|
|
9
|
+
* - failed: Agent encountered an error
|
|
10
|
+
* - stopped: Agent was stopped by user
|
|
11
|
+
*/
|
|
12
|
+
export type AgentSessionStatus = 'pending' | 'claimed' | 'running' | 'finalizing' | 'completed' | 'failed' | 'stopped';
|
|
13
|
+
/**
|
|
14
|
+
* Agent session state stored in Redis for distributed access
|
|
15
|
+
*/
|
|
16
|
+
export interface AgentSessionState {
|
|
17
|
+
/** Linear session ID (from webhook) */
|
|
18
|
+
linearSessionId: string;
|
|
19
|
+
/** Linear issue ID */
|
|
20
|
+
issueId: string;
|
|
21
|
+
/** Issue identifier (e.g., SUP-123) */
|
|
22
|
+
issueIdentifier?: string;
|
|
23
|
+
/** Claude CLI session ID for resuming with --resume */
|
|
24
|
+
claudeSessionId: string | null;
|
|
25
|
+
/** Git worktree path */
|
|
26
|
+
worktreePath: string;
|
|
27
|
+
/** Current agent status */
|
|
28
|
+
status: AgentSessionStatus;
|
|
29
|
+
/** Unix timestamp when session was created */
|
|
30
|
+
createdAt: number;
|
|
31
|
+
/** Unix timestamp of last update */
|
|
32
|
+
updatedAt: number;
|
|
33
|
+
/** Worker ID handling this session (null if pending) */
|
|
34
|
+
workerId?: string | null;
|
|
35
|
+
/** Unix timestamp when added to work queue */
|
|
36
|
+
queuedAt?: number | null;
|
|
37
|
+
/** Unix timestamp when claimed by worker */
|
|
38
|
+
claimedAt?: number | null;
|
|
39
|
+
/** Priority in queue (1-5, lower is higher priority) */
|
|
40
|
+
priority?: number;
|
|
41
|
+
/** Prompt context for the session */
|
|
42
|
+
promptContext?: string;
|
|
43
|
+
/** Linear organization ID for OAuth token lookup */
|
|
44
|
+
organizationId?: string;
|
|
45
|
+
/** Type of work: research, development, inflight, qa, acceptance, refinement (defaults to 'development') */
|
|
46
|
+
workType?: AgentWorkType;
|
|
47
|
+
/** Linear Agent ID handling this session */
|
|
48
|
+
agentId?: string;
|
|
49
|
+
/** Total cost in USD for this session */
|
|
50
|
+
totalCostUsd?: number;
|
|
51
|
+
/** Total input tokens consumed */
|
|
52
|
+
inputTokens?: number;
|
|
53
|
+
/** Total output tokens consumed */
|
|
54
|
+
outputTokens?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Store agent session state in Redis
|
|
58
|
+
*
|
|
59
|
+
* @param linearSessionId - The Linear session ID from webhook
|
|
60
|
+
* @param state - The session state to store
|
|
61
|
+
*/
|
|
62
|
+
export declare function storeSessionState(linearSessionId: string, state: Omit<AgentSessionState, 'linearSessionId' | 'createdAt' | 'updatedAt'>): Promise<AgentSessionState>;
|
|
63
|
+
/**
|
|
64
|
+
* Retrieve agent session state from Redis
|
|
65
|
+
*
|
|
66
|
+
* @param linearSessionId - The Linear session ID
|
|
67
|
+
* @returns The session state or null if not found
|
|
68
|
+
*/
|
|
69
|
+
export declare function getSessionState(linearSessionId: string): Promise<AgentSessionState | null>;
|
|
70
|
+
/**
|
|
71
|
+
* Update the Claude session ID for a session
|
|
72
|
+
* Called when the Claude init event is received with the session ID
|
|
73
|
+
*
|
|
74
|
+
* @param linearSessionId - The Linear session ID
|
|
75
|
+
* @param claudeSessionId - The Claude CLI session ID
|
|
76
|
+
*/
|
|
77
|
+
export declare function updateClaudeSessionId(linearSessionId: string, claudeSessionId: string): Promise<boolean>;
|
|
78
|
+
/**
|
|
79
|
+
* Update session status
|
|
80
|
+
*
|
|
81
|
+
* @param linearSessionId - The Linear session ID
|
|
82
|
+
* @param status - The new status
|
|
83
|
+
*/
|
|
84
|
+
export declare function updateSessionStatus(linearSessionId: string, status: AgentSessionState['status']): Promise<boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* Reset a session for re-queuing after orphan cleanup
|
|
87
|
+
* Clears workerId and resets status to pending so a new worker can claim it
|
|
88
|
+
*
|
|
89
|
+
* @param linearSessionId - The Linear session ID
|
|
90
|
+
*/
|
|
91
|
+
export declare function resetSessionForRequeue(linearSessionId: string): Promise<boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* Delete session state from KV
|
|
94
|
+
*
|
|
95
|
+
* @param linearSessionId - The Linear session ID
|
|
96
|
+
* @returns Whether the deletion was successful
|
|
97
|
+
*/
|
|
98
|
+
export declare function deleteSessionState(linearSessionId: string): Promise<boolean>;
|
|
99
|
+
/**
|
|
100
|
+
* Get session state by issue ID
|
|
101
|
+
* Useful when we have the issue but not the session ID
|
|
102
|
+
*
|
|
103
|
+
* @param issueId - The Linear issue ID
|
|
104
|
+
* @returns The most recent session state for this issue or null
|
|
105
|
+
*/
|
|
106
|
+
export declare function getSessionStateByIssue(issueId: string): Promise<AgentSessionState | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Mark a session as claimed by a worker
|
|
109
|
+
*
|
|
110
|
+
* @param linearSessionId - The Linear session ID
|
|
111
|
+
* @param workerId - The worker claiming the session
|
|
112
|
+
*/
|
|
113
|
+
export declare function claimSession(linearSessionId: string, workerId: string): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Update session with worker info when work starts
|
|
116
|
+
*
|
|
117
|
+
* @param linearSessionId - The Linear session ID
|
|
118
|
+
* @param workerId - The worker processing the session
|
|
119
|
+
* @param worktreePath - Path to the git worktree
|
|
120
|
+
*/
|
|
121
|
+
export declare function startSession(linearSessionId: string, workerId: string, worktreePath: string): Promise<boolean>;
|
|
122
|
+
/**
|
|
123
|
+
* Get all sessions from Redis
|
|
124
|
+
* For dashboard display
|
|
125
|
+
*/
|
|
126
|
+
export declare function getAllSessions(): Promise<AgentSessionState[]>;
|
|
127
|
+
/**
|
|
128
|
+
* Get sessions by status
|
|
129
|
+
*/
|
|
130
|
+
export declare function getSessionsByStatus(status: AgentSessionStatus | AgentSessionStatus[]): Promise<AgentSessionState[]>;
|
|
131
|
+
/**
|
|
132
|
+
* Transfer session ownership to a new worker
|
|
133
|
+
* Used when a worker re-registers after disconnection and gets a new ID
|
|
134
|
+
*
|
|
135
|
+
* @param linearSessionId - The Linear session ID
|
|
136
|
+
* @param newWorkerId - The new worker ID to assign
|
|
137
|
+
* @param oldWorkerId - The previous worker ID (for validation)
|
|
138
|
+
* @returns Whether the transfer was successful
|
|
139
|
+
*/
|
|
140
|
+
export declare function transferSessionOwnership(linearSessionId: string, newWorkerId: string, oldWorkerId: string): Promise<{
|
|
141
|
+
transferred: boolean;
|
|
142
|
+
reason?: string;
|
|
143
|
+
}>;
|
|
144
|
+
//# sourceMappingURL=session-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-storage.d.ts","sourceRoot":"","sources":["../../src/session-storage.ts"],"names":[],"mappings":"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"}
|