@cleocode/core 2026.3.45 → 2026.3.46
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/bootstrap.d.ts.map +1 -1
- package/dist/index.js +1475 -372
- package/dist/index.js.map +4 -4
- package/dist/init.d.ts.map +1 -1
- package/dist/injection.d.ts +1 -1
- package/dist/injection.d.ts.map +1 -1
- package/dist/routing/capability-matrix.d.ts +6 -4
- package/dist/routing/capability-matrix.d.ts.map +1 -1
- package/dist/scaffold.d.ts +16 -9
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/skills/agents/install.d.ts.map +1 -1
- package/dist/skills/routing-table.d.ts +17 -16
- package/dist/skills/routing-table.d.ts.map +1 -1
- package/dist/skills/skill-paths.d.ts.map +1 -1
- package/dist/system/health.d.ts.map +1 -1
- package/dist/ui/index.d.ts +0 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/package.json +9 -4
- package/schemas/adr-frontmatter.schema.json +72 -0
- package/schemas/agent-configs.schema.json +120 -0
- package/schemas/agent-registry.json +243 -0
- package/schemas/agent-registry.schema.json +132 -0
- package/schemas/archive/research-manifest.schema.json +257 -0
- package/schemas/archive.schema.json +450 -0
- package/schemas/brain-decision.schema.json +69 -0
- package/schemas/brain-learning.schema.json +57 -0
- package/schemas/brain-pattern.schema.json +72 -0
- package/schemas/config.schema.json +2606 -0
- package/schemas/context-state.schema.json +137 -0
- package/schemas/contribution.schema.json +722 -0
- package/schemas/critical-path.schema.json +246 -0
- package/schemas/deps-cache.schema.json +97 -0
- package/schemas/doctor-output.schema.json +283 -0
- package/schemas/error.schema.json +161 -0
- package/schemas/export-package.schema.json +375 -0
- package/schemas/global-config.schema.json +219 -0
- package/schemas/grade.schema.json +49 -0
- package/schemas/log.schema.json +250 -0
- package/schemas/metrics.schema.json +328 -0
- package/schemas/migrations.schema.json +150 -0
- package/schemas/nexus-registry.schema.json +90 -0
- package/schemas/operation-constitution.schema.json +438 -0
- package/schemas/output.schema.json +164 -0
- package/schemas/project-context.schema.json +164 -0
- package/schemas/project-info.schema.json +180 -0
- package/schemas/projects-registry.schema.json +107 -0
- package/schemas/protocol-frontmatter.schema.json +72 -0
- package/schemas/rcasd-consensus-report.schema.json +10 -0
- package/schemas/rcasd-evidence.schema.json +42 -0
- package/schemas/rcasd-gate-result.schema.json +46 -0
- package/schemas/rcasd-hitl-resolution.schema.json +10 -0
- package/schemas/rcasd-index.schema.json +10 -0
- package/schemas/rcasd-manifest.schema.json +10 -0
- package/schemas/rcasd-research-output.schema.json +10 -0
- package/schemas/rcasd-spec-frontmatter.schema.json +10 -0
- package/schemas/rcasd-stage-transition.schema.json +38 -0
- package/schemas/releases.schema.json +267 -0
- package/schemas/skills-manifest.schema.json +91 -0
- package/schemas/skillsmp.schema.json +208 -0
- package/schemas/spec-index.schema.json +196 -0
- package/schemas/system-flow-atlas.schema.json +125 -0
- package/src/__tests__/injection-chain.test.ts +11 -10
- package/src/__tests__/injection-mvi-tiers.test.ts +4 -2
- package/src/agents/__tests__/capacity.test.d.ts +7 -0
- package/src/agents/__tests__/capacity.test.d.ts.map +1 -0
- package/src/agents/__tests__/capacity.test.js +173 -0
- package/src/agents/__tests__/capacity.test.js.map +1 -0
- package/src/agents/__tests__/registry.test.d.ts +8 -0
- package/src/agents/__tests__/registry.test.d.ts.map +1 -0
- package/src/agents/__tests__/registry.test.js +348 -0
- package/src/agents/__tests__/registry.test.js.map +1 -0
- package/src/agents/__tests__/retry.test.d.ts +7 -0
- package/src/agents/__tests__/retry.test.d.ts.map +1 -0
- package/src/agents/__tests__/retry.test.js +225 -0
- package/src/agents/__tests__/retry.test.js.map +1 -0
- package/src/bootstrap.ts +3 -1
- package/src/init.ts +63 -18
- package/src/injection.ts +11 -5
- package/src/intelligence/__tests__/impact.test.d.ts +15 -0
- package/src/intelligence/__tests__/impact.test.d.ts.map +1 -0
- package/src/intelligence/__tests__/impact.test.js +384 -0
- package/src/intelligence/__tests__/impact.test.js.map +1 -0
- package/src/intelligence/__tests__/patterns.test.d.ts +8 -0
- package/src/intelligence/__tests__/patterns.test.d.ts.map +1 -0
- package/src/intelligence/__tests__/patterns.test.js +370 -0
- package/src/intelligence/__tests__/patterns.test.js.map +1 -0
- package/src/intelligence/__tests__/prediction.test.d.ts +8 -0
- package/src/intelligence/__tests__/prediction.test.d.ts.map +1 -0
- package/src/intelligence/__tests__/prediction.test.js +314 -0
- package/src/intelligence/__tests__/prediction.test.js.map +1 -0
- package/src/nexus/__tests__/nexus-e2e.test.d.ts +12 -0
- package/src/nexus/__tests__/nexus-e2e.test.d.ts.map +1 -0
- package/src/nexus/__tests__/nexus-e2e.test.js +1220 -0
- package/src/nexus/__tests__/nexus-e2e.test.js.map +1 -0
- package/src/nexus/__tests__/transfer.test.d.ts +8 -0
- package/src/nexus/__tests__/transfer.test.d.ts.map +1 -0
- package/src/nexus/__tests__/transfer.test.js +372 -0
- package/src/nexus/__tests__/transfer.test.js.map +1 -0
- package/src/nexus/__tests__/transfer.test.ts +1 -1
- package/src/routing/capability-matrix.ts +1435 -205
- package/src/scaffold.ts +18 -11
- package/src/skills/__tests__/routing-table.test.ts +53 -33
- package/src/skills/agents/install.ts +9 -1
- package/src/skills/routing-table.ts +39 -253
- package/src/skills/skill-paths.ts +3 -2
- package/src/store/__tests__/project-detect.test.ts +1 -1
- package/src/system/health.ts +18 -7
- package/src/ui/index.ts +0 -6
- package/src/validation/operation-gate-validators.ts +2 -2
- package/templates/CLEO-INJECTION.md +120 -0
- package/templates/README.md +29 -0
- package/templates/agent-registry.json +305 -0
- package/templates/cleo-gitignore +74 -0
- package/templates/config.template.json +187 -0
- package/templates/git-hooks/commit-msg +149 -0
- package/templates/git-hooks/pre-commit +40 -0
- package/templates/git-hooks/pre-push +79 -0
- package/templates/github/ISSUE_TEMPLATE/bug_report.yml +143 -0
- package/templates/github/ISSUE_TEMPLATE/config.yml +8 -0
- package/templates/github/ISSUE_TEMPLATE/feature_request.yml +125 -0
- package/templates/github/ISSUE_TEMPLATE/help_question.yml +99 -0
- package/templates/global-config.template.json +56 -0
- package/templates/hooks/precompact-safestop.sh +89 -0
- package/templates/issue-templates/bug_report.yml +143 -0
- package/templates/issue-templates/config.yml +8 -0
- package/templates/issue-templates/feature_request.yml +125 -0
- package/templates/issue-templates/help_question.yml +99 -0
- package/templates/skillsmp.json.example +28 -0
- package/templates/skillsmp.json.example.md +214 -0
- package/dist/ui/injection-legacy.d.ts +0 -26
- package/dist/ui/injection-legacy.d.ts.map +0 -1
- package/src/ui/__tests__/injection-registry.test.d.ts +0 -11
- package/src/ui/__tests__/injection-registry.test.d.ts.map +0 -1
- package/src/ui/__tests__/injection-registry.test.js +0 -46
- package/src/ui/__tests__/injection-registry.test.js.map +0 -1
- package/src/ui/__tests__/injection-registry.test.ts +0 -57
- package/src/ui/injection-legacy.ts +0 -44
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the Agent dimension: registry CRUD, heartbeat protocol,
|
|
3
|
+
* crash detection, error classification, and health reporting.
|
|
4
|
+
*
|
|
5
|
+
* @module agents/__tests__/registry.test
|
|
6
|
+
*/
|
|
7
|
+
import { mkdir, mkdtemp, rm } from 'node:fs/promises';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
11
|
+
import { checkAgentHealth, classifyError, deregisterAgent, generateAgentId, getAgentErrorHistory, getAgentInstance, getHealthReport, heartbeat, incrementTasksCompleted, listAgentInstances, markCrashed, registerAgent, updateAgentStatus, } from '../registry.js';
|
|
12
|
+
describe('Agent Registry', () => {
|
|
13
|
+
let tempDir;
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
tempDir = await mkdtemp(join(tmpdir(), 'cleo-agent-test-'));
|
|
16
|
+
await mkdir(join(tempDir, '.cleo'), { recursive: true });
|
|
17
|
+
await mkdir(join(tempDir, '.cleo', 'backups', 'operational'), { recursive: true });
|
|
18
|
+
});
|
|
19
|
+
afterEach(async () => {
|
|
20
|
+
try {
|
|
21
|
+
const { closeAllDatabases } = await import('../../store/sqlite.js');
|
|
22
|
+
await closeAllDatabases();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
/* module may not be loaded */
|
|
26
|
+
}
|
|
27
|
+
await Promise.race([
|
|
28
|
+
rm(tempDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 300 }).catch(() => { }),
|
|
29
|
+
new Promise((resolve) => setTimeout(resolve, 8_000)),
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
// ==========================================================================
|
|
33
|
+
// ID generation
|
|
34
|
+
// ==========================================================================
|
|
35
|
+
describe('generateAgentId', () => {
|
|
36
|
+
it('generates IDs with agt_ prefix', () => {
|
|
37
|
+
const id = generateAgentId();
|
|
38
|
+
expect(id).toMatch(/^agt_\d{14}_[0-9a-f]{6}$/);
|
|
39
|
+
});
|
|
40
|
+
it('generates unique IDs', () => {
|
|
41
|
+
const ids = new Set(Array.from({ length: 50 }, () => generateAgentId()));
|
|
42
|
+
expect(ids.size).toBe(50);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
// ==========================================================================
|
|
46
|
+
// Registration CRUD
|
|
47
|
+
// ==========================================================================
|
|
48
|
+
describe('registerAgent', () => {
|
|
49
|
+
it('creates a new agent instance with default values', async () => {
|
|
50
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
51
|
+
expect(agent.id).toMatch(/^agt_/);
|
|
52
|
+
expect(agent.agentType).toBe('executor');
|
|
53
|
+
expect(agent.status).toBe('starting');
|
|
54
|
+
expect(agent.errorCount).toBe(0);
|
|
55
|
+
expect(agent.totalTasksCompleted).toBe(0);
|
|
56
|
+
expect(agent.capacity).toBe('1.0');
|
|
57
|
+
expect(agent.sessionId).toBeNull();
|
|
58
|
+
expect(agent.taskId).toBeNull();
|
|
59
|
+
expect(agent.parentAgentId).toBeNull();
|
|
60
|
+
});
|
|
61
|
+
it('accepts optional session, task, and parent', async () => {
|
|
62
|
+
const agent = await registerAgent({
|
|
63
|
+
agentType: 'researcher',
|
|
64
|
+
sessionId: 'ses_test_123',
|
|
65
|
+
taskId: 'T001',
|
|
66
|
+
parentAgentId: 'agt_parent_abc123',
|
|
67
|
+
}, tempDir);
|
|
68
|
+
expect(agent.sessionId).toBe('ses_test_123');
|
|
69
|
+
expect(agent.taskId).toBe('T001');
|
|
70
|
+
expect(agent.parentAgentId).toBe('agt_parent_abc123');
|
|
71
|
+
});
|
|
72
|
+
it('stores metadata as JSON', async () => {
|
|
73
|
+
const agent = await registerAgent({
|
|
74
|
+
agentType: 'orchestrator',
|
|
75
|
+
metadata: { model: 'opus-4', region: 'us-east' },
|
|
76
|
+
}, tempDir);
|
|
77
|
+
const parsed = JSON.parse(agent.metadataJson ?? '{}');
|
|
78
|
+
expect(parsed.model).toBe('opus-4');
|
|
79
|
+
expect(parsed.region).toBe('us-east');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('getAgentInstance', () => {
|
|
83
|
+
it('returns null for non-existent agent', async () => {
|
|
84
|
+
const result = await getAgentInstance('agt_nonexistent_abc123', tempDir);
|
|
85
|
+
expect(result).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
it('retrieves a registered agent by ID', async () => {
|
|
88
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
89
|
+
const retrieved = await getAgentInstance(agent.id, tempDir);
|
|
90
|
+
expect(retrieved).not.toBeNull();
|
|
91
|
+
expect(retrieved.id).toBe(agent.id);
|
|
92
|
+
expect(retrieved.agentType).toBe('executor');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('deregisterAgent', () => {
|
|
96
|
+
it('marks agent as stopped', async () => {
|
|
97
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
98
|
+
const stopped = await deregisterAgent(agent.id, tempDir);
|
|
99
|
+
expect(stopped).not.toBeNull();
|
|
100
|
+
expect(stopped.status).toBe('stopped');
|
|
101
|
+
expect(stopped.stoppedAt).toBeTruthy();
|
|
102
|
+
});
|
|
103
|
+
it('returns null for non-existent agent', async () => {
|
|
104
|
+
const result = await deregisterAgent('agt_nonexistent_abc123', tempDir);
|
|
105
|
+
expect(result).toBeNull();
|
|
106
|
+
});
|
|
107
|
+
it('is idempotent for already-stopped agents', async () => {
|
|
108
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
109
|
+
await deregisterAgent(agent.id, tempDir);
|
|
110
|
+
const second = await deregisterAgent(agent.id, tempDir);
|
|
111
|
+
expect(second).not.toBeNull();
|
|
112
|
+
expect(second.status).toBe('stopped');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('listAgentInstances', () => {
|
|
116
|
+
it('returns all agents when no filters', async () => {
|
|
117
|
+
await registerAgent({ agentType: 'executor' }, tempDir);
|
|
118
|
+
await registerAgent({ agentType: 'researcher' }, tempDir);
|
|
119
|
+
const all = await listAgentInstances(undefined, tempDir);
|
|
120
|
+
expect(all.length).toBe(2);
|
|
121
|
+
});
|
|
122
|
+
it('filters by status', async () => {
|
|
123
|
+
const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
124
|
+
await registerAgent({ agentType: 'researcher' }, tempDir);
|
|
125
|
+
await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
|
|
126
|
+
const active = await listAgentInstances({ status: 'active' }, tempDir);
|
|
127
|
+
expect(active.length).toBe(1);
|
|
128
|
+
expect(active[0].id).toBe(a1.id);
|
|
129
|
+
});
|
|
130
|
+
it('filters by type', async () => {
|
|
131
|
+
await registerAgent({ agentType: 'executor' }, tempDir);
|
|
132
|
+
await registerAgent({ agentType: 'researcher' }, tempDir);
|
|
133
|
+
await registerAgent({ agentType: 'executor' }, tempDir);
|
|
134
|
+
const executors = await listAgentInstances({ agentType: 'executor' }, tempDir);
|
|
135
|
+
expect(executors.length).toBe(2);
|
|
136
|
+
});
|
|
137
|
+
it('filters by multiple statuses', async () => {
|
|
138
|
+
const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
139
|
+
const a2 = await registerAgent({ agentType: 'researcher' }, tempDir);
|
|
140
|
+
await registerAgent({ agentType: 'validator' }, tempDir);
|
|
141
|
+
await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
|
|
142
|
+
await updateAgentStatus(a2.id, { status: 'idle' }, tempDir);
|
|
143
|
+
const activeOrIdle = await listAgentInstances({ status: ['active', 'idle'] }, tempDir);
|
|
144
|
+
expect(activeOrIdle.length).toBe(2);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
// ==========================================================================
|
|
148
|
+
// Heartbeat
|
|
149
|
+
// ==========================================================================
|
|
150
|
+
describe('heartbeat', () => {
|
|
151
|
+
it('updates last_heartbeat and returns current status', async () => {
|
|
152
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
153
|
+
await updateAgentStatus(agent.id, { status: 'active' }, tempDir);
|
|
154
|
+
const status = await heartbeat(agent.id, tempDir);
|
|
155
|
+
expect(status).toBe('active');
|
|
156
|
+
const updated = await getAgentInstance(agent.id, tempDir);
|
|
157
|
+
expect(updated.lastHeartbeat).toBeTruthy();
|
|
158
|
+
});
|
|
159
|
+
it('returns null for non-existent agent', async () => {
|
|
160
|
+
const status = await heartbeat('agt_nonexistent_abc123', tempDir);
|
|
161
|
+
expect(status).toBeNull();
|
|
162
|
+
});
|
|
163
|
+
it('does not update heartbeat for stopped agents', async () => {
|
|
164
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
165
|
+
await deregisterAgent(agent.id, tempDir);
|
|
166
|
+
const status = await heartbeat(agent.id, tempDir);
|
|
167
|
+
expect(status).toBe('stopped');
|
|
168
|
+
});
|
|
169
|
+
it('does not update heartbeat for crashed agents', async () => {
|
|
170
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
171
|
+
await markCrashed(agent.id, 'test crash', tempDir);
|
|
172
|
+
const status = await heartbeat(agent.id, tempDir);
|
|
173
|
+
expect(status).toBe('crashed');
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
// ==========================================================================
|
|
177
|
+
// Status management
|
|
178
|
+
// ==========================================================================
|
|
179
|
+
describe('updateAgentStatus', () => {
|
|
180
|
+
it('updates status', async () => {
|
|
181
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
182
|
+
const updated = await updateAgentStatus(agent.id, { status: 'active' }, tempDir);
|
|
183
|
+
expect(updated).not.toBeNull();
|
|
184
|
+
expect(updated.status).toBe('active');
|
|
185
|
+
});
|
|
186
|
+
it('increments error count on error status', async () => {
|
|
187
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
188
|
+
await updateAgentStatus(agent.id, { status: 'error', error: 'Connection timeout' }, tempDir);
|
|
189
|
+
const updated = await getAgentInstance(agent.id, tempDir);
|
|
190
|
+
expect(updated.errorCount).toBe(1);
|
|
191
|
+
expect(updated.status).toBe('error');
|
|
192
|
+
});
|
|
193
|
+
it('logs error to agent_error_log', async () => {
|
|
194
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
195
|
+
await updateAgentStatus(agent.id, { status: 'error', error: 'SQLITE_BUSY: database is locked' }, tempDir);
|
|
196
|
+
const errors = await getAgentErrorHistory(agent.id, tempDir);
|
|
197
|
+
expect(errors.length).toBe(1);
|
|
198
|
+
expect(errors[0].errorType).toBe('retriable');
|
|
199
|
+
expect(errors[0].message).toBe('SQLITE_BUSY: database is locked');
|
|
200
|
+
});
|
|
201
|
+
it('sets stoppedAt when status is stopped', async () => {
|
|
202
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
203
|
+
const updated = await updateAgentStatus(agent.id, { status: 'stopped' }, tempDir);
|
|
204
|
+
expect(updated.stoppedAt).toBeTruthy();
|
|
205
|
+
});
|
|
206
|
+
it('returns null for non-existent agent', async () => {
|
|
207
|
+
const result = await updateAgentStatus('agt_nonexistent_abc123', { status: 'active' }, tempDir);
|
|
208
|
+
expect(result).toBeNull();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
describe('incrementTasksCompleted', () => {
|
|
212
|
+
it('increments the task counter', async () => {
|
|
213
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
214
|
+
await incrementTasksCompleted(agent.id, tempDir);
|
|
215
|
+
await incrementTasksCompleted(agent.id, tempDir);
|
|
216
|
+
const updated = await getAgentInstance(agent.id, tempDir);
|
|
217
|
+
expect(updated.totalTasksCompleted).toBe(2);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
// ==========================================================================
|
|
221
|
+
// Error classification
|
|
222
|
+
// ==========================================================================
|
|
223
|
+
describe('classifyError', () => {
|
|
224
|
+
it('classifies timeout errors as retriable', () => {
|
|
225
|
+
expect(classifyError(new Error('Connection timeout'))).toBe('retriable');
|
|
226
|
+
});
|
|
227
|
+
it('classifies network errors as retriable', () => {
|
|
228
|
+
expect(classifyError(new Error('ECONNREFUSED'))).toBe('retriable');
|
|
229
|
+
expect(classifyError(new Error('ECONNRESET'))).toBe('retriable');
|
|
230
|
+
expect(classifyError(new Error('ETIMEDOUT'))).toBe('retriable');
|
|
231
|
+
expect(classifyError(new Error('socket hang up'))).toBe('retriable');
|
|
232
|
+
});
|
|
233
|
+
it('classifies rate limit errors as retriable', () => {
|
|
234
|
+
expect(classifyError(new Error('Rate limit exceeded'))).toBe('retriable');
|
|
235
|
+
expect(classifyError(new Error('429 Too Many Requests'))).toBe('retriable');
|
|
236
|
+
expect(classifyError(new Error('503 Service Unavailable'))).toBe('retriable');
|
|
237
|
+
});
|
|
238
|
+
it('classifies SQLite busy as retriable', () => {
|
|
239
|
+
expect(classifyError(new Error('SQLITE_BUSY: database is locked'))).toBe('retriable');
|
|
240
|
+
});
|
|
241
|
+
it('classifies permission errors as permanent', () => {
|
|
242
|
+
expect(classifyError(new Error('Permission denied'))).toBe('permanent');
|
|
243
|
+
expect(classifyError(new Error('EACCES'))).toBe('permanent');
|
|
244
|
+
});
|
|
245
|
+
it('classifies auth errors as permanent', () => {
|
|
246
|
+
expect(classifyError(new Error('401 Unauthorized'))).toBe('permanent');
|
|
247
|
+
expect(classifyError(new Error('403 Forbidden'))).toBe('permanent');
|
|
248
|
+
expect(classifyError(new Error('invalid token'))).toBe('permanent');
|
|
249
|
+
});
|
|
250
|
+
it('classifies constraint errors as permanent', () => {
|
|
251
|
+
expect(classifyError(new Error('SQLITE_CONSTRAINT: UNIQUE violation'))).toBe('permanent');
|
|
252
|
+
});
|
|
253
|
+
it('classifies unknown errors as unknown', () => {
|
|
254
|
+
expect(classifyError(new Error('Something weird happened'))).toBe('unknown');
|
|
255
|
+
});
|
|
256
|
+
it('handles non-Error values', () => {
|
|
257
|
+
expect(classifyError('string error')).toBe('unknown');
|
|
258
|
+
expect(classifyError(42)).toBe('unknown');
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
// ==========================================================================
|
|
262
|
+
// Health monitoring
|
|
263
|
+
// ==========================================================================
|
|
264
|
+
describe('checkAgentHealth', () => {
|
|
265
|
+
it('detects agents with stale heartbeats', async () => {
|
|
266
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
267
|
+
await updateAgentStatus(agent.id, { status: 'active' }, tempDir);
|
|
268
|
+
// Wait briefly so heartbeat is definitively in the past, then use
|
|
269
|
+
// a threshold that guarantees staleness detection on slow CI runners
|
|
270
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
271
|
+
const stale = await checkAgentHealth(10, tempDir);
|
|
272
|
+
expect(stale.length).toBeGreaterThanOrEqual(1);
|
|
273
|
+
expect(stale.some((a) => a.id === agent.id)).toBe(true);
|
|
274
|
+
});
|
|
275
|
+
it('does not flag stopped agents', async () => {
|
|
276
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
277
|
+
await deregisterAgent(agent.id, tempDir);
|
|
278
|
+
const stale = await checkAgentHealth(0, tempDir);
|
|
279
|
+
expect(stale.some((a) => a.id === agent.id)).toBe(false);
|
|
280
|
+
});
|
|
281
|
+
it('returns empty array when all agents are healthy', async () => {
|
|
282
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
283
|
+
await updateAgentStatus(agent.id, { status: 'active' }, tempDir);
|
|
284
|
+
await heartbeat(agent.id, tempDir);
|
|
285
|
+
// Use a large threshold -- agent should be considered healthy
|
|
286
|
+
const stale = await checkAgentHealth(60_000, tempDir);
|
|
287
|
+
expect(stale.some((a) => a.id === agent.id)).toBe(false);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
describe('markCrashed', () => {
|
|
291
|
+
it('marks agent as crashed with error details', async () => {
|
|
292
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
293
|
+
const crashed = await markCrashed(agent.id, 'Out of memory', tempDir);
|
|
294
|
+
expect(crashed).not.toBeNull();
|
|
295
|
+
expect(crashed.status).toBe('crashed');
|
|
296
|
+
expect(crashed.errorCount).toBe(1);
|
|
297
|
+
});
|
|
298
|
+
it('provides default reason when none specified', async () => {
|
|
299
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
300
|
+
await markCrashed(agent.id, undefined, tempDir);
|
|
301
|
+
const errors = await getAgentErrorHistory(agent.id, tempDir);
|
|
302
|
+
expect(errors.length).toBe(1);
|
|
303
|
+
expect(errors[0].message).toContain('Heartbeat timeout');
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
describe('getHealthReport', () => {
|
|
307
|
+
it('produces summary of all agent states', async () => {
|
|
308
|
+
const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
309
|
+
const a2 = await registerAgent({ agentType: 'researcher' }, tempDir);
|
|
310
|
+
const a3 = await registerAgent({ agentType: 'orchestrator' }, tempDir);
|
|
311
|
+
await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
|
|
312
|
+
await updateAgentStatus(a2.id, { status: 'idle' }, tempDir);
|
|
313
|
+
await deregisterAgent(a3.id, tempDir);
|
|
314
|
+
const report = await getHealthReport(60_000, tempDir);
|
|
315
|
+
expect(report.total).toBe(3);
|
|
316
|
+
expect(report.active).toBe(1);
|
|
317
|
+
expect(report.idle).toBe(1);
|
|
318
|
+
expect(report.stopped).toBe(1);
|
|
319
|
+
});
|
|
320
|
+
it('counts total errors across all agents', async () => {
|
|
321
|
+
const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
322
|
+
await updateAgentStatus(a1.id, { status: 'error', error: 'err1' }, tempDir);
|
|
323
|
+
await updateAgentStatus(a1.id, { status: 'error', error: 'err2' }, tempDir);
|
|
324
|
+
const report = await getHealthReport(60_000, tempDir);
|
|
325
|
+
expect(report.totalErrors).toBe(2);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
// ==========================================================================
|
|
329
|
+
// Error history
|
|
330
|
+
// ==========================================================================
|
|
331
|
+
describe('getAgentErrorHistory', () => {
|
|
332
|
+
it('returns empty array for agent with no errors', async () => {
|
|
333
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
334
|
+
const errors = await getAgentErrorHistory(agent.id, tempDir);
|
|
335
|
+
expect(errors).toEqual([]);
|
|
336
|
+
});
|
|
337
|
+
it('returns all errors for an agent', async () => {
|
|
338
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
339
|
+
await updateAgentStatus(agent.id, { status: 'error', error: 'timeout' }, tempDir);
|
|
340
|
+
await updateAgentStatus(agent.id, { status: 'error', error: 'ECONNREFUSED' }, tempDir);
|
|
341
|
+
const errors = await getAgentErrorHistory(agent.id, tempDir);
|
|
342
|
+
expect(errors.length).toBe(2);
|
|
343
|
+
expect(errors[0].errorType).toBe('retriable');
|
|
344
|
+
expect(errors[1].errorType).toBe('retriable');
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
//# sourceMappingURL=registry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.test.js","sourceRoot":"","sources":["registry.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAErE,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,uBAAuB,EACvB,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,OAAe,CAAC;IAEpB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;QAC5D,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,CAAC;YACH,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;YACpE,MAAM,iBAAiB,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;QACD,MAAM,OAAO,CAAC,IAAI,CAAC;YACjB,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;YAC7F,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,gBAAgB;IAChB,6EAA6E;IAE7E,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;YAC7B,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;YAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;YACzE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,oBAAoB;IACpB,6EAA6E;IAE7E,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YAEtE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,KAAK,GAAG,MAAM,aAAa,CAC/B;gBACE,SAAS,EAAE,YAAY;gBACvB,SAAS,EAAE,cAAc;gBACzB,MAAM,EAAE,MAAM;gBACd,aAAa,EAAE,mBAAmB;aACnC,EACD,OAAO,CACR,CAAC;YAEF,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC7C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;YACvC,MAAM,KAAK,GAAG,MAAM,aAAa,CAC/B;gBACE,SAAS,EAAE,cAAc;gBACzB,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE;aACjD,EACD,OAAO,CACR,CAAC;YAEF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;YACtD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;YACzE,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAE5D,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YACjC,MAAM,CAAC,SAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACrC,MAAM,CAAC,SAAU,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;YACtC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEzD,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,OAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,OAAQ,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;YACxE,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAExD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,CAAC,MAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACxD,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;YAE1D,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACzD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;YACjC,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACnE,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;YAC1D,MAAM,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YAE9D,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YACvE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;YAC/B,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACxD,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;YAC1D,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YAExD,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YAC/E,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACnE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;YACrE,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;YACzD,MAAM,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YAC9D,MAAM,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;YAE5D,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACvF,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,YAAY;IACZ,6EAA6E;IAE7E,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YAEjE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAE9B,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC1D,MAAM,CAAC,OAAQ,CAAC,aAAa,CAAC,CAAC,UAAU,EAAE,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;YAClE,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEzC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;YAEnD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,oBAAoB;IACpB,6EAA6E;IAE7E,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;YAC9B,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YAEjF,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,OAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,OAAO,CAAC,CAAC;YAE7F,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC1D,MAAM,CAAC,OAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,CAAC,OAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,iBAAiB,CACrB,KAAK,CAAC,EAAE,EACR,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,iCAAiC,EAAE,EAC7D,OAAO,CACR,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;YAElF,MAAM,CAAC,OAAQ,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CACpC,wBAAwB,EACxB,EAAE,MAAM,EAAE,QAAQ,EAAE,EACpB,OAAO,CACR,CAAC;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACvC,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,uBAAuB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,uBAAuB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEjD,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC1D,MAAM,CAAC,OAAQ,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,uBAAuB;IACvB,6EAA6E;IAE7E,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACnE,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACjE,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAChE,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1E,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC5E,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACxE,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvE,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACpE,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC5F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtD,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,oBAAoB;IACpB,6EAA6E;IAE7E,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YAEjE,kEAAkE;YAClE,qEAAqE;YACrE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEzC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YACjE,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEnC,8DAA8D;YAC9D,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;YAEtE,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,OAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,OAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YAEhD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACnE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;YACrE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,OAAO,CAAC,CAAC;YAEvE,MAAM,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;YAC9D,MAAM,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;YAC5D,MAAM,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEtC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAEtD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACnE,MAAM,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;YAC5E,MAAM,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;YAE5E,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,gBAAgB;IAChB,6EAA6E;IAE7E,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;YACtE,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;YAClF,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,OAAO,CAAC,CAAC;YAEvF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.test.d.ts","sourceRoot":"","sources":["retry.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for retry logic, exponential backoff, and self-healing recovery.
|
|
3
|
+
*
|
|
4
|
+
* @module agents/__tests__/retry.test
|
|
5
|
+
*/
|
|
6
|
+
import { mkdir, mkdtemp, rm } from 'node:fs/promises';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
10
|
+
import { registerAgent, updateAgentStatus } from '../registry.js';
|
|
11
|
+
import { calculateDelay, createRetryPolicy, DEFAULT_RETRY_POLICY, recoverCrashedAgents, shouldRetry, withRetry, } from '../retry.js';
|
|
12
|
+
// ==========================================================================
|
|
13
|
+
// Retry Policy
|
|
14
|
+
// ==========================================================================
|
|
15
|
+
describe('Retry Policy', () => {
|
|
16
|
+
describe('createRetryPolicy', () => {
|
|
17
|
+
it('returns default policy when no overrides', () => {
|
|
18
|
+
const policy = createRetryPolicy();
|
|
19
|
+
expect(policy.maxRetries).toBe(3);
|
|
20
|
+
expect(policy.baseDelayMs).toBe(1_000);
|
|
21
|
+
expect(policy.maxDelayMs).toBe(30_000);
|
|
22
|
+
expect(policy.backoffMultiplier).toBe(2);
|
|
23
|
+
expect(policy.jitter).toBe(true);
|
|
24
|
+
expect(policy.retryOnUnknown).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('merges partial overrides with defaults', () => {
|
|
27
|
+
const policy = createRetryPolicy({ maxRetries: 5, baseDelayMs: 500 });
|
|
28
|
+
expect(policy.maxRetries).toBe(5);
|
|
29
|
+
expect(policy.baseDelayMs).toBe(500);
|
|
30
|
+
expect(policy.maxDelayMs).toBe(30_000); // unchanged default
|
|
31
|
+
});
|
|
32
|
+
it('DEFAULT_RETRY_POLICY is frozen', () => {
|
|
33
|
+
expect(Object.isFrozen(DEFAULT_RETRY_POLICY)).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('calculateDelay', () => {
|
|
37
|
+
it('applies exponential backoff', () => {
|
|
38
|
+
const policy = createRetryPolicy({ jitter: false, baseDelayMs: 100, backoffMultiplier: 2 });
|
|
39
|
+
expect(calculateDelay(0, policy)).toBe(100); // 100 * 2^0
|
|
40
|
+
expect(calculateDelay(1, policy)).toBe(200); // 100 * 2^1
|
|
41
|
+
expect(calculateDelay(2, policy)).toBe(400); // 100 * 2^2
|
|
42
|
+
expect(calculateDelay(3, policy)).toBe(800); // 100 * 2^3
|
|
43
|
+
});
|
|
44
|
+
it('caps at maxDelay', () => {
|
|
45
|
+
const policy = createRetryPolicy({
|
|
46
|
+
jitter: false,
|
|
47
|
+
baseDelayMs: 100,
|
|
48
|
+
maxDelayMs: 500,
|
|
49
|
+
backoffMultiplier: 10,
|
|
50
|
+
});
|
|
51
|
+
expect(calculateDelay(0, policy)).toBe(100);
|
|
52
|
+
expect(calculateDelay(1, policy)).toBe(500); // capped
|
|
53
|
+
expect(calculateDelay(2, policy)).toBe(500); // capped
|
|
54
|
+
});
|
|
55
|
+
it('adds jitter when enabled', () => {
|
|
56
|
+
const policy = createRetryPolicy({
|
|
57
|
+
jitter: true,
|
|
58
|
+
baseDelayMs: 1000,
|
|
59
|
+
backoffMultiplier: 1,
|
|
60
|
+
});
|
|
61
|
+
// With jitter, delay should be >= base but <= base * 1.25
|
|
62
|
+
const delays = Array.from({ length: 20 }, () => calculateDelay(0, policy));
|
|
63
|
+
const allInRange = delays.every((d) => d >= 1000 && d <= 1250);
|
|
64
|
+
expect(allInRange).toBe(true);
|
|
65
|
+
// With 20 samples, at least some should differ (jitter is random)
|
|
66
|
+
const uniqueDelays = new Set(delays);
|
|
67
|
+
expect(uniqueDelays.size).toBeGreaterThan(1);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('shouldRetry', () => {
|
|
71
|
+
it('allows retry for retriable errors within limit', () => {
|
|
72
|
+
const policy = createRetryPolicy({ maxRetries: 3 });
|
|
73
|
+
expect(shouldRetry(new Error('ECONNREFUSED'), 0, policy)).toBe(true);
|
|
74
|
+
expect(shouldRetry(new Error('timeout'), 1, policy)).toBe(true);
|
|
75
|
+
expect(shouldRetry(new Error('503 Service Unavailable'), 2, policy)).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
it('denies retry when attempt exceeds maxRetries', () => {
|
|
78
|
+
const policy = createRetryPolicy({ maxRetries: 3 });
|
|
79
|
+
expect(shouldRetry(new Error('ECONNREFUSED'), 3, policy)).toBe(false);
|
|
80
|
+
expect(shouldRetry(new Error('ECONNREFUSED'), 4, policy)).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
it('denies retry for permanent errors', () => {
|
|
83
|
+
const policy = createRetryPolicy({ maxRetries: 10 });
|
|
84
|
+
expect(shouldRetry(new Error('Permission denied'), 0, policy)).toBe(false);
|
|
85
|
+
expect(shouldRetry(new Error('401 Unauthorized'), 0, policy)).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it('respects retryOnUnknown policy', () => {
|
|
88
|
+
const retryUnknown = createRetryPolicy({ retryOnUnknown: true });
|
|
89
|
+
const noRetryUnknown = createRetryPolicy({ retryOnUnknown: false });
|
|
90
|
+
const unknownError = new Error('Something weird');
|
|
91
|
+
expect(shouldRetry(unknownError, 0, retryUnknown)).toBe(true);
|
|
92
|
+
expect(shouldRetry(unknownError, 0, noRetryUnknown)).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
// ==========================================================================
|
|
97
|
+
// withRetry wrapper
|
|
98
|
+
// ==========================================================================
|
|
99
|
+
describe('withRetry', () => {
|
|
100
|
+
it('succeeds on first attempt', async () => {
|
|
101
|
+
let callCount = 0;
|
|
102
|
+
const result = await withRetry(async () => {
|
|
103
|
+
callCount++;
|
|
104
|
+
return 'success';
|
|
105
|
+
});
|
|
106
|
+
expect(result.success).toBe(true);
|
|
107
|
+
expect(result.value).toBe('success');
|
|
108
|
+
expect(result.attempts).toBe(1);
|
|
109
|
+
expect(callCount).toBe(1);
|
|
110
|
+
});
|
|
111
|
+
it('retries on retriable error and eventually succeeds', async () => {
|
|
112
|
+
let callCount = 0;
|
|
113
|
+
const result = await withRetry(async () => {
|
|
114
|
+
callCount++;
|
|
115
|
+
if (callCount < 3)
|
|
116
|
+
throw new Error('ECONNREFUSED');
|
|
117
|
+
return 'recovered';
|
|
118
|
+
}, { baseDelayMs: 1, maxDelayMs: 5, jitter: false });
|
|
119
|
+
expect(result.success).toBe(true);
|
|
120
|
+
expect(result.value).toBe('recovered');
|
|
121
|
+
expect(result.attempts).toBe(3);
|
|
122
|
+
expect(callCount).toBe(3);
|
|
123
|
+
});
|
|
124
|
+
it('fails immediately on permanent error', async () => {
|
|
125
|
+
let callCount = 0;
|
|
126
|
+
const result = await withRetry(async () => {
|
|
127
|
+
callCount++;
|
|
128
|
+
throw new Error('Permission denied');
|
|
129
|
+
}, { baseDelayMs: 1, jitter: false });
|
|
130
|
+
expect(result.success).toBe(false);
|
|
131
|
+
expect(result.error?.message).toBe('Permission denied');
|
|
132
|
+
expect(result.attempts).toBe(1);
|
|
133
|
+
expect(callCount).toBe(1);
|
|
134
|
+
});
|
|
135
|
+
it('exhausts retries and fails', async () => {
|
|
136
|
+
let callCount = 0;
|
|
137
|
+
const result = await withRetry(async () => {
|
|
138
|
+
callCount++;
|
|
139
|
+
throw new Error('ECONNREFUSED');
|
|
140
|
+
}, { maxRetries: 2, baseDelayMs: 1, maxDelayMs: 5, jitter: false });
|
|
141
|
+
expect(result.success).toBe(false);
|
|
142
|
+
expect(result.attempts).toBe(3); // 1 initial + 2 retries
|
|
143
|
+
expect(callCount).toBe(3);
|
|
144
|
+
});
|
|
145
|
+
it('tracks total delay time', async () => {
|
|
146
|
+
let callCount = 0;
|
|
147
|
+
const result = await withRetry(async () => {
|
|
148
|
+
callCount++;
|
|
149
|
+
if (callCount <= 2)
|
|
150
|
+
throw new Error('timeout');
|
|
151
|
+
return 'ok';
|
|
152
|
+
}, { baseDelayMs: 10, backoffMultiplier: 1, jitter: false });
|
|
153
|
+
expect(result.success).toBe(true);
|
|
154
|
+
expect(result.totalDelayMs).toBeGreaterThanOrEqual(20); // 10 + 10
|
|
155
|
+
});
|
|
156
|
+
it('uses custom retry policy', async () => {
|
|
157
|
+
let callCount = 0;
|
|
158
|
+
const result = await withRetry(async () => {
|
|
159
|
+
callCount++;
|
|
160
|
+
throw new Error('rate limit');
|
|
161
|
+
}, { maxRetries: 1, baseDelayMs: 1, jitter: false });
|
|
162
|
+
expect(result.success).toBe(false);
|
|
163
|
+
expect(result.attempts).toBe(2); // 1 initial + 1 retry
|
|
164
|
+
expect(callCount).toBe(2);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
// ==========================================================================
|
|
168
|
+
// Self-Healing Recovery
|
|
169
|
+
// ==========================================================================
|
|
170
|
+
describe('recoverCrashedAgents', () => {
|
|
171
|
+
let tempDir;
|
|
172
|
+
beforeEach(async () => {
|
|
173
|
+
tempDir = await mkdtemp(join(tmpdir(), 'cleo-recover-test-'));
|
|
174
|
+
await mkdir(join(tempDir, '.cleo'), { recursive: true });
|
|
175
|
+
await mkdir(join(tempDir, '.cleo', 'backups', 'operational'), { recursive: true });
|
|
176
|
+
});
|
|
177
|
+
afterEach(async () => {
|
|
178
|
+
try {
|
|
179
|
+
const { closeAllDatabases } = await import('../../store/sqlite.js');
|
|
180
|
+
await closeAllDatabases();
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
/* module may not be loaded */
|
|
184
|
+
}
|
|
185
|
+
await Promise.race([
|
|
186
|
+
rm(tempDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 300 }).catch(() => { }),
|
|
187
|
+
new Promise((resolve) => setTimeout(resolve, 8_000)),
|
|
188
|
+
]);
|
|
189
|
+
});
|
|
190
|
+
it('recovers crashed agents with retriable errors', async () => {
|
|
191
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
192
|
+
await updateAgentStatus(agent.id, { status: 'crashed', error: 'ECONNREFUSED' }, tempDir);
|
|
193
|
+
const results = await recoverCrashedAgents(30_000, tempDir);
|
|
194
|
+
expect(results.length).toBe(1);
|
|
195
|
+
expect(results[0].recovered).toBe(true);
|
|
196
|
+
expect(results[0].action).toBe('restarted');
|
|
197
|
+
});
|
|
198
|
+
it('abandons agents with permanent errors', async () => {
|
|
199
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
200
|
+
await updateAgentStatus(agent.id, { status: 'crashed', error: 'Permission denied' }, tempDir);
|
|
201
|
+
const results = await recoverCrashedAgents(30_000, tempDir);
|
|
202
|
+
expect(results.length).toBe(1);
|
|
203
|
+
expect(results[0].recovered).toBe(false);
|
|
204
|
+
expect(results[0].action).toBe('abandoned');
|
|
205
|
+
});
|
|
206
|
+
it('abandons agents exceeding error threshold', async () => {
|
|
207
|
+
const agent = await registerAgent({ agentType: 'executor' }, tempDir);
|
|
208
|
+
// Simulate 5+ errors
|
|
209
|
+
for (let i = 0; i < 5; i++) {
|
|
210
|
+
await updateAgentStatus(agent.id, { status: 'error', error: `Error ${i}` }, tempDir);
|
|
211
|
+
}
|
|
212
|
+
await updateAgentStatus(agent.id, { status: 'crashed' }, tempDir);
|
|
213
|
+
const results = await recoverCrashedAgents(30_000, tempDir);
|
|
214
|
+
expect(results.length).toBe(1);
|
|
215
|
+
expect(results[0].recovered).toBe(false);
|
|
216
|
+
expect(results[0].action).toBe('abandoned');
|
|
217
|
+
expect(results[0].reason).toContain('exceeds threshold');
|
|
218
|
+
});
|
|
219
|
+
it('returns empty results when no crashed agents', async () => {
|
|
220
|
+
await registerAgent({ agentType: 'executor' }, tempDir);
|
|
221
|
+
const results = await recoverCrashedAgents(60_000, tempDir);
|
|
222
|
+
expect(results.length).toBe(0);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
//# sourceMappingURL=retry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.test.js","sourceRoot":"","sources":["retry.test.ts"],"names":[],"mappings":"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"}
|