@renseiai/agentfactory-server 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/dist/src/a2a-server.d.ts +88 -0
  4. package/dist/src/a2a-server.d.ts.map +1 -0
  5. package/dist/src/a2a-server.integration.test.d.ts +9 -0
  6. package/dist/src/a2a-server.integration.test.d.ts.map +1 -0
  7. package/dist/src/a2a-server.integration.test.js +397 -0
  8. package/dist/src/a2a-server.js +235 -0
  9. package/dist/src/a2a-server.test.d.ts +2 -0
  10. package/dist/src/a2a-server.test.d.ts.map +1 -0
  11. package/dist/src/a2a-server.test.js +311 -0
  12. package/dist/src/a2a-types.d.ts +125 -0
  13. package/dist/src/a2a-types.d.ts.map +1 -0
  14. package/dist/src/a2a-types.js +8 -0
  15. package/dist/src/agent-tracking.d.ts +201 -0
  16. package/dist/src/agent-tracking.d.ts.map +1 -0
  17. package/dist/src/agent-tracking.js +349 -0
  18. package/dist/src/env-validation.d.ts +65 -0
  19. package/dist/src/env-validation.d.ts.map +1 -0
  20. package/dist/src/env-validation.js +134 -0
  21. package/dist/src/governor-dedup.d.ts +15 -0
  22. package/dist/src/governor-dedup.d.ts.map +1 -0
  23. package/dist/src/governor-dedup.js +31 -0
  24. package/dist/src/governor-event-bus.d.ts +54 -0
  25. package/dist/src/governor-event-bus.d.ts.map +1 -0
  26. package/dist/src/governor-event-bus.js +152 -0
  27. package/dist/src/governor-storage.d.ts +28 -0
  28. package/dist/src/governor-storage.d.ts.map +1 -0
  29. package/dist/src/governor-storage.js +52 -0
  30. package/dist/src/index.d.ts +26 -0
  31. package/dist/src/index.d.ts.map +1 -0
  32. package/dist/src/index.js +50 -0
  33. package/dist/src/issue-lock.d.ts +129 -0
  34. package/dist/src/issue-lock.d.ts.map +1 -0
  35. package/dist/src/issue-lock.js +508 -0
  36. package/dist/src/logger.d.ts +76 -0
  37. package/dist/src/logger.d.ts.map +1 -0
  38. package/dist/src/logger.js +218 -0
  39. package/dist/src/orphan-cleanup.d.ts +64 -0
  40. package/dist/src/orphan-cleanup.d.ts.map +1 -0
  41. package/dist/src/orphan-cleanup.js +369 -0
  42. package/dist/src/pending-prompts.d.ts +67 -0
  43. package/dist/src/pending-prompts.d.ts.map +1 -0
  44. package/dist/src/pending-prompts.js +176 -0
  45. package/dist/src/processing-state-storage.d.ts +38 -0
  46. package/dist/src/processing-state-storage.d.ts.map +1 -0
  47. package/dist/src/processing-state-storage.js +61 -0
  48. package/dist/src/quota-tracker.d.ts +62 -0
  49. package/dist/src/quota-tracker.d.ts.map +1 -0
  50. package/dist/src/quota-tracker.js +155 -0
  51. package/dist/src/rate-limit.d.ts +111 -0
  52. package/dist/src/rate-limit.d.ts.map +1 -0
  53. package/dist/src/rate-limit.js +171 -0
  54. package/dist/src/redis-circuit-breaker.d.ts +67 -0
  55. package/dist/src/redis-circuit-breaker.d.ts.map +1 -0
  56. package/dist/src/redis-circuit-breaker.js +290 -0
  57. package/dist/src/redis-rate-limiter.d.ts +51 -0
  58. package/dist/src/redis-rate-limiter.d.ts.map +1 -0
  59. package/dist/src/redis-rate-limiter.js +168 -0
  60. package/dist/src/redis.d.ts +146 -0
  61. package/dist/src/redis.d.ts.map +1 -0
  62. package/dist/src/redis.js +343 -0
  63. package/dist/src/session-hash.d.ts +48 -0
  64. package/dist/src/session-hash.d.ts.map +1 -0
  65. package/dist/src/session-hash.js +80 -0
  66. package/dist/src/session-storage.d.ts +166 -0
  67. package/dist/src/session-storage.d.ts.map +1 -0
  68. package/dist/src/session-storage.js +397 -0
  69. package/dist/src/token-storage.d.ts +118 -0
  70. package/dist/src/token-storage.d.ts.map +1 -0
  71. package/dist/src/token-storage.js +263 -0
  72. package/dist/src/types.d.ts +11 -0
  73. package/dist/src/types.d.ts.map +1 -0
  74. package/dist/src/types.js +7 -0
  75. package/dist/src/webhook-idempotency.d.ts +44 -0
  76. package/dist/src/webhook-idempotency.d.ts.map +1 -0
  77. package/dist/src/webhook-idempotency.js +148 -0
  78. package/dist/src/work-queue.d.ts +120 -0
  79. package/dist/src/work-queue.d.ts.map +1 -0
  80. package/dist/src/work-queue.js +384 -0
  81. package/dist/src/worker-auth.d.ts +29 -0
  82. package/dist/src/worker-auth.d.ts.map +1 -0
  83. package/dist/src/worker-auth.js +49 -0
  84. package/dist/src/worker-storage.d.ts +108 -0
  85. package/dist/src/worker-storage.d.ts.map +1 -0
  86. package/dist/src/worker-storage.js +295 -0
  87. package/dist/src/workflow-state-integration.test.d.ts +2 -0
  88. package/dist/src/workflow-state-integration.test.d.ts.map +1 -0
  89. package/dist/src/workflow-state-integration.test.js +342 -0
  90. package/dist/src/workflow-state.test.d.ts +2 -0
  91. package/dist/src/workflow-state.test.d.ts.map +1 -0
  92. package/dist/src/workflow-state.test.js +113 -0
  93. package/package.json +72 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Structured JSON Logger for AgentFactory Server
3
+ *
4
+ * Provides consistent, structured logging with:
5
+ * - JSON output format for log aggregation
6
+ * - Log levels (debug, info, warn, error)
7
+ * - Context fields (requestId, sessionId, issueId, etc.)
8
+ * - Automatic timestamps
9
+ */
10
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
11
+ export interface LogContext {
12
+ /** Unique request identifier for tracing */
13
+ requestId?: string;
14
+ /** Linear agent session ID */
15
+ sessionId?: string;
16
+ /** Linear issue ID */
17
+ issueId?: string;
18
+ /** Linear issue identifier (e.g., SUP-123) */
19
+ issueIdentifier?: string;
20
+ /** Linear workspace/organization ID */
21
+ workspaceId?: string;
22
+ /** Duration in milliseconds */
23
+ durationMs?: number;
24
+ /** Error object for error logs */
25
+ error?: Error | unknown;
26
+ /** Any additional context fields */
27
+ [key: string]: unknown;
28
+ }
29
+ /**
30
+ * Logger class for structured logging
31
+ */
32
+ declare class Logger {
33
+ private service;
34
+ private defaultContext;
35
+ private minLevel;
36
+ private jsonEnabled;
37
+ constructor(service: string, defaultContext?: LogContext);
38
+ /**
39
+ * Create a child logger with additional default context
40
+ */
41
+ child(context: LogContext): Logger;
42
+ /**
43
+ * Check if a log level should be output
44
+ */
45
+ private shouldLog;
46
+ /**
47
+ * Format and output a log entry
48
+ */
49
+ private log;
50
+ /**
51
+ * Output JSON formatted log
52
+ */
53
+ private outputJson;
54
+ /**
55
+ * Output human-readable log for development
56
+ */
57
+ private outputPretty;
58
+ debug(message: string, context?: LogContext): void;
59
+ info(message: string, context?: LogContext): void;
60
+ warn(message: string, context?: LogContext): void;
61
+ error(message: string, context?: LogContext): void;
62
+ }
63
+ /**
64
+ * Create a logger instance for a service
65
+ */
66
+ export declare function createLogger(service: string, defaultContext?: LogContext): Logger;
67
+ /**
68
+ * Generate a unique request ID
69
+ */
70
+ export declare function generateRequestId(): string;
71
+ /**
72
+ * Default logger instance for the server
73
+ */
74
+ export declare const logger: Logger;
75
+ export {};
76
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAA;IACvB,oCAAoC;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAgFD;;GAEG;AACH,cAAM,MAAM;IACV,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,MAAM,EAAE,cAAc,GAAE,UAAe;IAO5D;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM;IAQlC;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACH,OAAO,CAAC,GAAG;IAuBX;;OAEG;IACH,OAAO,CAAC,UAAU;IAclB;;OAEG;IACH,OAAO,CAAC,YAAY;IAiDpB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIlD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;IAIjD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI;CAGnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,UAAe,GAC9B,MAAM,CAER;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,QAAsC,CAAA"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Structured JSON Logger for AgentFactory Server
3
+ *
4
+ * Provides consistent, structured logging with:
5
+ * - JSON output format for log aggregation
6
+ * - Log levels (debug, info, warn, error)
7
+ * - Context fields (requestId, sessionId, issueId, etc.)
8
+ * - Automatic timestamps
9
+ */
10
+ /**
11
+ * Log level priority for filtering
12
+ */
13
+ const LOG_LEVEL_PRIORITY = {
14
+ debug: 0,
15
+ info: 1,
16
+ warn: 2,
17
+ error: 3,
18
+ };
19
+ /**
20
+ * Get the minimum log level from environment
21
+ * Defaults to 'info' in production, 'debug' in development
22
+ */
23
+ function getMinLogLevel() {
24
+ const envLevel = process.env.LOG_LEVEL?.toLowerCase();
25
+ if (envLevel && envLevel in LOG_LEVEL_PRIORITY) {
26
+ return envLevel;
27
+ }
28
+ return process.env.NODE_ENV === 'production' ? 'info' : 'debug';
29
+ }
30
+ /**
31
+ * Check if JSON logging is enabled
32
+ * Defaults to true in production, false in development for readability
33
+ */
34
+ function isJsonLoggingEnabled() {
35
+ const envValue = process.env.LOG_JSON;
36
+ if (envValue !== undefined) {
37
+ return envValue === 'true' || envValue === '1';
38
+ }
39
+ return process.env.NODE_ENV === 'production';
40
+ }
41
+ /**
42
+ * Format an error for logging
43
+ */
44
+ function formatError(error) {
45
+ if (error instanceof Error) {
46
+ return {
47
+ name: error.name,
48
+ message: error.message,
49
+ stack: error.stack,
50
+ ...(error.cause ? { cause: formatError(error.cause) } : {}),
51
+ };
52
+ }
53
+ return { message: String(error) };
54
+ }
55
+ /**
56
+ * Format context for logging, handling special cases
57
+ */
58
+ function formatContext(context) {
59
+ const formatted = {};
60
+ for (const [key, value] of Object.entries(context)) {
61
+ if (value === undefined)
62
+ continue;
63
+ if (key === 'error') {
64
+ formatted.error = formatError(value);
65
+ }
66
+ else if (value instanceof Error) {
67
+ formatted[key] = formatError(value);
68
+ }
69
+ else {
70
+ formatted[key] = value;
71
+ }
72
+ }
73
+ return formatted;
74
+ }
75
+ /**
76
+ * Logger class for structured logging
77
+ */
78
+ class Logger {
79
+ service;
80
+ defaultContext;
81
+ minLevel;
82
+ jsonEnabled;
83
+ constructor(service, defaultContext = {}) {
84
+ this.service = service;
85
+ this.defaultContext = defaultContext;
86
+ this.minLevel = getMinLogLevel();
87
+ this.jsonEnabled = isJsonLoggingEnabled();
88
+ }
89
+ /**
90
+ * Create a child logger with additional default context
91
+ */
92
+ child(context) {
93
+ const child = new Logger(this.service, {
94
+ ...this.defaultContext,
95
+ ...context,
96
+ });
97
+ return child;
98
+ }
99
+ /**
100
+ * Check if a log level should be output
101
+ */
102
+ shouldLog(level) {
103
+ return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[this.minLevel];
104
+ }
105
+ /**
106
+ * Format and output a log entry
107
+ */
108
+ log(level, message, context = {}) {
109
+ if (!this.shouldLog(level))
110
+ return;
111
+ const mergedContext = { ...this.defaultContext, ...context };
112
+ const formattedContext = formatContext(mergedContext);
113
+ const entry = {
114
+ timestamp: new Date().toISOString(),
115
+ level,
116
+ message,
117
+ service: this.service,
118
+ ...(Object.keys(formattedContext).length > 0
119
+ ? { context: formattedContext }
120
+ : {}),
121
+ };
122
+ if (this.jsonEnabled) {
123
+ this.outputJson(level, entry);
124
+ }
125
+ else {
126
+ this.outputPretty(level, entry);
127
+ }
128
+ }
129
+ /**
130
+ * Output JSON formatted log
131
+ */
132
+ outputJson(level, entry) {
133
+ const output = JSON.stringify(entry);
134
+ switch (level) {
135
+ case 'error':
136
+ console.error(output);
137
+ break;
138
+ case 'warn':
139
+ console.warn(output);
140
+ break;
141
+ default:
142
+ console.log(output);
143
+ }
144
+ }
145
+ /**
146
+ * Output human-readable log for development
147
+ */
148
+ outputPretty(level, entry) {
149
+ const levelColors = {
150
+ debug: '\x1b[36m', // cyan
151
+ info: '\x1b[32m', // green
152
+ warn: '\x1b[33m', // yellow
153
+ error: '\x1b[31m', // red
154
+ };
155
+ const reset = '\x1b[0m';
156
+ const dim = '\x1b[2m';
157
+ const color = levelColors[level];
158
+ const levelStr = level.toUpperCase().padEnd(5);
159
+ const time = entry.timestamp.split('T')[1].replace('Z', '');
160
+ let output = `${dim}${time}${reset} ${color}${levelStr}${reset} [${entry.service}] ${entry.message}`;
161
+ if (entry.context && Object.keys(entry.context).length > 0) {
162
+ const contextStr = Object.entries(entry.context)
163
+ .filter(([key]) => key !== 'error')
164
+ .map(([key, value]) => `${key}=${JSON.stringify(value)}`)
165
+ .join(' ');
166
+ if (contextStr) {
167
+ output += ` ${dim}${contextStr}${reset}`;
168
+ }
169
+ // Print error details on separate lines
170
+ if (entry.context.error) {
171
+ const err = entry.context.error;
172
+ output += `\n ${color}${err.name}: ${err.message}${reset}`;
173
+ if (err.stack) {
174
+ const stackLines = err.stack.split('\n').slice(1, 4);
175
+ output += `\n${dim}${stackLines.join('\n')}${reset}`;
176
+ }
177
+ }
178
+ }
179
+ switch (level) {
180
+ case 'error':
181
+ console.error(output);
182
+ break;
183
+ case 'warn':
184
+ console.warn(output);
185
+ break;
186
+ default:
187
+ console.log(output);
188
+ }
189
+ }
190
+ debug(message, context) {
191
+ this.log('debug', message, context);
192
+ }
193
+ info(message, context) {
194
+ this.log('info', message, context);
195
+ }
196
+ warn(message, context) {
197
+ this.log('warn', message, context);
198
+ }
199
+ error(message, context) {
200
+ this.log('error', message, context);
201
+ }
202
+ }
203
+ /**
204
+ * Create a logger instance for a service
205
+ */
206
+ export function createLogger(service, defaultContext = {}) {
207
+ return new Logger(service, defaultContext);
208
+ }
209
+ /**
210
+ * Generate a unique request ID
211
+ */
212
+ export function generateRequestId() {
213
+ return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
214
+ }
215
+ /**
216
+ * Default logger instance for the server
217
+ */
218
+ export const logger = createLogger('agentfactory-server');
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Orphan Cleanup Module
3
+ *
4
+ * Detects and handles orphaned sessions - sessions marked as running/claimed
5
+ * but whose worker is no longer active (heartbeat timeout).
6
+ *
7
+ * When a worker disconnects, the work is re-queued for another worker to resume.
8
+ * The Linear issue status is NOT rolled back - the issue remains in its current
9
+ * workflow state and the next worker will resume from where the previous one left off.
10
+ */
11
+ import { type AgentSessionState } from './session-storage.js';
12
+ /**
13
+ * Callback for when an orphaned session is re-queued
14
+ */
15
+ export interface OrphanCleanupCallbacks {
16
+ /** Called when an orphaned session is re-queued. Use to post Linear comments, etc. */
17
+ onOrphanRequeued?: (session: AgentSessionState) => Promise<void>;
18
+ /** Called when a zombie pending session is recovered. Use to post Linear comments, etc. */
19
+ onZombieRecovered?: (session: AgentSessionState) => Promise<void>;
20
+ }
21
+ export interface OrphanCleanupResult {
22
+ checked: number;
23
+ orphaned: number;
24
+ requeued: number;
25
+ failed: number;
26
+ details: Array<{
27
+ sessionId: string;
28
+ issueIdentifier: string;
29
+ action: 'requeued' | 'failed';
30
+ reason?: string;
31
+ /** Path to worktree that may need cleanup (if on worker machine) */
32
+ worktreePath?: string;
33
+ }>;
34
+ /** Worktree paths that need cleanup on worker machines */
35
+ worktreePathsToCleanup: string[];
36
+ }
37
+ /**
38
+ * Find sessions that are orphaned (running/claimed but worker is gone)
39
+ */
40
+ export declare function findOrphanedSessions(): Promise<AgentSessionState[]>;
41
+ /**
42
+ * Find zombie pending sessions — sessions stuck in `pending` status
43
+ * that have no corresponding entry in the work queue or any issue-pending queue.
44
+ *
45
+ * These arise when:
46
+ * - claimWork() removes from queue, but claimSession() fails and requeue also fails
47
+ * - Issue lock expires but promotion fails silently
48
+ */
49
+ export declare function findZombiePendingSessions(): Promise<AgentSessionState[]>;
50
+ /**
51
+ * Clean up orphaned sessions by re-queuing them
52
+ *
53
+ * @param callbacks - Optional callbacks for external integrations (e.g., posting Linear comments)
54
+ */
55
+ export declare function cleanupOrphanedSessions(callbacks?: OrphanCleanupCallbacks): Promise<OrphanCleanupResult>;
56
+ export declare function shouldRunCleanup(): boolean;
57
+ /**
58
+ * Run cleanup if enough time has passed (debounced)
59
+ * Safe to call frequently - will only actually run periodically
60
+ *
61
+ * @param callbacks - Optional callbacks for external integrations
62
+ */
63
+ export declare function maybeCleanupOrphans(callbacks?: OrphanCleanupCallbacks): Promise<OrphanCleanupResult | null>;
64
+ //# sourceMappingURL=orphan-cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orphan-cleanup.d.ts","sourceRoot":"","sources":["../../src/orphan-cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAA;AAqB7B;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,sFAAsF;IACtF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,2FAA2F;IAC3F,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAClE;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,KAAK,CAAC;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,eAAe,EAAE,MAAM,CAAA;QACvB,MAAM,EAAE,UAAU,GAAG,QAAQ,CAAA;QAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,oEAAoE;QACpE,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAC,CAAA;IACF,0DAA0D;IAC1D,sBAAsB,EAAE,MAAM,EAAE,CAAA;CACjC;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAuDzE;AAKD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiC9E;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,CAAC,EAAE,sBAAsB,GACjC,OAAO,CAAC,mBAAmB,CAAC,CAyP9B;AASD,wBAAgB,gBAAgB,IAAI,OAAO,CAO1C;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,CAAC,EAAE,sBAAsB,GACjC,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAKrC"}