@sparkleideas/shared 3.0.0-alpha.7
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/README.md +323 -0
- package/__tests__/hooks/bash-safety.test.ts +289 -0
- package/__tests__/hooks/file-organization.test.ts +335 -0
- package/__tests__/hooks/git-commit.test.ts +336 -0
- package/__tests__/hooks/index.ts +23 -0
- package/__tests__/hooks/session-hooks.test.ts +357 -0
- package/__tests__/hooks/task-hooks.test.ts +193 -0
- package/docs/EVENTS_IMPLEMENTATION_SUMMARY.md +388 -0
- package/docs/EVENTS_QUICK_REFERENCE.md +470 -0
- package/docs/EVENTS_README.md +352 -0
- package/package.json +39 -0
- package/src/core/config/defaults.ts +207 -0
- package/src/core/config/index.ts +15 -0
- package/src/core/config/loader.ts +271 -0
- package/src/core/config/schema.ts +188 -0
- package/src/core/config/validator.ts +209 -0
- package/src/core/event-bus.ts +236 -0
- package/src/core/index.ts +22 -0
- package/src/core/interfaces/agent.interface.ts +251 -0
- package/src/core/interfaces/coordinator.interface.ts +363 -0
- package/src/core/interfaces/event.interface.ts +267 -0
- package/src/core/interfaces/index.ts +19 -0
- package/src/core/interfaces/memory.interface.ts +332 -0
- package/src/core/interfaces/task.interface.ts +223 -0
- package/src/core/orchestrator/event-coordinator.ts +122 -0
- package/src/core/orchestrator/health-monitor.ts +214 -0
- package/src/core/orchestrator/index.ts +89 -0
- package/src/core/orchestrator/lifecycle-manager.ts +263 -0
- package/src/core/orchestrator/session-manager.ts +279 -0
- package/src/core/orchestrator/task-manager.ts +317 -0
- package/src/events/domain-events.ts +584 -0
- package/src/events/event-store.test.ts +387 -0
- package/src/events/event-store.ts +588 -0
- package/src/events/example-usage.ts +293 -0
- package/src/events/index.ts +90 -0
- package/src/events/projections.ts +561 -0
- package/src/events/state-reconstructor.ts +349 -0
- package/src/events.ts +367 -0
- package/src/hooks/INTEGRATION.md +658 -0
- package/src/hooks/README.md +532 -0
- package/src/hooks/example-usage.ts +499 -0
- package/src/hooks/executor.ts +379 -0
- package/src/hooks/hooks.test.ts +421 -0
- package/src/hooks/index.ts +131 -0
- package/src/hooks/registry.ts +333 -0
- package/src/hooks/safety/bash-safety.ts +604 -0
- package/src/hooks/safety/file-organization.ts +473 -0
- package/src/hooks/safety/git-commit.ts +623 -0
- package/src/hooks/safety/index.ts +46 -0
- package/src/hooks/session-hooks.ts +559 -0
- package/src/hooks/task-hooks.ts +513 -0
- package/src/hooks/types.ts +357 -0
- package/src/hooks/verify-exports.test.ts +125 -0
- package/src/index.ts +195 -0
- package/src/mcp/connection-pool.ts +438 -0
- package/src/mcp/index.ts +183 -0
- package/src/mcp/server.ts +774 -0
- package/src/mcp/session-manager.ts +428 -0
- package/src/mcp/tool-registry.ts +566 -0
- package/src/mcp/transport/http.ts +557 -0
- package/src/mcp/transport/index.ts +294 -0
- package/src/mcp/transport/stdio.ts +324 -0
- package/src/mcp/transport/websocket.ts +484 -0
- package/src/mcp/types.ts +565 -0
- package/src/plugin-interface.ts +663 -0
- package/src/plugin-loader.ts +638 -0
- package/src/plugin-registry.ts +604 -0
- package/src/plugins/index.ts +34 -0
- package/src/plugins/official/hive-mind-plugin.ts +330 -0
- package/src/plugins/official/index.ts +24 -0
- package/src/plugins/official/maestro-plugin.ts +508 -0
- package/src/plugins/types.ts +108 -0
- package/src/resilience/bulkhead.ts +277 -0
- package/src/resilience/circuit-breaker.ts +326 -0
- package/src/resilience/index.ts +26 -0
- package/src/resilience/rate-limiter.ts +420 -0
- package/src/resilience/retry.ts +224 -0
- package/src/security/index.ts +39 -0
- package/src/security/input-validation.ts +265 -0
- package/src/security/secure-random.ts +159 -0
- package/src/services/index.ts +16 -0
- package/src/services/v3-progress.service.ts +505 -0
- package/src/types/agent.types.ts +144 -0
- package/src/types/index.ts +22 -0
- package/src/types/mcp.types.ts +300 -0
- package/src/types/memory.types.ts +263 -0
- package/src/types/swarm.types.ts +255 -0
- package/src/types/task.types.ts +205 -0
- package/src/types.ts +367 -0
- package/src/utils/secure-logger.d.ts +69 -0
- package/src/utils/secure-logger.d.ts.map +1 -0
- package/src/utils/secure-logger.js +208 -0
- package/src/utils/secure-logger.js.map +1 -0
- package/src/utils/secure-logger.ts +257 -0
- package/tmp.json +0 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 Configuration Loader
|
|
3
|
+
* Load configuration from various sources
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile } from 'fs/promises';
|
|
7
|
+
import { join, resolve } from 'path';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
import type { SystemConfig } from './schema.js';
|
|
10
|
+
import { validateSystemConfig, type ValidationResult } from './validator.js';
|
|
11
|
+
import { defaultSystemConfig, mergeWithDefaults } from './defaults.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration source type
|
|
15
|
+
*/
|
|
16
|
+
export type ConfigSource = 'file' | 'env' | 'default' | 'merged';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Loaded configuration with metadata
|
|
20
|
+
*/
|
|
21
|
+
export interface LoadedConfig {
|
|
22
|
+
config: SystemConfig;
|
|
23
|
+
source: ConfigSource;
|
|
24
|
+
path?: string;
|
|
25
|
+
warnings?: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Configuration file names to search for
|
|
30
|
+
*/
|
|
31
|
+
const CONFIG_FILE_NAMES = [
|
|
32
|
+
'@sparkleideas/claude-flow.config.json',
|
|
33
|
+
'@sparkleideas/claude-flow.config.js',
|
|
34
|
+
'@sparkleideas/claude-flow.json',
|
|
35
|
+
'.@sparkleideas/claude-flow.json',
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Find configuration file in directory
|
|
40
|
+
*/
|
|
41
|
+
async function findConfigFile(directory: string): Promise<string | null> {
|
|
42
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
43
|
+
const path = join(directory, name);
|
|
44
|
+
if (existsSync(path)) {
|
|
45
|
+
return path;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Load configuration from JSON file
|
|
53
|
+
*/
|
|
54
|
+
async function loadJsonConfig(path: string): Promise<unknown> {
|
|
55
|
+
const content = await readFile(path, 'utf8');
|
|
56
|
+
return JSON.parse(content);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Load configuration from environment variables
|
|
61
|
+
*/
|
|
62
|
+
function loadEnvConfig(): Partial<SystemConfig> {
|
|
63
|
+
const config: Partial<SystemConfig> = {};
|
|
64
|
+
|
|
65
|
+
// Orchestrator settings
|
|
66
|
+
if (process.env.CLAUDE_FLOW_MAX_AGENTS) {
|
|
67
|
+
config.orchestrator = {
|
|
68
|
+
...defaultSystemConfig.orchestrator,
|
|
69
|
+
lifecycle: {
|
|
70
|
+
...defaultSystemConfig.orchestrator.lifecycle,
|
|
71
|
+
maxConcurrentAgents: parseInt(process.env.CLAUDE_FLOW_MAX_AGENTS, 10),
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Data directory
|
|
77
|
+
if (process.env.CLAUDE_FLOW_DATA_DIR) {
|
|
78
|
+
config.orchestrator = {
|
|
79
|
+
...config.orchestrator,
|
|
80
|
+
...defaultSystemConfig.orchestrator,
|
|
81
|
+
session: {
|
|
82
|
+
...defaultSystemConfig.orchestrator.session,
|
|
83
|
+
dataDir: process.env.CLAUDE_FLOW_DATA_DIR,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Memory type
|
|
89
|
+
if (process.env.CLAUDE_FLOW_MEMORY_TYPE) {
|
|
90
|
+
const memoryType = process.env.CLAUDE_FLOW_MEMORY_TYPE as NonNullable<SystemConfig['memory']>['type'];
|
|
91
|
+
if (['sqlite', '@sparkleideas/agentdb', 'hybrid', 'redis', 'memory'].includes(memoryType)) {
|
|
92
|
+
config.memory = {
|
|
93
|
+
...(defaultSystemConfig.memory ?? { type: 'hybrid' }),
|
|
94
|
+
type: memoryType,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// MCP transport
|
|
100
|
+
const defaultMcp = defaultSystemConfig.mcp ?? { name: '@sparkleideas/claude-flow', version: '3.0.0', transport: { type: 'stdio' as const } };
|
|
101
|
+
if (process.env.CLAUDE_FLOW_MCP_TRANSPORT) {
|
|
102
|
+
const transport = process.env.CLAUDE_FLOW_MCP_TRANSPORT as 'stdio' | 'http' | 'websocket';
|
|
103
|
+
if (['stdio', 'http', 'websocket'].includes(transport)) {
|
|
104
|
+
config.mcp = {
|
|
105
|
+
...defaultMcp,
|
|
106
|
+
transport: {
|
|
107
|
+
...defaultMcp.transport,
|
|
108
|
+
type: transport,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (process.env.CLAUDE_FLOW_MCP_PORT) {
|
|
115
|
+
config.mcp = {
|
|
116
|
+
...config.mcp,
|
|
117
|
+
...defaultMcp,
|
|
118
|
+
transport: {
|
|
119
|
+
...config.mcp?.transport,
|
|
120
|
+
...defaultMcp.transport,
|
|
121
|
+
port: parseInt(process.env.CLAUDE_FLOW_MCP_PORT, 10),
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Swarm topology
|
|
127
|
+
const defaultSwarm = defaultSystemConfig.swarm ?? { topology: 'hierarchical-mesh' as const, maxAgents: 20 };
|
|
128
|
+
if (process.env.CLAUDE_FLOW_SWARM_TOPOLOGY) {
|
|
129
|
+
const topology = process.env.CLAUDE_FLOW_SWARM_TOPOLOGY as NonNullable<SystemConfig['swarm']>['topology'];
|
|
130
|
+
if (['hierarchical', 'mesh', 'ring', 'star', 'adaptive', 'hierarchical-mesh'].includes(topology)) {
|
|
131
|
+
config.swarm = {
|
|
132
|
+
...defaultSwarm,
|
|
133
|
+
topology,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return config;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Configuration loader class
|
|
143
|
+
*/
|
|
144
|
+
export class ConfigLoader {
|
|
145
|
+
private searchPaths: string[] = [];
|
|
146
|
+
|
|
147
|
+
constructor(additionalPaths?: string[]) {
|
|
148
|
+
// Default search paths
|
|
149
|
+
this.searchPaths = [
|
|
150
|
+
process.cwd(),
|
|
151
|
+
resolve(process.cwd(), '..'),
|
|
152
|
+
resolve(process.env.HOME ?? '', '.@sparkleideas/claude-flow'),
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
if (additionalPaths) {
|
|
156
|
+
this.searchPaths.push(...additionalPaths);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Load configuration from all sources
|
|
162
|
+
*/
|
|
163
|
+
async load(): Promise<LoadedConfig> {
|
|
164
|
+
const warnings: string[] = [];
|
|
165
|
+
|
|
166
|
+
// Start with defaults
|
|
167
|
+
let config: SystemConfig = { ...defaultSystemConfig };
|
|
168
|
+
let source: ConfigSource = 'default';
|
|
169
|
+
let path: string | undefined;
|
|
170
|
+
|
|
171
|
+
// Try to load from file
|
|
172
|
+
for (const searchPath of this.searchPaths) {
|
|
173
|
+
const configPath = await findConfigFile(searchPath);
|
|
174
|
+
if (configPath) {
|
|
175
|
+
try {
|
|
176
|
+
const fileConfig = await loadJsonConfig(configPath);
|
|
177
|
+
const validation = validateSystemConfig(fileConfig);
|
|
178
|
+
|
|
179
|
+
if (validation.success) {
|
|
180
|
+
config = mergeWithDefaults(validation.data!, defaultSystemConfig) as SystemConfig;
|
|
181
|
+
source = 'file';
|
|
182
|
+
path = configPath;
|
|
183
|
+
break;
|
|
184
|
+
} else {
|
|
185
|
+
warnings.push(`Invalid config at ${configPath}: ${validation.errors?.map(e => e.message).join(', ')}`);
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
warnings.push(`Failed to load config from ${configPath}: ${(error as Error).message}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Merge with environment variables
|
|
194
|
+
const envConfig = loadEnvConfig();
|
|
195
|
+
if (Object.keys(envConfig).length > 0) {
|
|
196
|
+
config = this.deepMerge(config, envConfig) as SystemConfig;
|
|
197
|
+
source = source === 'default' ? 'env' : 'merged';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
config,
|
|
202
|
+
source,
|
|
203
|
+
path,
|
|
204
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Load configuration from specific file
|
|
210
|
+
*/
|
|
211
|
+
async loadFromFile(filePath: string): Promise<LoadedConfig> {
|
|
212
|
+
const absolutePath = resolve(filePath);
|
|
213
|
+
const fileConfig = await loadJsonConfig(absolutePath);
|
|
214
|
+
const validation = validateSystemConfig(fileConfig);
|
|
215
|
+
|
|
216
|
+
if (!validation.success) {
|
|
217
|
+
throw new Error(`Invalid configuration: ${validation.errors?.map(e => e.message).join(', ')}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const config = mergeWithDefaults(validation.data!, defaultSystemConfig) as SystemConfig;
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
config,
|
|
224
|
+
source: 'file',
|
|
225
|
+
path: absolutePath,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Deep merge objects
|
|
231
|
+
*/
|
|
232
|
+
private deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {
|
|
233
|
+
const result = { ...target };
|
|
234
|
+
|
|
235
|
+
for (const key of Object.keys(source)) {
|
|
236
|
+
const sourceValue = source[key];
|
|
237
|
+
const targetValue = target[key];
|
|
238
|
+
|
|
239
|
+
if (
|
|
240
|
+
sourceValue &&
|
|
241
|
+
typeof sourceValue === 'object' &&
|
|
242
|
+
!Array.isArray(sourceValue) &&
|
|
243
|
+
targetValue &&
|
|
244
|
+
typeof targetValue === 'object' &&
|
|
245
|
+
!Array.isArray(targetValue)
|
|
246
|
+
) {
|
|
247
|
+
result[key] = this.deepMerge(
|
|
248
|
+
targetValue as Record<string, unknown>,
|
|
249
|
+
sourceValue as Record<string, unknown>,
|
|
250
|
+
);
|
|
251
|
+
} else if (sourceValue !== undefined) {
|
|
252
|
+
result[key] = sourceValue;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Load configuration (convenience function)
|
|
262
|
+
*/
|
|
263
|
+
export async function loadConfig(options?: { paths?: string[]; file?: string }): Promise<LoadedConfig> {
|
|
264
|
+
const loader = new ConfigLoader(options?.paths);
|
|
265
|
+
|
|
266
|
+
if (options?.file) {
|
|
267
|
+
return loader.loadFromFile(options.file);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return loader.load();
|
|
271
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 Configuration Schemas
|
|
3
|
+
* Zod schemas for all configuration types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Agent configuration schema
|
|
10
|
+
*/
|
|
11
|
+
export const AgentConfigSchema = z.object({
|
|
12
|
+
id: z.string().min(1),
|
|
13
|
+
name: z.string().min(1),
|
|
14
|
+
type: z.string().min(1),
|
|
15
|
+
capabilities: z.array(z.string()).default([]),
|
|
16
|
+
maxConcurrentTasks: z.number().int().min(1).default(5),
|
|
17
|
+
priority: z.number().int().min(0).max(100).default(50),
|
|
18
|
+
timeout: z.number().int().positive().optional(),
|
|
19
|
+
retryPolicy: z.object({
|
|
20
|
+
maxRetries: z.number().int().min(0).default(3),
|
|
21
|
+
backoffMs: z.number().int().positive().default(1000),
|
|
22
|
+
backoffMultiplier: z.number().positive().default(2),
|
|
23
|
+
}).optional(),
|
|
24
|
+
resources: z.object({
|
|
25
|
+
maxMemoryMb: z.number().int().positive().optional(),
|
|
26
|
+
maxCpuPercent: z.number().min(0).max(100).optional(),
|
|
27
|
+
}).optional(),
|
|
28
|
+
metadata: z.record(z.unknown()).optional(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Task configuration schema
|
|
33
|
+
*/
|
|
34
|
+
export const TaskConfigSchema = z.object({
|
|
35
|
+
type: z.string().min(1),
|
|
36
|
+
description: z.string().min(1),
|
|
37
|
+
priority: z.number().int().min(0).max(100).default(50),
|
|
38
|
+
timeout: z.number().int().positive().optional(),
|
|
39
|
+
assignedAgent: z.string().optional(),
|
|
40
|
+
input: z.record(z.unknown()).optional(),
|
|
41
|
+
metadata: z.object({
|
|
42
|
+
requiredCapabilities: z.array(z.string()).optional(),
|
|
43
|
+
retryCount: z.number().int().min(0).optional(),
|
|
44
|
+
maxRetries: z.number().int().min(0).optional(),
|
|
45
|
+
critical: z.boolean().optional(),
|
|
46
|
+
parentTaskId: z.string().optional(),
|
|
47
|
+
childTaskIds: z.array(z.string()).optional(),
|
|
48
|
+
tags: z.array(z.string()).optional(),
|
|
49
|
+
}).optional(),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Swarm configuration schema
|
|
54
|
+
*/
|
|
55
|
+
export const SwarmConfigSchema = z.object({
|
|
56
|
+
topology: z.enum(['hierarchical', 'mesh', 'ring', 'star', 'adaptive', 'hierarchical-mesh']),
|
|
57
|
+
maxAgents: z.number().int().positive().default(20),
|
|
58
|
+
autoScale: z.object({
|
|
59
|
+
enabled: z.boolean().default(false),
|
|
60
|
+
minAgents: z.number().int().min(0).default(1),
|
|
61
|
+
maxAgents: z.number().int().positive().default(20),
|
|
62
|
+
scaleUpThreshold: z.number().min(0).max(1).default(0.8),
|
|
63
|
+
scaleDownThreshold: z.number().min(0).max(1).default(0.3),
|
|
64
|
+
}).optional(),
|
|
65
|
+
coordination: z.object({
|
|
66
|
+
consensusRequired: z.boolean().default(false),
|
|
67
|
+
timeoutMs: z.number().int().positive().default(10000),
|
|
68
|
+
retryPolicy: z.object({
|
|
69
|
+
maxRetries: z.number().int().min(0).default(3),
|
|
70
|
+
backoffMs: z.number().int().positive().default(500),
|
|
71
|
+
}),
|
|
72
|
+
}).optional(),
|
|
73
|
+
communication: z.object({
|
|
74
|
+
protocol: z.enum(['events', 'messages', 'shared-memory']).default('events'),
|
|
75
|
+
batchSize: z.number().int().positive().default(10),
|
|
76
|
+
flushIntervalMs: z.number().int().positive().default(100),
|
|
77
|
+
}).optional(),
|
|
78
|
+
metadata: z.record(z.unknown()).optional(),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Memory configuration schema
|
|
83
|
+
*/
|
|
84
|
+
export const MemoryConfigSchema = z.object({
|
|
85
|
+
type: z.enum(['sqlite', '@sparkleideas/agentdb', 'hybrid', 'redis', 'memory']).default('hybrid'),
|
|
86
|
+
path: z.string().optional(),
|
|
87
|
+
maxSize: z.number().int().positive().optional(),
|
|
88
|
+
ttlMs: z.number().int().positive().optional(),
|
|
89
|
+
sqlite: z.object({
|
|
90
|
+
filename: z.string().optional(),
|
|
91
|
+
inMemory: z.boolean().default(false),
|
|
92
|
+
wal: z.boolean().default(true),
|
|
93
|
+
}).optional(),
|
|
94
|
+
@sparkleideas/agentdb: z.object({
|
|
95
|
+
dimensions: z.number().int().positive().default(1536),
|
|
96
|
+
indexType: z.enum(['hnsw', 'flat', 'ivf']).default('hnsw'),
|
|
97
|
+
efConstruction: z.number().int().positive().default(200),
|
|
98
|
+
m: z.number().int().positive().default(16),
|
|
99
|
+
quantization: z.enum(['none', 'scalar', 'product']).default('none'),
|
|
100
|
+
}).optional(),
|
|
101
|
+
redis: z.object({
|
|
102
|
+
host: z.string().default('localhost'),
|
|
103
|
+
port: z.number().int().positive().default(6379),
|
|
104
|
+
password: z.string().optional(),
|
|
105
|
+
db: z.number().int().min(0).default(0),
|
|
106
|
+
keyPrefix: z.string().default('@sparkleideas/claude-flow:'),
|
|
107
|
+
}).optional(),
|
|
108
|
+
hybrid: z.object({
|
|
109
|
+
vectorThreshold: z.number().int().positive().default(100),
|
|
110
|
+
}).optional(),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* MCP server configuration schema
|
|
115
|
+
*/
|
|
116
|
+
export const MCPServerConfigSchema = z.object({
|
|
117
|
+
name: z.string().min(1).default('@sparkleideas/claude-flow'),
|
|
118
|
+
version: z.string().min(1).default('3.0.0'),
|
|
119
|
+
transport: z.object({
|
|
120
|
+
type: z.enum(['stdio', 'http', 'websocket']).default('stdio'),
|
|
121
|
+
port: z.number().int().positive().optional(),
|
|
122
|
+
host: z.string().optional(),
|
|
123
|
+
path: z.string().optional(),
|
|
124
|
+
}),
|
|
125
|
+
capabilities: z.object({
|
|
126
|
+
tools: z.boolean().default(true),
|
|
127
|
+
resources: z.boolean().default(true),
|
|
128
|
+
prompts: z.boolean().default(true),
|
|
129
|
+
logging: z.boolean().default(true),
|
|
130
|
+
experimental: z.record(z.boolean()).optional(),
|
|
131
|
+
}).optional(),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Orchestrator configuration schema
|
|
136
|
+
*/
|
|
137
|
+
export const OrchestratorConfigSchema = z.object({
|
|
138
|
+
session: z.object({
|
|
139
|
+
persistSessions: z.boolean().default(true),
|
|
140
|
+
dataDir: z.string().default('./data'),
|
|
141
|
+
sessionRetentionMs: z.number().int().positive().default(3600000),
|
|
142
|
+
}),
|
|
143
|
+
health: z.object({
|
|
144
|
+
checkInterval: z.number().int().positive().default(30000),
|
|
145
|
+
historyLimit: z.number().int().positive().default(100),
|
|
146
|
+
degradedThreshold: z.number().int().min(0).default(1),
|
|
147
|
+
unhealthyThreshold: z.number().int().min(0).default(2),
|
|
148
|
+
}),
|
|
149
|
+
lifecycle: z.object({
|
|
150
|
+
maxConcurrentAgents: z.number().int().positive().default(20),
|
|
151
|
+
spawnTimeout: z.number().int().positive().default(30000),
|
|
152
|
+
terminateTimeout: z.number().int().positive().default(10000),
|
|
153
|
+
maxSpawnRetries: z.number().int().min(0).default(3),
|
|
154
|
+
}),
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Full system configuration schema
|
|
159
|
+
*/
|
|
160
|
+
export const SystemConfigSchema = z.object({
|
|
161
|
+
orchestrator: OrchestratorConfigSchema,
|
|
162
|
+
memory: MemoryConfigSchema.optional(),
|
|
163
|
+
mcp: MCPServerConfigSchema.optional(),
|
|
164
|
+
swarm: SwarmConfigSchema.optional(),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Export schema types
|
|
169
|
+
* Using z.output to get post-default types (fields with defaults are required in output)
|
|
170
|
+
*/
|
|
171
|
+
export type AgentConfig = z.output<typeof AgentConfigSchema>;
|
|
172
|
+
export type TaskConfig = z.output<typeof TaskConfigSchema>;
|
|
173
|
+
export type SwarmConfig = z.output<typeof SwarmConfigSchema>;
|
|
174
|
+
export type MemoryConfig = z.output<typeof MemoryConfigSchema>;
|
|
175
|
+
export type MCPServerConfig = z.output<typeof MCPServerConfigSchema>;
|
|
176
|
+
export type OrchestratorConfig = z.output<typeof OrchestratorConfigSchema>;
|
|
177
|
+
export type SystemConfig = z.output<typeof SystemConfigSchema>;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Input types (for validation before defaults are applied)
|
|
181
|
+
*/
|
|
182
|
+
export type AgentConfigInput = z.input<typeof AgentConfigSchema>;
|
|
183
|
+
export type TaskConfigInput = z.input<typeof TaskConfigSchema>;
|
|
184
|
+
export type SwarmConfigInput = z.input<typeof SwarmConfigSchema>;
|
|
185
|
+
export type MemoryConfigInput = z.input<typeof MemoryConfigSchema>;
|
|
186
|
+
export type MCPServerConfigInput = z.input<typeof MCPServerConfigSchema>;
|
|
187
|
+
export type OrchestratorConfigInput = z.input<typeof OrchestratorConfigSchema>;
|
|
188
|
+
export type SystemConfigInput = z.input<typeof SystemConfigSchema>;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 Configuration Validator
|
|
3
|
+
* Validation logic using Zod schemas
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z, type ZodError } from 'zod';
|
|
7
|
+
import {
|
|
8
|
+
AgentConfigSchema,
|
|
9
|
+
TaskConfigSchema,
|
|
10
|
+
SwarmConfigSchema,
|
|
11
|
+
MemoryConfigSchema,
|
|
12
|
+
MCPServerConfigSchema,
|
|
13
|
+
OrchestratorConfigSchema,
|
|
14
|
+
SystemConfigSchema,
|
|
15
|
+
type AgentConfig,
|
|
16
|
+
type TaskConfig,
|
|
17
|
+
type SwarmConfig,
|
|
18
|
+
type MemoryConfig,
|
|
19
|
+
type MCPServerConfig,
|
|
20
|
+
type OrchestratorConfig,
|
|
21
|
+
type SystemConfig,
|
|
22
|
+
} from './schema.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validation result
|
|
26
|
+
*/
|
|
27
|
+
export interface ValidationResult<T> {
|
|
28
|
+
success: boolean;
|
|
29
|
+
data?: T;
|
|
30
|
+
errors?: ValidationError[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validation error
|
|
35
|
+
*/
|
|
36
|
+
export interface ValidationError {
|
|
37
|
+
path: string;
|
|
38
|
+
message: string;
|
|
39
|
+
code: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Convert Zod error to validation errors
|
|
44
|
+
*/
|
|
45
|
+
function zodErrorToValidationErrors(error: ZodError): ValidationError[] {
|
|
46
|
+
return error.errors.map((e) => ({
|
|
47
|
+
path: e.path.join('.'),
|
|
48
|
+
message: e.message,
|
|
49
|
+
code: e.code,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Generic validation function
|
|
55
|
+
* Uses parse + try/catch to get output types with defaults applied
|
|
56
|
+
*/
|
|
57
|
+
function validate<TInput, TOutput>(
|
|
58
|
+
schema: z.ZodType<TOutput, z.ZodTypeDef, TInput>,
|
|
59
|
+
data: unknown
|
|
60
|
+
): ValidationResult<TOutput> {
|
|
61
|
+
try {
|
|
62
|
+
const parsed = schema.parse(data);
|
|
63
|
+
return {
|
|
64
|
+
success: true,
|
|
65
|
+
data: parsed,
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof z.ZodError) {
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
errors: zodErrorToValidationErrors(error),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Validate agent configuration
|
|
80
|
+
*/
|
|
81
|
+
export function validateAgentConfig(data: unknown): ValidationResult<AgentConfig> {
|
|
82
|
+
return validate(AgentConfigSchema, data);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Validate task configuration
|
|
87
|
+
*/
|
|
88
|
+
export function validateTaskConfig(data: unknown): ValidationResult<TaskConfig> {
|
|
89
|
+
return validate(TaskConfigSchema, data);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Validate swarm configuration
|
|
94
|
+
*/
|
|
95
|
+
export function validateSwarmConfig(data: unknown): ValidationResult<SwarmConfig> {
|
|
96
|
+
return validate(SwarmConfigSchema, data);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Validate memory configuration
|
|
101
|
+
*/
|
|
102
|
+
export function validateMemoryConfig(data: unknown): ValidationResult<MemoryConfig> {
|
|
103
|
+
return validate(MemoryConfigSchema, data);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Validate MCP server configuration
|
|
108
|
+
*/
|
|
109
|
+
export function validateMCPServerConfig(data: unknown): ValidationResult<MCPServerConfig> {
|
|
110
|
+
return validate(MCPServerConfigSchema, data);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Validate orchestrator configuration
|
|
115
|
+
*/
|
|
116
|
+
export function validateOrchestratorConfig(data: unknown): ValidationResult<OrchestratorConfig> {
|
|
117
|
+
return validate(OrchestratorConfigSchema, data);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Validate full system configuration
|
|
122
|
+
*/
|
|
123
|
+
export function validateSystemConfig(data: unknown): ValidationResult<SystemConfig> {
|
|
124
|
+
return validate(SystemConfigSchema, data);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Configuration validator class
|
|
129
|
+
*/
|
|
130
|
+
export class ConfigValidator {
|
|
131
|
+
/**
|
|
132
|
+
* Validate and throw on error
|
|
133
|
+
*/
|
|
134
|
+
static validateOrThrow<TInput, TOutput>(
|
|
135
|
+
schema: z.ZodType<TOutput, z.ZodTypeDef, TInput>,
|
|
136
|
+
data: unknown,
|
|
137
|
+
configName: string
|
|
138
|
+
): TOutput {
|
|
139
|
+
const result = validate(schema, data);
|
|
140
|
+
|
|
141
|
+
if (!result.success) {
|
|
142
|
+
const errorMessages = result.errors
|
|
143
|
+
?.map((e) => ` - ${e.path}: ${e.message}`)
|
|
144
|
+
.join('\n');
|
|
145
|
+
throw new Error(`Invalid ${configName} configuration:\n${errorMessages}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return result.data!;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Validate agent config or throw
|
|
153
|
+
*/
|
|
154
|
+
static validateAgentOrThrow(data: unknown): AgentConfig {
|
|
155
|
+
return this.validateOrThrow(AgentConfigSchema, data, 'agent');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Validate task config or throw
|
|
160
|
+
*/
|
|
161
|
+
static validateTaskOrThrow(data: unknown): TaskConfig {
|
|
162
|
+
return this.validateOrThrow(TaskConfigSchema, data, 'task');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Validate swarm config or throw
|
|
167
|
+
*/
|
|
168
|
+
static validateSwarmOrThrow(data: unknown): SwarmConfig {
|
|
169
|
+
return this.validateOrThrow(SwarmConfigSchema, data, 'swarm');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Validate memory config or throw
|
|
174
|
+
*/
|
|
175
|
+
static validateMemoryOrThrow(data: unknown): MemoryConfig {
|
|
176
|
+
return this.validateOrThrow(MemoryConfigSchema, data, 'memory');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Validate MCP server config or throw
|
|
181
|
+
*/
|
|
182
|
+
static validateMCPServerOrThrow(data: unknown): MCPServerConfig {
|
|
183
|
+
return this.validateOrThrow(MCPServerConfigSchema, data, 'MCP server');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Validate orchestrator config or throw
|
|
188
|
+
*/
|
|
189
|
+
static validateOrchestratorOrThrow(data: unknown): OrchestratorConfig {
|
|
190
|
+
return this.validateOrThrow(OrchestratorConfigSchema, data, 'orchestrator');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Validate system config or throw
|
|
195
|
+
*/
|
|
196
|
+
static validateSystemOrThrow(data: unknown): SystemConfig {
|
|
197
|
+
return this.validateOrThrow(SystemConfigSchema, data, 'system');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check if data matches schema
|
|
202
|
+
*/
|
|
203
|
+
static isValid<TInput, TOutput>(
|
|
204
|
+
schema: z.ZodType<TOutput, z.ZodTypeDef, TInput>,
|
|
205
|
+
data: unknown
|
|
206
|
+
): boolean {
|
|
207
|
+
return validate(schema, data).success;
|
|
208
|
+
}
|
|
209
|
+
}
|