diff --git a/.opencode/agents/enforcer.yml b/.opencode/agents/enforcer.yml index 1cb450056..c2b61182f 100644 --- a/.opencode/agents/enforcer.yml +++ b/.opencode/agents/enforcer.yml @@ -2,6 +2,8 @@ name: enforcer description: "Enforcer agent for codex compliance and error prevention" version: "1.0.0" +system: "You are the StringRay Enforcer agent. You validate code against the Universal Development Codex (60 error-prevention terms), enforce quality gates, and prevent errors with 99.6% accuracy. You check for type safety, input validation, memory optimization, error handling, security, and architecture compliance. Block operations that violate codex terms." + # ============================================================================= # CODEX COMPLIANCE # ============================================================================= diff --git a/src/__tests__/unit/integration.test.ts b/src/__tests__/unit/integration.test.ts index 2e5338d26..c8ad57b6c 100644 --- a/src/__tests__/unit/integration.test.ts +++ b/src/__tests__/unit/integration.test.ts @@ -20,7 +20,7 @@ vi.mock("child_process", () => ({ })), })); -vi.mock("../mcps/agent-resolver.js", () => ({ +vi.mock("../../mcps/agent-resolver.js", () => ({ resolveAgent: vi.fn().mockResolvedValue({ name: "enforcer", system: "You are a code quality enforcer...", diff --git a/src/mcps/orchestrator/execution/execution-planner.ts b/src/mcps/orchestrator/execution/execution-planner.ts index a11d0330b..d3c3b1033 100644 --- a/src/mcps/orchestrator/execution/execution-planner.ts +++ b/src/mcps/orchestrator/execution/execution-planner.ts @@ -46,8 +46,8 @@ export class ExecutionPlanner { errors.push(`Task ${i}: Missing required field 'type'`); } - // Check dependencies exist - if (task.dependencies && task.id) { + // Check dependencies exist (only for string[] dependency IDs) + if (task.dependencies && task.id && Array.isArray(task.dependencies)) { const taskIds = new Set(tasks.map(t => t.id).filter((id): id is string => !!id)); for (const depId of task.dependencies) { if (!taskIds.has(depId)) { @@ -145,7 +145,10 @@ export class ExecutionPlanner { const dependentTasks: OrchestrationTask[] = []; for (const task of sortedTasks) { - if (!task.dependencies || task.dependencies.length === 0) { + const hasDeps = task.dependencies + ? (Array.isArray(task.dependencies) ? task.dependencies.length : Number(task.dependencies)) > 0 + : false; + if (!hasDeps) { independentTasks.push(task); } else { dependentTasks.push(task); @@ -171,7 +174,7 @@ export class ExecutionPlanner { if (visited.has(task.id)) return; visited.add(task.id); - if (task.dependencies) { + if (task.dependencies && Array.isArray(task.dependencies)) { for (const depId of task.dependencies) { const depTask = taskMap.get(depId); if (depTask) visit(depTask); @@ -314,9 +317,12 @@ export class ExecutionPlanner { complexity = (complexity + task.estimatedComplexity) / 2; } - // Adjust based on dependencies + // Adjust based on dependencies (handles both string[] and number) if (task.dependencies) { - complexity += task.dependencies.length * 5; + const depCount = Array.isArray(task.dependencies) + ? task.dependencies.length + : Number(task.dependencies) || 0; + complexity += depCount * 5; } return Math.min(Math.max(Math.round(complexity), 1), 100); @@ -337,8 +343,11 @@ export class ExecutionPlanner { */ private calculateParallelPotential(tasks: OrchestrationTask[]): number { // Tasks without dependencies can run in parallel - const independent = tasks.filter(t => !t.dependencies || t.dependencies.length === 0); - return independent.length / tasks.length; + const independent = tasks.filter( + t => !t.dependencies || + (Array.isArray(t.dependencies) ? t.dependencies.length : Number(t.dependencies)) === 0 + ); + return tasks.length > 0 ? independent.length / tasks.length : 0; } } diff --git a/src/mcps/orchestrator/handlers/status-handler.ts b/src/mcps/orchestrator/handlers/status-handler.ts index e763232e4..e891f2e05 100644 --- a/src/mcps/orchestrator/handlers/status-handler.ts +++ b/src/mcps/orchestrator/handlers/status-handler.ts @@ -258,14 +258,14 @@ ${optimizations.map((o) => `• ${o}`).join('\n')} private formatStatusResponse(status: unknown, detailed: boolean): string { const statusAny = status as Record; - // Check if it's a completed session - if (statusAny.completed) { + // Check if it's a completed session (supports both 'completed' boolean and status: 'completed') + if (statusAny.completed || statusAny.status === 'completed') { const result = statusAny as { success: boolean; duration: number; completedTasks: number; failedTasks: number }; return `šŸ“Š Session Status: COMPLETED **Success:** ${result.success ? 'āœ… Yes' : 'āŒ No'} **Duration:** ${result.duration}ms -**Tasks:** ${result.completedTasks + result.failedTasks} (${result.completedTasks} āœ…, ${result.failedTasks} āŒ)`; +**Tasks:** ${(result.completedTasks ?? 0) + (result.failedTasks ?? 0)} (${result.completedTasks ?? 0} āœ…, ${result.failedTasks ?? 0} āŒ)`; } // Overall status @@ -273,19 +273,21 @@ ${optimizations.map((o) => `• ${o}`).join('\n')} let response = `šŸ“Š Orchestration Status -**Active Sessions:** ${orchStatus.activeSessions} -**Total Tasks Executed:** ${orchStatus.totalTasks}`; +**Active Sessions:** ${orchStatus.activeSessions ?? 0} +**Total Tasks Executed:** ${orchStatus.totalTasks ?? 0}`; - if (Object.keys(orchStatus.agentUtilization).length > 0) { + const agentUtil = orchStatus.agentUtilization || {}; + if (Object.keys(agentUtil).length > 0) { response += `\n\n**Agent Utilization:**`; - for (const [agent, count] of Object.entries(orchStatus.agentUtilization)) { + for (const [agent, count] of Object.entries(agentUtil)) { response += `\n• ${agent}: ${count} tasks`; } } - if (detailed && orchStatus.recentSessions.length > 0) { + const sessions = orchStatus.recentSessions || []; + if (detailed && sessions.length > 0) { response += `\n\n**Recent Sessions:**`; - for (const session of orchStatus.recentSessions) { + for (const session of sessions) { response += `\n• ${session.sessionId}: ${session.tasks} tasks, ${session.duration}ms`; } } diff --git a/src/mcps/orchestrator/types.ts b/src/mcps/orchestrator/types.ts index c13b7c7ee..2557c02de 100644 --- a/src/mcps/orchestrator/types.ts +++ b/src/mcps/orchestrator/types.ts @@ -15,7 +15,7 @@ export interface OrchestrationTask { description: string; type: string; priority?: 'critical' | 'high' | 'medium' | 'low'; - dependencies?: string[]; + dependencies?: string[] | number; estimatedComplexity?: number; } diff --git a/src/mcps/security-scan.server.ts b/src/mcps/security-scan.server.ts index a8ff9224e..086e11f1f 100644 --- a/src/mcps/security-scan.server.ts +++ b/src/mcps/security-scan.server.ts @@ -138,10 +138,11 @@ class StrRaySecurityScanServer { try { // 1. Dependency Vulnerability Scanning if (scope === "dependencies" || scope === "full") { + const detectedPm = this.detectPackageManager("auto"); const depResults = await this.scanDependencies( auditLevel, includeOutdated, - "npm", + detectedPm, ); results.vulnerabilities.push(...depResults.vulnerabilities); results.recommendations.push(...depResults.recommendations);