agentic-flow 2.0.1-alpha.4 → 2.0.1-alpha.8
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/CHANGELOG.md +26 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentdb/controllers/EmbeddingService.d.ts +37 -0
- package/dist/agentdb/controllers/EmbeddingService.d.ts.map +1 -0
- package/dist/agentdb/controllers/EmbeddingService.js +1 -0
- package/dist/agentdb/controllers/EmbeddingService.js.map +1 -0
- package/dist/billing/mcp/tools.d.ts.map +1 -1
- package/dist/billing/mcp/tools.js +2 -0
- package/dist/billing/mcp/tools.js.map +1 -1
- package/dist/cli/commands/hooks.d.ts +18 -0
- package/dist/cli/commands/hooks.d.ts.map +1 -0
- package/dist/cli/commands/hooks.js +750 -0
- package/dist/cli/commands/hooks.js.map +1 -0
- package/dist/cli-proxy.js +26 -1
- package/dist/cli-proxy.js.map +1 -1
- package/dist/core/agentdb-fast.js +3 -3
- package/dist/core/agentdb-fast.js.map +1 -1
- package/dist/core/agentdb-wrapper-enhanced.d.ts.map +1 -1
- package/dist/core/agentdb-wrapper-enhanced.js +32 -17
- package/dist/core/agentdb-wrapper-enhanced.js.map +1 -1
- package/dist/core/attention-native.d.ts +1 -0
- package/dist/core/attention-native.d.ts.map +1 -1
- package/dist/core/attention-native.js +6 -1
- package/dist/core/attention-native.js.map +1 -1
- package/dist/federation/integrations/supabase-adapter-debug.js +3 -3
- package/dist/federation/integrations/supabase-adapter-debug.js.map +1 -1
- package/dist/intelligence/RuVectorIntelligence.d.ts +362 -0
- package/dist/intelligence/RuVectorIntelligence.d.ts.map +1 -0
- package/dist/intelligence/RuVectorIntelligence.js +852 -0
- package/dist/intelligence/RuVectorIntelligence.js.map +1 -0
- package/dist/intelligence/index.d.ts +14 -0
- package/dist/intelligence/index.d.ts.map +1 -0
- package/dist/intelligence/index.js +14 -0
- package/dist/intelligence/index.js.map +1 -0
- package/dist/llm/RuvLLMOrchestrator.d.ts +184 -0
- package/dist/llm/RuvLLMOrchestrator.d.ts.map +1 -0
- package/dist/llm/RuvLLMOrchestrator.js +442 -0
- package/dist/llm/RuvLLMOrchestrator.js.map +1 -0
- package/dist/llm/index.d.ts +9 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +8 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/mcp/claudeFlowSdkServer.d.ts.map +1 -1
- package/dist/mcp/claudeFlowSdkServer.js +86 -21
- package/dist/mcp/claudeFlowSdkServer.js.map +1 -1
- package/dist/mcp/fastmcp/servers/hooks-server.d.ts +15 -0
- package/dist/mcp/fastmcp/servers/hooks-server.d.ts.map +1 -0
- package/dist/mcp/fastmcp/servers/hooks-server.js +63 -0
- package/dist/mcp/fastmcp/servers/hooks-server.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.d.ts +20 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.js +110 -0
- package/dist/mcp/fastmcp/tools/hooks/benchmark.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.js +276 -0
- package/dist/mcp/fastmcp/tools/hooks/build-agents.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.d.ts +6 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.js +164 -0
- package/dist/mcp/fastmcp/tools/hooks/explain.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/index.d.ts +28 -0
- package/dist/mcp/fastmcp/tools/hooks/index.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/index.js +59 -0
- package/dist/mcp/fastmcp/tools/hooks/index.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.d.ts +91 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.js +269 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-bridge.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.d.ts +58 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.js +416 -0
- package/dist/mcp/fastmcp/tools/hooks/intelligence-tools.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.d.ts +6 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.js +137 -0
- package/dist/mcp/fastmcp/tools/hooks/metrics.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.js +91 -0
- package/dist/mcp/fastmcp/tools/hooks/post-command.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.d.ts +12 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.js +146 -0
- package/dist/mcp/fastmcp/tools/hooks/post-edit.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.js +70 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-command.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.d.ts +14 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.js +121 -0
- package/dist/mcp/fastmcp/tools/hooks/pre-edit.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.js +171 -0
- package/dist/mcp/fastmcp/tools/hooks/pretrain.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/route.d.ts +12 -0
- package/dist/mcp/fastmcp/tools/hooks/route.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/route.js +267 -0
- package/dist/mcp/fastmcp/tools/hooks/route.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.d.ts +46 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.js +159 -0
- package/dist/mcp/fastmcp/tools/hooks/shared.js.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.d.ts +7 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.d.ts.map +1 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.js +151 -0
- package/dist/mcp/fastmcp/tools/hooks/transfer.js.map +1 -0
- package/dist/mcp/tools/agent-booster-tools.d.ts +10 -1
- package/dist/mcp/tools/agent-booster-tools.d.ts.map +1 -1
- package/dist/mcp/tools/agent-booster-tools.js.map +1 -1
- package/dist/mcp/tools/sona-tools.d.ts.map +1 -1
- package/dist/mcp/tools/sona-tools.js +15 -3
- package/dist/mcp/tools/sona-tools.js.map +1 -1
- package/dist/memory/SharedMemoryPool.d.ts +16 -3
- package/dist/memory/SharedMemoryPool.d.ts.map +1 -1
- package/dist/memory/SharedMemoryPool.js +33 -1
- package/dist/memory/SharedMemoryPool.js.map +1 -1
- package/dist/middleware/auth.middleware.d.ts +114 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +222 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/optimizations/agent-booster-migration.d.ts.map +1 -1
- package/dist/optimizations/agent-booster-migration.js.map +1 -1
- package/dist/proxy/anthropic-to-gemini.d.ts.map +1 -1
- package/dist/proxy/anthropic-to-gemini.js.map +1 -1
- package/dist/proxy/anthropic-to-openrouter.d.ts.map +1 -1
- package/dist/proxy/anthropic-to-openrouter.js.map +1 -1
- package/dist/proxy/anthropic-to-requesty.d.ts.map +1 -1
- package/dist/proxy/anthropic-to-requesty.js.map +1 -1
- package/dist/proxy/quic-proxy.d.ts +0 -1
- package/dist/proxy/quic-proxy.d.ts.map +1 -1
- package/dist/proxy/quic-proxy.js +2 -1
- package/dist/proxy/quic-proxy.js.map +1 -1
- package/dist/reasoningbank/AdvancedMemory.d.ts.map +1 -1
- package/dist/reasoningbank/AdvancedMemory.js +12 -1
- package/dist/reasoningbank/AdvancedMemory.js.map +1 -1
- package/dist/reasoningbank/HybridBackend.d.ts +9 -0
- package/dist/reasoningbank/HybridBackend.d.ts.map +1 -1
- package/dist/reasoningbank/HybridBackend.js +48 -4
- package/dist/reasoningbank/HybridBackend.js.map +1 -1
- package/dist/reasoningbank/backend-selector.d.ts +1 -1
- package/dist/reasoningbank/backend-selector.d.ts.map +1 -1
- package/dist/reasoningbank/backend-selector.js.map +1 -1
- package/dist/reasoningbank/index-new.d.ts +0 -6
- package/dist/reasoningbank/index-new.d.ts.map +1 -1
- package/dist/reasoningbank/index-new.js +9 -7
- package/dist/reasoningbank/index-new.js.map +1 -1
- package/dist/reasoningbank/index.d.ts +1 -6
- package/dist/reasoningbank/index.d.ts.map +1 -1
- package/dist/reasoningbank/index.js +10 -7
- package/dist/reasoningbank/index.js.map +1 -1
- package/dist/router/providers/onnx-local.d.ts.map +1 -1
- package/dist/router/providers/onnx-local.js +3 -1
- package/dist/router/providers/onnx-local.js.map +1 -1
- package/dist/routing/CircuitBreakerRouter.d.ts +187 -0
- package/dist/routing/CircuitBreakerRouter.d.ts.map +1 -0
- package/dist/routing/CircuitBreakerRouter.js +460 -0
- package/dist/routing/CircuitBreakerRouter.js.map +1 -0
- package/dist/routing/SemanticRouter.d.ts +164 -0
- package/dist/routing/SemanticRouter.d.ts.map +1 -0
- package/dist/routing/SemanticRouter.js +291 -0
- package/dist/routing/SemanticRouter.js.map +1 -0
- package/dist/routing/index.d.ts +12 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +10 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/services/embedding-service.d.ts.map +1 -1
- package/dist/services/embedding-service.js +5 -2
- package/dist/services/embedding-service.js.map +1 -1
- package/dist/services/sona-agent-training.js +1 -1
- package/dist/services/sona-agent-training.js.map +1 -1
- package/dist/services/sona-agentdb-integration.d.ts.map +1 -1
- package/dist/services/sona-agentdb-integration.js +10 -5
- package/dist/services/sona-agentdb-integration.js.map +1 -1
- package/dist/services/sona-service.d.ts +6 -6
- package/dist/services/sona-service.d.ts.map +1 -1
- package/dist/services/sona-service.js +3 -1
- package/dist/services/sona-service.js.map +1 -1
- package/dist/utils/audit-logger.d.ts +115 -0
- package/dist/utils/audit-logger.d.ts.map +1 -0
- package/dist/utils/audit-logger.js +228 -0
- package/dist/utils/audit-logger.js.map +1 -0
- package/dist/utils/cli.d.ts +1 -1
- package/dist/utils/cli.d.ts.map +1 -1
- package/dist/utils/cli.js +5 -0
- package/dist/utils/cli.js.map +1 -1
- package/dist/utils/input-validator.d.ts +116 -0
- package/dist/utils/input-validator.d.ts.map +1 -0
- package/dist/utils/input-validator.js +299 -0
- package/dist/utils/input-validator.js.map +1 -0
- package/dist/utils/rate-limiter.js +2 -2
- package/dist/utils/rate-limiter.js.map +1 -1
- package/package.json +5 -2
- package/wasm/reasoningbank/reasoningbank_wasm_bg.js +2 -2
- package/wasm/reasoningbank/reasoningbank_wasm_bg.wasm +0 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides secure input validation for RuVector integration:
|
|
5
|
+
* - Task description validation
|
|
6
|
+
* - Configuration validation
|
|
7
|
+
* - Injection attack prevention
|
|
8
|
+
* - Resource exhaustion prevention
|
|
9
|
+
*/
|
|
10
|
+
export class ValidationError extends Error {
|
|
11
|
+
field;
|
|
12
|
+
constructor(message, field) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.field = field;
|
|
15
|
+
this.name = 'ValidationError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Input Validator
|
|
20
|
+
*
|
|
21
|
+
* Validates all external inputs to prevent:
|
|
22
|
+
* - Injection attacks (XSS, SQL injection, prompt injection)
|
|
23
|
+
* - Resource exhaustion (excessive length, recursion)
|
|
24
|
+
* - Malicious content (scripts, control characters)
|
|
25
|
+
*/
|
|
26
|
+
export class InputValidator {
|
|
27
|
+
// Suspicious patterns that could indicate attacks
|
|
28
|
+
static SUSPICIOUS_PATTERNS = [
|
|
29
|
+
/<script/i, // XSS attempt
|
|
30
|
+
/javascript:/i, // JavaScript protocol
|
|
31
|
+
/data:text\/html/i, // Data URI XSS
|
|
32
|
+
/on\w+\s*=/i, // Event handlers
|
|
33
|
+
/\beval\s*\(/i, // eval() calls
|
|
34
|
+
/\bFunction\s*\(/i, // Function constructor
|
|
35
|
+
/__proto__/, // Prototype pollution
|
|
36
|
+
/\.\.\//, // Path traversal
|
|
37
|
+
/[;\x00]/, // SQL injection chars
|
|
38
|
+
];
|
|
39
|
+
// Control characters that should be removed
|
|
40
|
+
static CONTROL_CHARS_REGEX = /[\x00-\x1F\x7F]/g;
|
|
41
|
+
/**
|
|
42
|
+
* Validate task description
|
|
43
|
+
*
|
|
44
|
+
* @param taskDescription - User-provided task description
|
|
45
|
+
* @param options - Validation options
|
|
46
|
+
* @returns Sanitized task description
|
|
47
|
+
* @throws ValidationError if invalid
|
|
48
|
+
*/
|
|
49
|
+
static validateTaskDescription(taskDescription, options) {
|
|
50
|
+
const opts = {
|
|
51
|
+
maxLength: options?.maxLength ?? 10000,
|
|
52
|
+
minLength: options?.minLength ?? 1,
|
|
53
|
+
allowEmpty: options?.allowEmpty ?? false,
|
|
54
|
+
sanitize: options?.sanitize ?? true,
|
|
55
|
+
};
|
|
56
|
+
// Check for null/undefined
|
|
57
|
+
if (taskDescription === null || taskDescription === undefined) {
|
|
58
|
+
throw new ValidationError('Task description is required', 'taskDescription');
|
|
59
|
+
}
|
|
60
|
+
// Check type
|
|
61
|
+
if (typeof taskDescription !== 'string') {
|
|
62
|
+
throw new ValidationError(`Task description must be a string, got ${typeof taskDescription}`, 'taskDescription');
|
|
63
|
+
}
|
|
64
|
+
// Check empty
|
|
65
|
+
if (!opts.allowEmpty && taskDescription.trim().length === 0) {
|
|
66
|
+
throw new ValidationError('Task description cannot be empty', 'taskDescription');
|
|
67
|
+
}
|
|
68
|
+
// Check length
|
|
69
|
+
if (taskDescription.length < opts.minLength) {
|
|
70
|
+
throw new ValidationError(`Task description too short (min ${opts.minLength} chars)`, 'taskDescription');
|
|
71
|
+
}
|
|
72
|
+
if (taskDescription.length > opts.maxLength) {
|
|
73
|
+
throw new ValidationError(`Task description too long (max ${opts.maxLength} chars)`, 'taskDescription');
|
|
74
|
+
}
|
|
75
|
+
// Sanitize if requested
|
|
76
|
+
let sanitized = taskDescription;
|
|
77
|
+
if (opts.sanitize) {
|
|
78
|
+
// Remove control characters
|
|
79
|
+
sanitized = sanitized.replace(InputValidator.CONTROL_CHARS_REGEX, '');
|
|
80
|
+
// Check for suspicious patterns
|
|
81
|
+
for (const pattern of InputValidator.SUSPICIOUS_PATTERNS) {
|
|
82
|
+
if (pattern.test(sanitized)) {
|
|
83
|
+
throw new ValidationError('Task description contains suspicious content', 'taskDescription');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return sanitized.trim();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Validate agent name
|
|
91
|
+
*
|
|
92
|
+
* @param agentName - Agent identifier
|
|
93
|
+
* @returns Sanitized agent name
|
|
94
|
+
* @throws ValidationError if invalid
|
|
95
|
+
*/
|
|
96
|
+
static validateAgentName(agentName) {
|
|
97
|
+
if (!agentName || typeof agentName !== 'string') {
|
|
98
|
+
throw new ValidationError('Agent name is required', 'agentName');
|
|
99
|
+
}
|
|
100
|
+
if (agentName.length < 1 || agentName.length > 100) {
|
|
101
|
+
throw new ValidationError('Agent name must be between 1-100 characters', 'agentName');
|
|
102
|
+
}
|
|
103
|
+
// Only allow alphanumeric, dash, underscore
|
|
104
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(agentName)) {
|
|
105
|
+
throw new ValidationError('Agent name can only contain letters, numbers, dash, and underscore', 'agentName');
|
|
106
|
+
}
|
|
107
|
+
return agentName.toLowerCase();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Validate confidence score
|
|
111
|
+
*
|
|
112
|
+
* @param confidence - Confidence score (0-1)
|
|
113
|
+
* @returns Validated confidence
|
|
114
|
+
* @throws ValidationError if invalid
|
|
115
|
+
*/
|
|
116
|
+
static validateConfidence(confidence) {
|
|
117
|
+
if (typeof confidence !== 'number') {
|
|
118
|
+
throw new ValidationError(`Confidence must be a number, got ${typeof confidence}`, 'confidence');
|
|
119
|
+
}
|
|
120
|
+
if (Number.isNaN(confidence) || !Number.isFinite(confidence)) {
|
|
121
|
+
throw new ValidationError('Confidence must be a valid number', 'confidence');
|
|
122
|
+
}
|
|
123
|
+
if (confidence < 0 || confidence > 1) {
|
|
124
|
+
throw new ValidationError('Confidence must be between 0 and 1', 'confidence');
|
|
125
|
+
}
|
|
126
|
+
return confidence;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Validate timeout value
|
|
130
|
+
*
|
|
131
|
+
* @param timeout - Timeout in milliseconds
|
|
132
|
+
* @param min - Minimum allowed timeout (default: 100ms)
|
|
133
|
+
* @param max - Maximum allowed timeout (default: 5 minutes)
|
|
134
|
+
* @returns Validated timeout
|
|
135
|
+
* @throws ValidationError if invalid
|
|
136
|
+
*/
|
|
137
|
+
static validateTimeout(timeout, min = 100, max = 300000) {
|
|
138
|
+
if (typeof timeout !== 'number') {
|
|
139
|
+
throw new ValidationError(`Timeout must be a number, got ${typeof timeout}`, 'timeout');
|
|
140
|
+
}
|
|
141
|
+
if (Number.isNaN(timeout) || !Number.isFinite(timeout)) {
|
|
142
|
+
throw new ValidationError('Timeout must be a valid number', 'timeout');
|
|
143
|
+
}
|
|
144
|
+
if (timeout < min) {
|
|
145
|
+
throw new ValidationError(`Timeout too short (min ${min}ms)`, 'timeout');
|
|
146
|
+
}
|
|
147
|
+
if (timeout > max) {
|
|
148
|
+
throw new ValidationError(`Timeout too long (max ${max}ms)`, 'timeout');
|
|
149
|
+
}
|
|
150
|
+
return Math.floor(timeout);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Validate array of strings
|
|
154
|
+
*
|
|
155
|
+
* @param array - Array to validate
|
|
156
|
+
* @param fieldName - Field name for error messages
|
|
157
|
+
* @param maxItems - Maximum number of items
|
|
158
|
+
* @param maxLength - Maximum length per item
|
|
159
|
+
* @returns Validated array
|
|
160
|
+
* @throws ValidationError if invalid
|
|
161
|
+
*/
|
|
162
|
+
static validateStringArray(array, fieldName, maxItems = 100, maxLength = 1000) {
|
|
163
|
+
if (!Array.isArray(array)) {
|
|
164
|
+
throw new ValidationError(`${fieldName} must be an array`, fieldName);
|
|
165
|
+
}
|
|
166
|
+
if (array.length > maxItems) {
|
|
167
|
+
throw new ValidationError(`${fieldName} has too many items (max ${maxItems})`, fieldName);
|
|
168
|
+
}
|
|
169
|
+
const validated = [];
|
|
170
|
+
for (let i = 0; i < array.length; i++) {
|
|
171
|
+
const item = array[i];
|
|
172
|
+
if (typeof item !== 'string') {
|
|
173
|
+
throw new ValidationError(`${fieldName}[${i}] must be a string`, fieldName);
|
|
174
|
+
}
|
|
175
|
+
if (item.length > maxLength) {
|
|
176
|
+
throw new ValidationError(`${fieldName}[${i}] too long (max ${maxLength} chars)`, fieldName);
|
|
177
|
+
}
|
|
178
|
+
validated.push(item);
|
|
179
|
+
}
|
|
180
|
+
return validated;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Validate configuration object
|
|
184
|
+
*
|
|
185
|
+
* @param config - Configuration to validate
|
|
186
|
+
* @param schema - Validation schema
|
|
187
|
+
* @returns Validated configuration
|
|
188
|
+
* @throws ValidationError if invalid
|
|
189
|
+
*/
|
|
190
|
+
static validateConfig(config, schema) {
|
|
191
|
+
if (!config || typeof config !== 'object') {
|
|
192
|
+
throw new ValidationError('Configuration must be an object', 'config');
|
|
193
|
+
}
|
|
194
|
+
const validated = {};
|
|
195
|
+
const configObj = config;
|
|
196
|
+
for (const [key, rules] of Object.entries(schema)) {
|
|
197
|
+
const value = configObj[key];
|
|
198
|
+
// Check required
|
|
199
|
+
if (rules.required && (value === undefined || value === null)) {
|
|
200
|
+
throw new ValidationError(`Configuration field '${key}' is required`, key);
|
|
201
|
+
}
|
|
202
|
+
// Skip if optional and not provided
|
|
203
|
+
if (!rules.required && (value === undefined || value === null)) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
// Check type
|
|
207
|
+
if (typeof value !== rules.type) {
|
|
208
|
+
throw new ValidationError(`Configuration field '${key}' must be ${rules.type}, got ${typeof value}`, key);
|
|
209
|
+
}
|
|
210
|
+
// Validate numbers
|
|
211
|
+
if (rules.type === 'number') {
|
|
212
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
|
213
|
+
throw new ValidationError(`Configuration field '${key}' must be a valid number`, key);
|
|
214
|
+
}
|
|
215
|
+
if (rules.min !== undefined && value < rules.min) {
|
|
216
|
+
throw new ValidationError(`Configuration field '${key}' must be >= ${rules.min}`, key);
|
|
217
|
+
}
|
|
218
|
+
if (rules.max !== undefined && value > rules.max) {
|
|
219
|
+
throw new ValidationError(`Configuration field '${key}' must be <= ${rules.max}`, key);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Custom validator
|
|
223
|
+
if (rules.validator && !rules.validator(value)) {
|
|
224
|
+
throw new ValidationError(`Configuration field '${key}' failed validation`, key);
|
|
225
|
+
}
|
|
226
|
+
validated[key] = value;
|
|
227
|
+
}
|
|
228
|
+
return validated;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Sanitize HTML to prevent XSS
|
|
232
|
+
*
|
|
233
|
+
* @param html - HTML string to sanitize
|
|
234
|
+
* @returns Sanitized HTML (text only)
|
|
235
|
+
*/
|
|
236
|
+
static sanitizeHtml(html) {
|
|
237
|
+
if (typeof html !== 'string') {
|
|
238
|
+
return '';
|
|
239
|
+
}
|
|
240
|
+
// Strip all HTML tags, keep text only
|
|
241
|
+
return html
|
|
242
|
+
.replace(/<[^>]*>/g, '')
|
|
243
|
+
.replace(/</g, '<')
|
|
244
|
+
.replace(/>/g, '>')
|
|
245
|
+
.replace(/&/g, '&')
|
|
246
|
+
.replace(/"/g, '"')
|
|
247
|
+
.replace(/'/g, "'");
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Validate email address
|
|
251
|
+
*
|
|
252
|
+
* @param email - Email to validate
|
|
253
|
+
* @returns Normalized email
|
|
254
|
+
* @throws ValidationError if invalid
|
|
255
|
+
*/
|
|
256
|
+
static validateEmail(email) {
|
|
257
|
+
if (!email || typeof email !== 'string') {
|
|
258
|
+
throw new ValidationError('Email is required', 'email');
|
|
259
|
+
}
|
|
260
|
+
// Basic email regex
|
|
261
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
262
|
+
if (!emailRegex.test(email)) {
|
|
263
|
+
throw new ValidationError('Invalid email format', 'email');
|
|
264
|
+
}
|
|
265
|
+
if (email.length > 254) {
|
|
266
|
+
throw new ValidationError('Email too long (max 254 chars)', 'email');
|
|
267
|
+
}
|
|
268
|
+
return email.toLowerCase().trim();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Validation middleware factory
|
|
273
|
+
*
|
|
274
|
+
* Creates validation middleware for Express/Fastify routes
|
|
275
|
+
*/
|
|
276
|
+
export function createValidationMiddleware(validator) {
|
|
277
|
+
return async (req, res, next) => {
|
|
278
|
+
try {
|
|
279
|
+
await validator(req);
|
|
280
|
+
next();
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
if (error instanceof ValidationError) {
|
|
284
|
+
res.status(400).json({
|
|
285
|
+
error: 'Validation Error',
|
|
286
|
+
message: error.message,
|
|
287
|
+
field: error.field,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
res.status(500).json({
|
|
292
|
+
error: 'Internal Server Error',
|
|
293
|
+
message: 'Validation failed',
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=input-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-validator.js","sourceRoot":"","sources":["../../src/utils/input-validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Input Validation Utilities\n *\n * Provides secure input validation for RuVector integration:\n * - Task description validation\n * - Configuration validation\n * - Injection attack prevention\n * - Resource exhaustion prevention\n */\n\nexport interface ValidationOptions {\n maxLength?: number;\n minLength?: number;\n allowEmpty?: boolean;\n sanitize?: boolean;\n}\n\nexport class ValidationError extends Error {\n constructor(message: string, public field?: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Input Validator\n *\n * Validates all external inputs to prevent:\n * - Injection attacks (XSS, SQL injection, prompt injection)\n * - Resource exhaustion (excessive length, recursion)\n * - Malicious content (scripts, control characters)\n */\nexport class InputValidator {\n // Suspicious patterns that could indicate attacks\n private static readonly SUSPICIOUS_PATTERNS = [\n /<script/i, // XSS attempt\n /javascript:/i, // JavaScript protocol\n /data:text\\/html/i, // Data URI XSS\n /on\\w+\\s*=/i, // Event handlers\n /\\beval\\s*\\(/i, // eval() calls\n /\\bFunction\\s*\\(/i, // Function constructor\n /__proto__/, // Prototype pollution\n /\\.\\.\\//, // Path traversal\n /[;\\x00]/, // SQL injection chars\n ];\n\n // Control characters that should be removed\n private static readonly CONTROL_CHARS_REGEX = /[\\x00-\\x1F\\x7F]/g;\n\n /**\n * Validate task description\n *\n * @param taskDescription - User-provided task description\n * @param options - Validation options\n * @returns Sanitized task description\n * @throws ValidationError if invalid\n */\n static validateTaskDescription(\n taskDescription: string,\n options?: ValidationOptions\n ): string {\n const opts = {\n maxLength: options?.maxLength ?? 10000,\n minLength: options?.minLength ?? 1,\n allowEmpty: options?.allowEmpty ?? false,\n sanitize: options?.sanitize ?? true,\n };\n\n // Check for null/undefined\n if (taskDescription === null || taskDescription === undefined) {\n throw new ValidationError('Task description is required', 'taskDescription');\n }\n\n // Check type\n if (typeof taskDescription !== 'string') {\n throw new ValidationError(\n `Task description must be a string, got ${typeof taskDescription}`,\n 'taskDescription'\n );\n }\n\n // Check empty\n if (!opts.allowEmpty && taskDescription.trim().length === 0) {\n throw new ValidationError('Task description cannot be empty', 'taskDescription');\n }\n\n // Check length\n if (taskDescription.length < opts.minLength) {\n throw new ValidationError(\n `Task description too short (min ${opts.minLength} chars)`,\n 'taskDescription'\n );\n }\n\n if (taskDescription.length > opts.maxLength) {\n throw new ValidationError(\n `Task description too long (max ${opts.maxLength} chars)`,\n 'taskDescription'\n );\n }\n\n // Sanitize if requested\n let sanitized = taskDescription;\n if (opts.sanitize) {\n // Remove control characters\n sanitized = sanitized.replace(InputValidator.CONTROL_CHARS_REGEX, '');\n\n // Check for suspicious patterns\n for (const pattern of InputValidator.SUSPICIOUS_PATTERNS) {\n if (pattern.test(sanitized)) {\n throw new ValidationError(\n 'Task description contains suspicious content',\n 'taskDescription'\n );\n }\n }\n }\n\n return sanitized.trim();\n }\n\n /**\n * Validate agent name\n *\n * @param agentName - Agent identifier\n * @returns Sanitized agent name\n * @throws ValidationError if invalid\n */\n static validateAgentName(agentName: string): string {\n if (!agentName || typeof agentName !== 'string') {\n throw new ValidationError('Agent name is required', 'agentName');\n }\n\n if (agentName.length < 1 || agentName.length > 100) {\n throw new ValidationError(\n 'Agent name must be between 1-100 characters',\n 'agentName'\n );\n }\n\n // Only allow alphanumeric, dash, underscore\n if (!/^[a-zA-Z0-9_-]+$/.test(agentName)) {\n throw new ValidationError(\n 'Agent name can only contain letters, numbers, dash, and underscore',\n 'agentName'\n );\n }\n\n return agentName.toLowerCase();\n }\n\n /**\n * Validate confidence score\n *\n * @param confidence - Confidence score (0-1)\n * @returns Validated confidence\n * @throws ValidationError if invalid\n */\n static validateConfidence(confidence: number): number {\n if (typeof confidence !== 'number') {\n throw new ValidationError(\n `Confidence must be a number, got ${typeof confidence}`,\n 'confidence'\n );\n }\n\n if (Number.isNaN(confidence) || !Number.isFinite(confidence)) {\n throw new ValidationError('Confidence must be a valid number', 'confidence');\n }\n\n if (confidence < 0 || confidence > 1) {\n throw new ValidationError('Confidence must be between 0 and 1', 'confidence');\n }\n\n return confidence;\n }\n\n /**\n * Validate timeout value\n *\n * @param timeout - Timeout in milliseconds\n * @param min - Minimum allowed timeout (default: 100ms)\n * @param max - Maximum allowed timeout (default: 5 minutes)\n * @returns Validated timeout\n * @throws ValidationError if invalid\n */\n static validateTimeout(\n timeout: number,\n min: number = 100,\n max: number = 300000\n ): number {\n if (typeof timeout !== 'number') {\n throw new ValidationError(\n `Timeout must be a number, got ${typeof timeout}`,\n 'timeout'\n );\n }\n\n if (Number.isNaN(timeout) || !Number.isFinite(timeout)) {\n throw new ValidationError('Timeout must be a valid number', 'timeout');\n }\n\n if (timeout < min) {\n throw new ValidationError(`Timeout too short (min ${min}ms)`, 'timeout');\n }\n\n if (timeout > max) {\n throw new ValidationError(`Timeout too long (max ${max}ms)`, 'timeout');\n }\n\n return Math.floor(timeout);\n }\n\n /**\n * Validate array of strings\n *\n * @param array - Array to validate\n * @param fieldName - Field name for error messages\n * @param maxItems - Maximum number of items\n * @param maxLength - Maximum length per item\n * @returns Validated array\n * @throws ValidationError if invalid\n */\n static validateStringArray(\n array: unknown,\n fieldName: string,\n maxItems: number = 100,\n maxLength: number = 1000\n ): string[] {\n if (!Array.isArray(array)) {\n throw new ValidationError(`${fieldName} must be an array`, fieldName);\n }\n\n if (array.length > maxItems) {\n throw new ValidationError(\n `${fieldName} has too many items (max ${maxItems})`,\n fieldName\n );\n }\n\n const validated: string[] = [];\n for (let i = 0; i < array.length; i++) {\n const item = array[i];\n\n if (typeof item !== 'string') {\n throw new ValidationError(\n `${fieldName}[${i}] must be a string`,\n fieldName\n );\n }\n\n if (item.length > maxLength) {\n throw new ValidationError(\n `${fieldName}[${i}] too long (max ${maxLength} chars)`,\n fieldName\n );\n }\n\n validated.push(item);\n }\n\n return validated;\n }\n\n /**\n * Validate configuration object\n *\n * @param config - Configuration to validate\n * @param schema - Validation schema\n * @returns Validated configuration\n * @throws ValidationError if invalid\n */\n static validateConfig<T extends Record<string, any>>(\n config: unknown,\n schema: {\n [K in keyof T]: {\n type: 'string' | 'number' | 'boolean' | 'object';\n required?: boolean;\n min?: number;\n max?: number;\n validator?: (value: any) => boolean;\n };\n }\n ): T {\n if (!config || typeof config !== 'object') {\n throw new ValidationError('Configuration must be an object', 'config');\n }\n\n const validated: any = {};\n const configObj = config as Record<string, any>;\n\n for (const [key, rules] of Object.entries(schema)) {\n const value = configObj[key];\n\n // Check required\n if (rules.required && (value === undefined || value === null)) {\n throw new ValidationError(`Configuration field '${key}' is required`, key);\n }\n\n // Skip if optional and not provided\n if (!rules.required && (value === undefined || value === null)) {\n continue;\n }\n\n // Check type\n if (typeof value !== rules.type) {\n throw new ValidationError(\n `Configuration field '${key}' must be ${rules.type}, got ${typeof value}`,\n key\n );\n }\n\n // Validate numbers\n if (rules.type === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n throw new ValidationError(\n `Configuration field '${key}' must be a valid number`,\n key\n );\n }\n\n if (rules.min !== undefined && value < rules.min) {\n throw new ValidationError(\n `Configuration field '${key}' must be >= ${rules.min}`,\n key\n );\n }\n\n if (rules.max !== undefined && value > rules.max) {\n throw new ValidationError(\n `Configuration field '${key}' must be <= ${rules.max}`,\n key\n );\n }\n }\n\n // Custom validator\n if (rules.validator && !rules.validator(value)) {\n throw new ValidationError(\n `Configuration field '${key}' failed validation`,\n key\n );\n }\n\n validated[key] = value;\n }\n\n return validated as T;\n }\n\n /**\n * Sanitize HTML to prevent XSS\n *\n * @param html - HTML string to sanitize\n * @returns Sanitized HTML (text only)\n */\n static sanitizeHtml(html: string): string {\n if (typeof html !== 'string') {\n return '';\n }\n\n // Strip all HTML tags, keep text only\n return html\n .replace(/<[^>]*>/g, '')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/&/g, '&')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n }\n\n /**\n * Validate email address\n *\n * @param email - Email to validate\n * @returns Normalized email\n * @throws ValidationError if invalid\n */\n static validateEmail(email: string): string {\n if (!email || typeof email !== 'string') {\n throw new ValidationError('Email is required', 'email');\n }\n\n // Basic email regex\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n throw new ValidationError('Invalid email format', 'email');\n }\n\n if (email.length > 254) {\n throw new ValidationError('Email too long (max 254 chars)', 'email');\n }\n\n return email.toLowerCase().trim();\n }\n}\n\n/**\n * Validation middleware factory\n *\n * Creates validation middleware for Express/Fastify routes\n */\nexport function createValidationMiddleware(\n validator: (req: any) => void | Promise<void>\n) {\n return async (req: any, res: any, next: any) => {\n try {\n await validator(req);\n next();\n } catch (error) {\n if (error instanceof ValidationError) {\n res.status(400).json({\n error: 'Validation Error',\n message: error.message,\n field: error.field,\n });\n } else {\n res.status(500).json({\n error: 'Internal Server Error',\n message: 'Validation failed',\n });\n }\n }\n };\n}\n"]}
|
|
@@ -10,11 +10,11 @@ export class RateLimiter {
|
|
|
10
10
|
// Cleanup expired entries every minute
|
|
11
11
|
this.cleanupInterval = setInterval(() => {
|
|
12
12
|
const now = Date.now();
|
|
13
|
-
|
|
13
|
+
this.clients.forEach((record, key) => {
|
|
14
14
|
if (record.resetTime < now && (!record.blockedUntil || record.blockedUntil < now)) {
|
|
15
15
|
this.clients.delete(key);
|
|
16
16
|
}
|
|
17
|
-
}
|
|
17
|
+
});
|
|
18
18
|
}, 60000);
|
|
19
19
|
}
|
|
20
20
|
async consume(key) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,MAAM,OAAO,WAAW;IACd,MAAM,CAAoB;IAC1B,OAAO,GAA8B,IAAI,GAAG,EAAE,CAAC;IAC/C,eAAe,CAAiB;IAExC,YAAY,MAAyB;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,uCAAuC;QACvC,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,MAAM,OAAO,WAAW;IACd,MAAM,CAAoB;IAC1B,OAAO,GAA8B,IAAI,GAAG,EAAE,CAAC;IAC/C,eAAe,CAAiB;IAExC,YAAY,MAAyB;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,uCAAuC;QACvC,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;gBACnC,IAAI,MAAM,CAAC,SAAS,GAAG,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,YAAY,GAAG,GAAG,CAAC,EAAE,CAAC;oBAClF,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,KAAK,CAAC,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAErC,6BAA6B;QAC7B,IAAI,MAAM,EAAE,YAAY,IAAI,MAAM,CAAC,YAAY,GAAG,GAAG,EAAE,CAAC;YACtD,MAAM,WAAW,GAAG,MAAM,CAAC,YAAY,GAAG,GAAG,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAChG,CAAC;QAED,6BAA6B;QAC7B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;gBACpB,KAAK,EAAE,CAAC;gBACR,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI;aAC7C,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,kBAAkB;QAClB,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,0BAA0B;QAC1B,IAAI,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,CAAC,YAAY,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,MAAM,CAAC,MAAM,iBAAiB,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QACvG,CAAC;IACH,CAAC;IAED,OAAO;QACL,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF","sourcesContent":["/**\n * Simple in-memory rate limiter for proxy protection\n */\n\nexport interface RateLimiterConfig {\n points: number; // Number of requests\n duration: number; // Time window in seconds\n blockDuration: number; // Block duration in seconds when exceeded\n}\n\ninterface ClientRecord {\n count: number;\n resetTime: number;\n blockedUntil?: number;\n}\n\nexport class RateLimiter {\n private config: RateLimiterConfig;\n private clients: Map<string, ClientRecord> = new Map();\n private cleanupInterval: NodeJS.Timeout;\n\n constructor(config: RateLimiterConfig) {\n this.config = config;\n\n // Cleanup expired entries every minute\n this.cleanupInterval = setInterval(() => {\n const now = Date.now();\n this.clients.forEach((record, key) => {\n if (record.resetTime < now && (!record.blockedUntil || record.blockedUntil < now)) {\n this.clients.delete(key);\n }\n });\n }, 60000);\n }\n\n async consume(key: string): Promise<void> {\n const now = Date.now();\n const record = this.clients.get(key);\n\n // Check if client is blocked\n if (record?.blockedUntil && record.blockedUntil > now) {\n const remainingMs = record.blockedUntil - now;\n throw new Error(`Rate limit exceeded. Try again in ${Math.ceil(remainingMs / 1000)} seconds`);\n }\n\n // Initialize or reset record\n if (!record || record.resetTime < now) {\n this.clients.set(key, {\n count: 1,\n resetTime: now + this.config.duration * 1000\n });\n return;\n }\n\n // Increment count\n record.count++;\n\n // Check if limit exceeded\n if (record.count > this.config.points) {\n record.blockedUntil = now + this.config.blockDuration * 1000;\n throw new Error(`Rate limit exceeded (${this.config.points} requests per ${this.config.duration}s)`);\n }\n }\n\n destroy(): void {\n clearInterval(this.cleanupInterval);\n this.clients.clear();\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-flow",
|
|
3
|
-
"version": "2.0.1-alpha.
|
|
3
|
+
"version": "2.0.1-alpha.8",
|
|
4
4
|
"description": "Production-ready AI agent orchestration platform with 66 specialized agents, 213 MCP tools, ReasoningBank learning memory, and autonomous multi-agent swarms. Built by @ruvnet with Claude Agent SDK, neural networks, memory persistence, GitHub integration, and distributed consensus protocols.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -143,10 +143,13 @@
|
|
|
143
143
|
"@anthropic-ai/claude-agent-sdk": "^0.1.5",
|
|
144
144
|
"@anthropic-ai/sdk": "^0.65.0",
|
|
145
145
|
"@google/genai": "^1.22.0",
|
|
146
|
+
"@ruvector/router": "^0.1.25",
|
|
147
|
+
"@ruvector/ruvllm": "^0.2.3",
|
|
148
|
+
"@ruvector/tiny-dancer": "^0.1.15",
|
|
146
149
|
"@supabase/supabase-js": "^2.78.0",
|
|
147
150
|
"@xenova/transformers": "^2.17.2",
|
|
148
151
|
"agent-booster": "file:../packages/agent-booster",
|
|
149
|
-
"agentdb": "^
|
|
152
|
+
"agentdb": "^2.0.0-alpha.2.20",
|
|
150
153
|
"axios": "^1.12.2",
|
|
151
154
|
"better-sqlite3": "^11.10.0",
|
|
152
155
|
"dotenv": "^16.4.5",
|
|
@@ -258,7 +258,7 @@ export function log(message) {
|
|
|
258
258
|
wasm.log(ptr0, len0);
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
function
|
|
261
|
+
function __wbg_adapter_6(arg0, arg1, arg2) {
|
|
262
262
|
wasm.__wbindgen_export_5(arg0, arg1, addHeapObject(arg2));
|
|
263
263
|
}
|
|
264
264
|
|
|
@@ -540,7 +540,7 @@ export function __wbindgen_cast_2241b6af4c4b2941(arg0, arg1) {
|
|
|
540
540
|
|
|
541
541
|
export function __wbindgen_cast_8eb6fd44e7238d11(arg0, arg1) {
|
|
542
542
|
// Cast intrinsic for `Closure(Closure { dtor_idx: 62, function: Function { arguments: [Externref], shim_idx: 63, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
543
|
-
const ret = makeMutClosure(arg0, arg1, 62,
|
|
543
|
+
const ret = makeMutClosure(arg0, arg1, 62, __wbg_adapter_6);
|
|
544
544
|
return addHeapObject(ret);
|
|
545
545
|
};
|
|
546
546
|
|
|
Binary file
|