@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.
- package/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/src/a2a-server.d.ts +88 -0
- package/dist/src/a2a-server.d.ts.map +1 -0
- package/dist/src/a2a-server.integration.test.d.ts +9 -0
- package/dist/src/a2a-server.integration.test.d.ts.map +1 -0
- package/dist/src/a2a-server.integration.test.js +397 -0
- package/dist/src/a2a-server.js +235 -0
- package/dist/src/a2a-server.test.d.ts +2 -0
- package/dist/src/a2a-server.test.d.ts.map +1 -0
- package/dist/src/a2a-server.test.js +311 -0
- package/dist/src/a2a-types.d.ts +125 -0
- package/dist/src/a2a-types.d.ts.map +1 -0
- package/dist/src/a2a-types.js +8 -0
- package/dist/src/agent-tracking.d.ts +201 -0
- package/dist/src/agent-tracking.d.ts.map +1 -0
- package/dist/src/agent-tracking.js +349 -0
- package/dist/src/env-validation.d.ts +65 -0
- package/dist/src/env-validation.d.ts.map +1 -0
- package/dist/src/env-validation.js +134 -0
- package/dist/src/governor-dedup.d.ts +15 -0
- package/dist/src/governor-dedup.d.ts.map +1 -0
- package/dist/src/governor-dedup.js +31 -0
- package/dist/src/governor-event-bus.d.ts +54 -0
- package/dist/src/governor-event-bus.d.ts.map +1 -0
- package/dist/src/governor-event-bus.js +152 -0
- package/dist/src/governor-storage.d.ts +28 -0
- package/dist/src/governor-storage.d.ts.map +1 -0
- package/dist/src/governor-storage.js +52 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +50 -0
- package/dist/src/issue-lock.d.ts +129 -0
- package/dist/src/issue-lock.d.ts.map +1 -0
- package/dist/src/issue-lock.js +508 -0
- package/dist/src/logger.d.ts +76 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +218 -0
- package/dist/src/orphan-cleanup.d.ts +64 -0
- package/dist/src/orphan-cleanup.d.ts.map +1 -0
- package/dist/src/orphan-cleanup.js +369 -0
- package/dist/src/pending-prompts.d.ts +67 -0
- package/dist/src/pending-prompts.d.ts.map +1 -0
- package/dist/src/pending-prompts.js +176 -0
- package/dist/src/processing-state-storage.d.ts +38 -0
- package/dist/src/processing-state-storage.d.ts.map +1 -0
- package/dist/src/processing-state-storage.js +61 -0
- package/dist/src/quota-tracker.d.ts +62 -0
- package/dist/src/quota-tracker.d.ts.map +1 -0
- package/dist/src/quota-tracker.js +155 -0
- package/dist/src/rate-limit.d.ts +111 -0
- package/dist/src/rate-limit.d.ts.map +1 -0
- package/dist/src/rate-limit.js +171 -0
- package/dist/src/redis-circuit-breaker.d.ts +67 -0
- package/dist/src/redis-circuit-breaker.d.ts.map +1 -0
- package/dist/src/redis-circuit-breaker.js +290 -0
- package/dist/src/redis-rate-limiter.d.ts +51 -0
- package/dist/src/redis-rate-limiter.d.ts.map +1 -0
- package/dist/src/redis-rate-limiter.js +168 -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-hash.d.ts +48 -0
- package/dist/src/session-hash.d.ts.map +1 -0
- package/dist/src/session-hash.js +80 -0
- package/dist/src/session-storage.d.ts +166 -0
- package/dist/src/session-storage.d.ts.map +1 -0
- package/dist/src/session-storage.js +397 -0
- package/dist/src/token-storage.d.ts +118 -0
- package/dist/src/token-storage.d.ts.map +1 -0
- package/dist/src/token-storage.js +263 -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 +120 -0
- package/dist/src/work-queue.d.ts.map +1 -0
- package/dist/src/work-queue.js +384 -0
- package/dist/src/worker-auth.d.ts +29 -0
- package/dist/src/worker-auth.d.ts.map +1 -0
- package/dist/src/worker-auth.js +49 -0
- package/dist/src/worker-storage.d.ts +108 -0
- package/dist/src/worker-storage.d.ts.map +1 -0
- package/dist/src/worker-storage.js +295 -0
- package/dist/src/workflow-state-integration.test.d.ts +2 -0
- package/dist/src/workflow-state-integration.test.d.ts.map +1 -0
- package/dist/src/workflow-state-integration.test.js +342 -0
- package/dist/src/workflow-state.test.d.ts +2 -0
- package/dist/src/workflow-state.test.d.ts.map +1 -0
- package/dist/src/workflow-state.test.js +113 -0
- package/package.json +72 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Tracking Module
|
|
3
|
+
*
|
|
4
|
+
* Tracks which issues the agent has worked on to enable automated QA pickup.
|
|
5
|
+
* Also tracks QA attempts to prevent infinite loops.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Record of an issue that was worked on by an agent
|
|
9
|
+
*/
|
|
10
|
+
export interface AgentWorkRecord {
|
|
11
|
+
issueId: string;
|
|
12
|
+
issueIdentifier: string;
|
|
13
|
+
completedAt: number;
|
|
14
|
+
sessionId: string;
|
|
15
|
+
prUrl?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Record of QA attempts for an issue
|
|
19
|
+
*/
|
|
20
|
+
export interface QAAttemptRecord {
|
|
21
|
+
issueId: string;
|
|
22
|
+
attemptNumber: number;
|
|
23
|
+
startedAt: number;
|
|
24
|
+
sessionId: string;
|
|
25
|
+
previousAttempts: Array<{
|
|
26
|
+
sessionId: string;
|
|
27
|
+
failedAt: number;
|
|
28
|
+
reason?: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Escalation strategy computed deterministically from cycleCount.
|
|
33
|
+
* No LLM in the decision loop — pure function.
|
|
34
|
+
*/
|
|
35
|
+
export type EscalationStrategy = 'normal' | 'context-enriched' | 'decompose' | 'escalate-human';
|
|
36
|
+
/**
|
|
37
|
+
* Workflow phase types
|
|
38
|
+
*/
|
|
39
|
+
export type WorkflowPhase = 'development' | 'qa' | 'refinement' | 'acceptance';
|
|
40
|
+
/**
|
|
41
|
+
* Record of a single phase attempt within a workflow cycle
|
|
42
|
+
*/
|
|
43
|
+
export interface PhaseRecord {
|
|
44
|
+
attempt: number;
|
|
45
|
+
sessionId?: string;
|
|
46
|
+
startedAt: number;
|
|
47
|
+
completedAt?: number;
|
|
48
|
+
result?: 'passed' | 'failed' | 'unknown';
|
|
49
|
+
failureReason?: string;
|
|
50
|
+
costUsd?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Cross-phase workflow state for an issue.
|
|
54
|
+
* Tracks the full dev-QA-rejected cycle count and accumulated failure context.
|
|
55
|
+
* Higher-level overlay on top of the existing QAAttemptRecord.
|
|
56
|
+
*/
|
|
57
|
+
export interface WorkflowState {
|
|
58
|
+
issueId: string;
|
|
59
|
+
issueIdentifier: string;
|
|
60
|
+
cycleCount: number;
|
|
61
|
+
phases: {
|
|
62
|
+
development: PhaseRecord[];
|
|
63
|
+
qa: PhaseRecord[];
|
|
64
|
+
refinement: PhaseRecord[];
|
|
65
|
+
acceptance: PhaseRecord[];
|
|
66
|
+
};
|
|
67
|
+
strategy: EscalationStrategy;
|
|
68
|
+
failureSummary: string | null;
|
|
69
|
+
createdAt: number;
|
|
70
|
+
updatedAt: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Compute escalation strategy deterministically from cycle count.
|
|
74
|
+
* Pure function — no side effects, no LLM.
|
|
75
|
+
*/
|
|
76
|
+
export declare function computeStrategy(cycleCount: number): EscalationStrategy;
|
|
77
|
+
/**
|
|
78
|
+
* Get the workflow state for an issue
|
|
79
|
+
*/
|
|
80
|
+
export declare function getWorkflowState(issueId: string): Promise<WorkflowState | null>;
|
|
81
|
+
/**
|
|
82
|
+
* Update (partial merge) the workflow state for an issue.
|
|
83
|
+
* Creates the state if it doesn't exist.
|
|
84
|
+
*/
|
|
85
|
+
export declare function updateWorkflowState(issueId: string, partial: Partial<Omit<WorkflowState, 'issueId'>> & {
|
|
86
|
+
issueIdentifier?: string;
|
|
87
|
+
}): Promise<WorkflowState>;
|
|
88
|
+
/**
|
|
89
|
+
* Record a phase attempt in the workflow state
|
|
90
|
+
*/
|
|
91
|
+
export declare function recordPhaseAttempt(issueId: string, phase: WorkflowPhase, record: PhaseRecord): Promise<WorkflowState>;
|
|
92
|
+
/**
|
|
93
|
+
* Increment the dev-QA-rejected cycle count and recompute strategy.
|
|
94
|
+
* Called when QA or acceptance fails and triggers a Rejected transition.
|
|
95
|
+
*/
|
|
96
|
+
export declare function incrementCycleCount(issueId: string): Promise<WorkflowState>;
|
|
97
|
+
/**
|
|
98
|
+
* Append a failure reason to the accumulated failure summary.
|
|
99
|
+
* Format: --- Cycle {N}, {phase} Attempt {M} ({timestamp}) ---\n{reason}
|
|
100
|
+
*/
|
|
101
|
+
export declare function appendFailureSummary(issueId: string, newFailure: string): Promise<WorkflowState>;
|
|
102
|
+
/**
|
|
103
|
+
* Clear workflow state for an issue (called on acceptance pass)
|
|
104
|
+
*/
|
|
105
|
+
export declare function clearWorkflowState(issueId: string): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Extract a structured failure reason from an agent's result message.
|
|
108
|
+
* Strips boilerplate and keeps the substantive failure description.
|
|
109
|
+
*/
|
|
110
|
+
export declare function extractFailureReason(resultMessage: string | undefined): string;
|
|
111
|
+
/**
|
|
112
|
+
* Mark an issue as having been worked on by the agent
|
|
113
|
+
*/
|
|
114
|
+
export declare function markAgentWorked(issueId: string, data: Omit<AgentWorkRecord, 'issueId' | 'completedAt'>): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Check if an issue was worked on by the agent
|
|
117
|
+
*/
|
|
118
|
+
export declare function wasAgentWorked(issueId: string): Promise<AgentWorkRecord | null>;
|
|
119
|
+
/**
|
|
120
|
+
* Record a QA attempt for an issue
|
|
121
|
+
*/
|
|
122
|
+
export declare function recordQAAttempt(issueId: string, sessionId: string): Promise<QAAttemptRecord>;
|
|
123
|
+
/**
|
|
124
|
+
* Get QA attempt count for an issue
|
|
125
|
+
*/
|
|
126
|
+
export declare function getQAAttemptCount(issueId: string): Promise<number>;
|
|
127
|
+
/**
|
|
128
|
+
* Mark an issue as having just failed QA (prevents immediate re-trigger)
|
|
129
|
+
*/
|
|
130
|
+
export declare function markQAFailed(issueId: string, reason?: string): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Check if an issue just failed QA (within cooldown period)
|
|
133
|
+
*/
|
|
134
|
+
export declare function didJustFailQA(issueId: string): Promise<boolean>;
|
|
135
|
+
/**
|
|
136
|
+
* Clear QA failed marker (when issue is fixed and moves to Finished again)
|
|
137
|
+
*/
|
|
138
|
+
export declare function clearQAFailed(issueId: string): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Clear agent worked record (e.g., when issue is moved back to Backlog)
|
|
141
|
+
*/
|
|
142
|
+
export declare function clearAgentWorked(issueId: string): Promise<void>;
|
|
143
|
+
/**
|
|
144
|
+
* Clear QA attempt record (e.g., after successful QA)
|
|
145
|
+
*/
|
|
146
|
+
export declare function clearQAAttempts(issueId: string): Promise<void>;
|
|
147
|
+
/**
|
|
148
|
+
* Mark an issue as having development work just queued
|
|
149
|
+
* Prevents rapid re-queuing if status is toggled back and forth
|
|
150
|
+
*/
|
|
151
|
+
export declare function markDevelopmentQueued(issueId: string): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Check if development work was just queued for an issue (within cooldown period)
|
|
154
|
+
*/
|
|
155
|
+
export declare function didJustQueueDevelopment(issueId: string): Promise<boolean>;
|
|
156
|
+
/**
|
|
157
|
+
* Clear development queued marker
|
|
158
|
+
*/
|
|
159
|
+
export declare function clearDevelopmentQueued(issueId: string): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Mark an issue as having acceptance work just queued
|
|
162
|
+
* Prevents rapid re-queuing if status is toggled back and forth
|
|
163
|
+
*/
|
|
164
|
+
export declare function markAcceptanceQueued(issueId: string): Promise<void>;
|
|
165
|
+
/**
|
|
166
|
+
* Check if acceptance work was just queued for an issue (within cooldown period)
|
|
167
|
+
*/
|
|
168
|
+
export declare function didJustQueueAcceptance(issueId: string): Promise<boolean>;
|
|
169
|
+
/**
|
|
170
|
+
* Clear acceptance queued marker
|
|
171
|
+
*/
|
|
172
|
+
export declare function clearAcceptanceQueued(issueId: string): Promise<void>;
|
|
173
|
+
/**
|
|
174
|
+
* Clean up all tracking data for an accepted issue
|
|
175
|
+
* Called after successful acceptance processing to remove all Redis state
|
|
176
|
+
*/
|
|
177
|
+
export declare function cleanupAcceptedIssue(issueId: string): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Maximum total sessions (across all phases) allowed per issue.
|
|
180
|
+
* Once reached, no more automated sessions will be created.
|
|
181
|
+
*/
|
|
182
|
+
export declare const MAX_TOTAL_SESSIONS = 8;
|
|
183
|
+
/**
|
|
184
|
+
* Get the total number of sessions across all workflow phases for an issue.
|
|
185
|
+
* Returns 0 if no workflow state exists.
|
|
186
|
+
*/
|
|
187
|
+
export declare function getTotalSessionCount(issueId: string): Promise<number>;
|
|
188
|
+
/**
|
|
189
|
+
* Mark an issue as having just completed acceptance.
|
|
190
|
+
* Prevents re-triggering acceptance within the cooldown window.
|
|
191
|
+
*/
|
|
192
|
+
export declare function markAcceptanceCompleted(issueId: string): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* Check if acceptance was recently completed for an issue (within cooldown period)
|
|
195
|
+
*/
|
|
196
|
+
export declare function didAcceptanceJustComplete(issueId: string): Promise<boolean>;
|
|
197
|
+
/**
|
|
198
|
+
* Clear acceptance completed marker
|
|
199
|
+
*/
|
|
200
|
+
export declare function clearAcceptanceCompleted(issueId: string): Promise<void>;
|
|
201
|
+
//# sourceMappingURL=agent-tracking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-tracking.d.ts","sourceRoot":"","sources":["../../src/agent-tracking.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Tracking Module
|
|
3
|
+
*
|
|
4
|
+
* Tracks which issues the agent has worked on to enable automated QA pickup.
|
|
5
|
+
* Also tracks QA attempts to prevent infinite loops.
|
|
6
|
+
*/
|
|
7
|
+
import { redisSet, redisGet, redisExists, redisDel } from './redis.js';
|
|
8
|
+
const log = {
|
|
9
|
+
info: (msg, data) => console.log(`[tracking] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
10
|
+
warn: (msg, data) => console.warn(`[tracking] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
11
|
+
error: (msg, data) => console.error(`[tracking] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
12
|
+
debug: (_msg, _data) => { },
|
|
13
|
+
};
|
|
14
|
+
// Redis key prefixes
|
|
15
|
+
const AGENT_WORKED_PREFIX = 'agent:worked:';
|
|
16
|
+
const QA_ATTEMPT_PREFIX = 'qa:attempt:';
|
|
17
|
+
const QA_FAILED_PREFIX = 'qa:failed:';
|
|
18
|
+
const DEV_QUEUED_PREFIX = 'agent:dev-queued:';
|
|
19
|
+
const ACCEPTANCE_QUEUED_PREFIX = 'agent:acceptance-queued:';
|
|
20
|
+
const ACCEPTANCE_COMPLETED_PREFIX = 'agent:acceptance-completed:';
|
|
21
|
+
const WORKFLOW_STATE_PREFIX = 'workflow:state:';
|
|
22
|
+
// TTLs in seconds
|
|
23
|
+
const AGENT_WORKED_TTL = 7 * 24 * 60 * 60; // 7 days
|
|
24
|
+
const QA_ATTEMPT_TTL = 24 * 60 * 60; // 24 hours
|
|
25
|
+
const QA_FAILED_TTL = 60 * 60; // 1 hour
|
|
26
|
+
const DEV_QUEUED_TTL = 300; // 5 minutes
|
|
27
|
+
const ACCEPTANCE_QUEUED_TTL = 300; // 5 minutes
|
|
28
|
+
const ACCEPTANCE_COMPLETED_TTL = 30 * 60; // 30 minutes
|
|
29
|
+
const WORKFLOW_STATE_TTL = 30 * 24 * 60 * 60; // 30 days
|
|
30
|
+
/**
|
|
31
|
+
* Compute escalation strategy deterministically from cycle count.
|
|
32
|
+
* Pure function — no side effects, no LLM.
|
|
33
|
+
*/
|
|
34
|
+
export function computeStrategy(cycleCount) {
|
|
35
|
+
if (cycleCount <= 1)
|
|
36
|
+
return 'normal';
|
|
37
|
+
if (cycleCount === 2)
|
|
38
|
+
return 'context-enriched';
|
|
39
|
+
if (cycleCount === 3)
|
|
40
|
+
return 'decompose';
|
|
41
|
+
return 'escalate-human';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the workflow state for an issue
|
|
45
|
+
*/
|
|
46
|
+
export async function getWorkflowState(issueId) {
|
|
47
|
+
const key = `${WORKFLOW_STATE_PREFIX}${issueId}`;
|
|
48
|
+
return redisGet(key);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Update (partial merge) the workflow state for an issue.
|
|
52
|
+
* Creates the state if it doesn't exist.
|
|
53
|
+
*/
|
|
54
|
+
export async function updateWorkflowState(issueId, partial) {
|
|
55
|
+
const key = `${WORKFLOW_STATE_PREFIX}${issueId}`;
|
|
56
|
+
const existing = await redisGet(key);
|
|
57
|
+
const state = {
|
|
58
|
+
issueId,
|
|
59
|
+
issueIdentifier: partial.issueIdentifier ?? existing?.issueIdentifier ?? '',
|
|
60
|
+
cycleCount: partial.cycleCount ?? existing?.cycleCount ?? 0,
|
|
61
|
+
phases: {
|
|
62
|
+
development: partial.phases?.development ?? existing?.phases?.development ?? [],
|
|
63
|
+
qa: partial.phases?.qa ?? existing?.phases?.qa ?? [],
|
|
64
|
+
refinement: partial.phases?.refinement ?? existing?.phases?.refinement ?? [],
|
|
65
|
+
acceptance: partial.phases?.acceptance ?? existing?.phases?.acceptance ?? [],
|
|
66
|
+
},
|
|
67
|
+
strategy: partial.strategy ?? existing?.strategy ?? 'normal',
|
|
68
|
+
failureSummary: partial.failureSummary !== undefined ? partial.failureSummary : (existing?.failureSummary ?? null),
|
|
69
|
+
createdAt: existing?.createdAt ?? Date.now(),
|
|
70
|
+
updatedAt: Date.now(),
|
|
71
|
+
};
|
|
72
|
+
await redisSet(key, state, WORKFLOW_STATE_TTL);
|
|
73
|
+
return state;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Record a phase attempt in the workflow state
|
|
77
|
+
*/
|
|
78
|
+
export async function recordPhaseAttempt(issueId, phase, record) {
|
|
79
|
+
const existing = await getWorkflowState(issueId);
|
|
80
|
+
const phases = existing?.phases ?? { development: [], qa: [], refinement: [], acceptance: [] };
|
|
81
|
+
phases[phase] = [...phases[phase], record];
|
|
82
|
+
return updateWorkflowState(issueId, { phases });
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Increment the dev-QA-rejected cycle count and recompute strategy.
|
|
86
|
+
* Called when QA or acceptance fails and triggers a Rejected transition.
|
|
87
|
+
*/
|
|
88
|
+
export async function incrementCycleCount(issueId) {
|
|
89
|
+
const existing = await getWorkflowState(issueId);
|
|
90
|
+
const newCount = (existing?.cycleCount ?? 0) + 1;
|
|
91
|
+
const strategy = computeStrategy(newCount);
|
|
92
|
+
log.info('Workflow cycle incremented', { issueId, cycleCount: newCount, strategy });
|
|
93
|
+
return updateWorkflowState(issueId, { cycleCount: newCount, strategy });
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Append a failure reason to the accumulated failure summary.
|
|
97
|
+
* Format: --- Cycle {N}, {phase} Attempt {M} ({timestamp}) ---\n{reason}
|
|
98
|
+
*/
|
|
99
|
+
export async function appendFailureSummary(issueId, newFailure) {
|
|
100
|
+
const existing = await getWorkflowState(issueId);
|
|
101
|
+
const currentSummary = existing?.failureSummary ?? '';
|
|
102
|
+
const updatedSummary = currentSummary
|
|
103
|
+
? `${currentSummary}\n\n${newFailure}`
|
|
104
|
+
: newFailure;
|
|
105
|
+
return updateWorkflowState(issueId, { failureSummary: updatedSummary });
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Clear workflow state for an issue (called on acceptance pass)
|
|
109
|
+
*/
|
|
110
|
+
export async function clearWorkflowState(issueId) {
|
|
111
|
+
const key = `${WORKFLOW_STATE_PREFIX}${issueId}`;
|
|
112
|
+
await redisDel(key);
|
|
113
|
+
log.info('Cleared workflow state', { issueId });
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Extract a structured failure reason from an agent's result message.
|
|
117
|
+
* Strips boilerplate and keeps the substantive failure description.
|
|
118
|
+
*/
|
|
119
|
+
export function extractFailureReason(resultMessage) {
|
|
120
|
+
if (!resultMessage)
|
|
121
|
+
return 'No result message provided';
|
|
122
|
+
// Try to extract from structured sections
|
|
123
|
+
const failurePatterns = [
|
|
124
|
+
/##\s*(?:QA\s+)?(?:Failed|Failure|Issues?\s+Found)[^\n]*\n([\s\S]*?)(?=\n##|\n<!--|\Z)/i,
|
|
125
|
+
/(?:Fail(?:ure|ed)\s+(?:Reason|Details?|Summary)):?\s*([\s\S]*?)(?=\n##|\n<!--|\Z)/i,
|
|
126
|
+
/(?:Issues?\s+Found|Problems?\s+Found):?\s*([\s\S]*?)(?=\n##|\n<!--|\Z)/i,
|
|
127
|
+
];
|
|
128
|
+
for (const pattern of failurePatterns) {
|
|
129
|
+
const match = resultMessage.match(pattern);
|
|
130
|
+
if (match?.[1]) {
|
|
131
|
+
const extracted = match[1].trim();
|
|
132
|
+
if (extracted.length > 20) {
|
|
133
|
+
// Truncate if excessively long
|
|
134
|
+
return extracted.length > 2000 ? extracted.slice(0, 2000) + '...' : extracted;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Fallback: take the last meaningful paragraph (often the conclusion)
|
|
139
|
+
const paragraphs = resultMessage.split(/\n\n+/).filter(p => p.trim().length > 20);
|
|
140
|
+
if (paragraphs.length > 0) {
|
|
141
|
+
const last = paragraphs[paragraphs.length - 1].trim();
|
|
142
|
+
return last.length > 2000 ? last.slice(0, 2000) + '...' : last;
|
|
143
|
+
}
|
|
144
|
+
return resultMessage.slice(0, 500);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Mark an issue as having been worked on by the agent
|
|
148
|
+
*/
|
|
149
|
+
export async function markAgentWorked(issueId, data) {
|
|
150
|
+
const key = `${AGENT_WORKED_PREFIX}${issueId}`;
|
|
151
|
+
const record = {
|
|
152
|
+
...data,
|
|
153
|
+
issueId,
|
|
154
|
+
completedAt: Date.now(),
|
|
155
|
+
};
|
|
156
|
+
await redisSet(key, record, AGENT_WORKED_TTL);
|
|
157
|
+
log.info('Marked agent worked', {
|
|
158
|
+
issueId,
|
|
159
|
+
issueIdentifier: data.issueIdentifier,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Check if an issue was worked on by the agent
|
|
164
|
+
*/
|
|
165
|
+
export async function wasAgentWorked(issueId) {
|
|
166
|
+
const key = `${AGENT_WORKED_PREFIX}${issueId}`;
|
|
167
|
+
return redisGet(key);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Record a QA attempt for an issue
|
|
171
|
+
*/
|
|
172
|
+
export async function recordQAAttempt(issueId, sessionId) {
|
|
173
|
+
const key = `${QA_ATTEMPT_PREFIX}${issueId}`;
|
|
174
|
+
const existing = await redisGet(key);
|
|
175
|
+
const record = {
|
|
176
|
+
issueId,
|
|
177
|
+
attemptNumber: (existing?.attemptNumber ?? 0) + 1,
|
|
178
|
+
startedAt: Date.now(),
|
|
179
|
+
sessionId,
|
|
180
|
+
previousAttempts: existing?.previousAttempts ?? [],
|
|
181
|
+
};
|
|
182
|
+
// Add current attempt to history if this is a retry
|
|
183
|
+
if (existing) {
|
|
184
|
+
record.previousAttempts.push({
|
|
185
|
+
sessionId: existing.sessionId,
|
|
186
|
+
failedAt: Date.now(),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
await redisSet(key, record, QA_ATTEMPT_TTL);
|
|
190
|
+
log.info('Recorded QA attempt', {
|
|
191
|
+
issueId,
|
|
192
|
+
attemptNumber: record.attemptNumber,
|
|
193
|
+
});
|
|
194
|
+
return record;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get QA attempt count for an issue
|
|
198
|
+
*/
|
|
199
|
+
export async function getQAAttemptCount(issueId) {
|
|
200
|
+
const key = `${QA_ATTEMPT_PREFIX}${issueId}`;
|
|
201
|
+
const record = await redisGet(key);
|
|
202
|
+
return record?.attemptNumber ?? 0;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Mark an issue as having just failed QA (prevents immediate re-trigger)
|
|
206
|
+
*/
|
|
207
|
+
export async function markQAFailed(issueId, reason) {
|
|
208
|
+
const key = `${QA_FAILED_PREFIX}${issueId}`;
|
|
209
|
+
await redisSet(key, { failedAt: Date.now(), reason }, QA_FAILED_TTL);
|
|
210
|
+
log.info('Marked QA failed', { issueId, reason });
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Check if an issue just failed QA (within cooldown period)
|
|
214
|
+
*/
|
|
215
|
+
export async function didJustFailQA(issueId) {
|
|
216
|
+
const key = `${QA_FAILED_PREFIX}${issueId}`;
|
|
217
|
+
return redisExists(key);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Clear QA failed marker (when issue is fixed and moves to Finished again)
|
|
221
|
+
*/
|
|
222
|
+
export async function clearQAFailed(issueId) {
|
|
223
|
+
const key = `${QA_FAILED_PREFIX}${issueId}`;
|
|
224
|
+
await redisDel(key);
|
|
225
|
+
log.debug('Cleared QA failed marker', { issueId });
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Clear agent worked record (e.g., when issue is moved back to Backlog)
|
|
229
|
+
*/
|
|
230
|
+
export async function clearAgentWorked(issueId) {
|
|
231
|
+
const key = `${AGENT_WORKED_PREFIX}${issueId}`;
|
|
232
|
+
await redisDel(key);
|
|
233
|
+
log.debug('Cleared agent worked marker', { issueId });
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Clear QA attempt record (e.g., after successful QA)
|
|
237
|
+
*/
|
|
238
|
+
export async function clearQAAttempts(issueId) {
|
|
239
|
+
const key = `${QA_ATTEMPT_PREFIX}${issueId}`;
|
|
240
|
+
await redisDel(key);
|
|
241
|
+
log.debug('Cleared QA attempts', { issueId });
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Mark an issue as having development work just queued
|
|
245
|
+
* Prevents rapid re-queuing if status is toggled back and forth
|
|
246
|
+
*/
|
|
247
|
+
export async function markDevelopmentQueued(issueId) {
|
|
248
|
+
const key = `${DEV_QUEUED_PREFIX}${issueId}`;
|
|
249
|
+
await redisSet(key, { queuedAt: Date.now() }, DEV_QUEUED_TTL);
|
|
250
|
+
log.info('Marked development queued', { issueId });
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Check if development work was just queued for an issue (within cooldown period)
|
|
254
|
+
*/
|
|
255
|
+
export async function didJustQueueDevelopment(issueId) {
|
|
256
|
+
const key = `${DEV_QUEUED_PREFIX}${issueId}`;
|
|
257
|
+
return redisExists(key);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Clear development queued marker
|
|
261
|
+
*/
|
|
262
|
+
export async function clearDevelopmentQueued(issueId) {
|
|
263
|
+
const key = `${DEV_QUEUED_PREFIX}${issueId}`;
|
|
264
|
+
await redisDel(key);
|
|
265
|
+
log.debug('Cleared development queued marker', { issueId });
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Mark an issue as having acceptance work just queued
|
|
269
|
+
* Prevents rapid re-queuing if status is toggled back and forth
|
|
270
|
+
*/
|
|
271
|
+
export async function markAcceptanceQueued(issueId) {
|
|
272
|
+
const key = `${ACCEPTANCE_QUEUED_PREFIX}${issueId}`;
|
|
273
|
+
await redisSet(key, { queuedAt: Date.now() }, ACCEPTANCE_QUEUED_TTL);
|
|
274
|
+
log.info('Marked acceptance queued', { issueId });
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Check if acceptance work was just queued for an issue (within cooldown period)
|
|
278
|
+
*/
|
|
279
|
+
export async function didJustQueueAcceptance(issueId) {
|
|
280
|
+
const key = `${ACCEPTANCE_QUEUED_PREFIX}${issueId}`;
|
|
281
|
+
return redisExists(key);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Clear acceptance queued marker
|
|
285
|
+
*/
|
|
286
|
+
export async function clearAcceptanceQueued(issueId) {
|
|
287
|
+
const key = `${ACCEPTANCE_QUEUED_PREFIX}${issueId}`;
|
|
288
|
+
await redisDel(key);
|
|
289
|
+
log.debug('Cleared acceptance queued marker', { issueId });
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Clean up all tracking data for an accepted issue
|
|
293
|
+
* Called after successful acceptance processing to remove all Redis state
|
|
294
|
+
*/
|
|
295
|
+
export async function cleanupAcceptedIssue(issueId) {
|
|
296
|
+
const keysToDelete = [
|
|
297
|
+
`${AGENT_WORKED_PREFIX}${issueId}`,
|
|
298
|
+
`${QA_ATTEMPT_PREFIX}${issueId}`,
|
|
299
|
+
`${QA_FAILED_PREFIX}${issueId}`,
|
|
300
|
+
`${DEV_QUEUED_PREFIX}${issueId}`,
|
|
301
|
+
`${ACCEPTANCE_QUEUED_PREFIX}${issueId}`,
|
|
302
|
+
`${ACCEPTANCE_COMPLETED_PREFIX}${issueId}`,
|
|
303
|
+
`${WORKFLOW_STATE_PREFIX}${issueId}`,
|
|
304
|
+
];
|
|
305
|
+
await Promise.all(keysToDelete.map((key) => redisDel(key)));
|
|
306
|
+
log.info('Cleaned up all tracking data for accepted issue', { issueId });
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Maximum total sessions (across all phases) allowed per issue.
|
|
310
|
+
* Once reached, no more automated sessions will be created.
|
|
311
|
+
*/
|
|
312
|
+
export const MAX_TOTAL_SESSIONS = 8;
|
|
313
|
+
/**
|
|
314
|
+
* Get the total number of sessions across all workflow phases for an issue.
|
|
315
|
+
* Returns 0 if no workflow state exists.
|
|
316
|
+
*/
|
|
317
|
+
export async function getTotalSessionCount(issueId) {
|
|
318
|
+
const state = await getWorkflowState(issueId);
|
|
319
|
+
if (!state)
|
|
320
|
+
return 0;
|
|
321
|
+
return (state.phases.development.length +
|
|
322
|
+
state.phases.qa.length +
|
|
323
|
+
state.phases.refinement.length +
|
|
324
|
+
state.phases.acceptance.length);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Mark an issue as having just completed acceptance.
|
|
328
|
+
* Prevents re-triggering acceptance within the cooldown window.
|
|
329
|
+
*/
|
|
330
|
+
export async function markAcceptanceCompleted(issueId) {
|
|
331
|
+
const key = `${ACCEPTANCE_COMPLETED_PREFIX}${issueId}`;
|
|
332
|
+
await redisSet(key, { completedAt: Date.now() }, ACCEPTANCE_COMPLETED_TTL);
|
|
333
|
+
log.info('Marked acceptance completed', { issueId });
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Check if acceptance was recently completed for an issue (within cooldown period)
|
|
337
|
+
*/
|
|
338
|
+
export async function didAcceptanceJustComplete(issueId) {
|
|
339
|
+
const key = `${ACCEPTANCE_COMPLETED_PREFIX}${issueId}`;
|
|
340
|
+
return redisExists(key);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Clear acceptance completed marker
|
|
344
|
+
*/
|
|
345
|
+
export async function clearAcceptanceCompleted(issueId) {
|
|
346
|
+
const key = `${ACCEPTANCE_COMPLETED_PREFIX}${issueId}`;
|
|
347
|
+
await redisDel(key);
|
|
348
|
+
log.debug('Cleared acceptance completed marker', { issueId });
|
|
349
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Variable Validation
|
|
3
|
+
*
|
|
4
|
+
* Validates required environment variables on startup.
|
|
5
|
+
* Fails fast if critical security variables are missing in production.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for environment validation
|
|
9
|
+
*/
|
|
10
|
+
export interface EnvValidationConfig {
|
|
11
|
+
/** Variable names required in production */
|
|
12
|
+
requiredVars?: string[];
|
|
13
|
+
/** Variables that need minimum length validation */
|
|
14
|
+
minLengthVars?: Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
minLength: number;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validation result
|
|
21
|
+
*/
|
|
22
|
+
export interface EnvValidationResult {
|
|
23
|
+
valid: boolean;
|
|
24
|
+
missing: string[];
|
|
25
|
+
warnings: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate environment variables
|
|
29
|
+
*
|
|
30
|
+
* In production: All required vars must be present
|
|
31
|
+
* In development: Log warnings for missing vars but don't fail
|
|
32
|
+
*
|
|
33
|
+
* @param config - Optional configuration to override defaults
|
|
34
|
+
* @returns Validation result with missing vars
|
|
35
|
+
*/
|
|
36
|
+
export declare function validateEnv(config?: EnvValidationConfig): EnvValidationResult;
|
|
37
|
+
/**
|
|
38
|
+
* Validate and fail fast if critical vars are missing
|
|
39
|
+
*
|
|
40
|
+
* Call this at application startup to ensure required
|
|
41
|
+
* environment variables are configured.
|
|
42
|
+
*
|
|
43
|
+
* @param config - Optional configuration to override defaults
|
|
44
|
+
* @throws Error if required vars are missing in production
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateEnvOrThrow(config?: EnvValidationConfig): void;
|
|
47
|
+
/**
|
|
48
|
+
* Check if webhook signature verification is configured
|
|
49
|
+
*/
|
|
50
|
+
export declare function isWebhookSecretConfigured(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Check if cron authentication is configured
|
|
53
|
+
*/
|
|
54
|
+
export declare function isCronSecretConfigured(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Check if session hashing is configured
|
|
57
|
+
*/
|
|
58
|
+
export declare function isSessionHashConfigured(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Get session hash salt
|
|
61
|
+
* @param saltEnvVar - Environment variable name for the salt (default: SESSION_HASH_SALT)
|
|
62
|
+
* @throws Error if not configured
|
|
63
|
+
*/
|
|
64
|
+
export declare function getSessionHashSalt(saltEnvVar?: string): string;
|
|
65
|
+
//# sourceMappingURL=env-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-validation.d.ts","sourceRoot":"","sources":["../../src/env-validation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,oDAAoD;IACpD,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC3D;AA8BD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,CAkC7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAsBrE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAGjD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,SAAsB,GAAG,MAAM,CAM3E"}
|