@@ -71,52 +71,111 @@ export async function checkOpenAI(config: Config): Promise<boolean> {
7171 }
7272}
7373
74+ export interface ServiceStatus {
75+ service : string ;
76+ status : 'available' | 'unavailable' ;
77+ details ?: string ;
78+ }
79+
80+ export interface PrerequisiteValidationResult {
81+ allPassed : boolean ;
82+ services : ServiceStatus [ ] ;
83+ }
84+
7485/**
75- * Generate error message for failed prerequisites
86+ * Check all prerequisites and return structured status
7687 */
77- function createErrorMessage ( qdrantOk : boolean , embeddingOk : boolean , provider : string ) : string {
78- const errors : string [ ] = [ ] ;
88+ export async function checkAllPrerequisitesDetailed ( config : Config ) : Promise < PrerequisiteValidationResult > {
89+ const services : ServiceStatus [ ] = [ ] ;
7990
80- if ( ! qdrantOk ) {
81- errors . push ( 'Qdrant database is inaccessible' ) ;
82- }
91+ // Check Qdrant
92+ const qdrantOk = await checkQdrant ( config ) ;
93+ services . push ( {
94+ service : 'qdrant' ,
95+ status : qdrantOk ? 'available' : 'unavailable' ,
96+ details : qdrantOk ? undefined : `Cannot connect to Qdrant at ${ config . storage . qdrantEndpoint } `
97+ } ) ;
8398
84- if ( ! embeddingOk ) {
85- if ( provider === 'ollama' ) {
86- errors . push ( 'Ollama embedding service is inaccessible or model unavailable' ) ;
87- } else if ( provider === 'openai' ) {
88- errors . push ( 'OpenAI API is inaccessible or key invalid' ) ;
99+ // Check embedding service
100+ let embeddingOk = false ;
101+ let embeddingDetails : string | undefined ;
102+
103+ if ( config . embedding . provider === 'ollama' ) {
104+ const ollamaOk = await checkOllama ( config ) ;
105+ const modelOk = ollamaOk ? await checkOllamaModel ( config ) : false ;
106+ embeddingOk = ollamaOk && modelOk ;
107+
108+ if ( ! ollamaOk ) {
109+ embeddingDetails = `Cannot connect to Ollama at ${ config . embedding . endpoint } ` ;
110+ } else if ( ! modelOk ) {
111+ embeddingDetails = `Model "${ config . embedding . model } " not available in Ollama` ;
112+ }
113+ } else if ( config . embedding . provider === 'openai' ) {
114+ embeddingOk = await checkOpenAI ( config ) ;
115+ if ( ! embeddingOk ) {
116+ embeddingDetails = process . env . OPENAI_API_KEY ?
117+ 'OpenAI API request failed' :
118+ 'OPENAI_API_KEY environment variable not set' ;
89119 }
120+ } else if ( config . embedding . provider === 'mock' ) {
121+ embeddingOk = true ;
122+ } else {
123+ embeddingDetails = `Unknown embedding provider: ${ config . embedding . provider } ` ;
90124 }
91125
92- errors . push ( '' ) ;
93- errors . push ( 'For setup instructions, see: https://github.com/peteretelej/directory-indexer#setup' ) ;
126+ services . push ( {
127+ service : config . embedding . provider ,
128+ status : embeddingOk ? 'available' : 'unavailable' ,
129+ details : embeddingDetails
130+ } ) ;
94131
95- return errors . join ( '\n' ) ;
132+ return {
133+ allPassed : services . every ( s => s . status === 'available' ) ,
134+ services
135+ } ;
136+ }
137+
138+ /**
139+ * Generate comprehensive error message that lists all missing services
140+ */
141+ function createComprehensiveErrorMessage ( result : PrerequisiteValidationResult ) : string {
142+ const unavailableServices = result . services . filter ( s => s . status === 'unavailable' ) ;
143+
144+ const serviceDescriptions = unavailableServices . map ( service => {
145+ return `${ service . service } (${ service . details } )` ;
146+ } ) ;
147+
148+ const message = `Required services are not available to use directory-indexer features: ${ serviceDescriptions . join ( ', ' ) } .` ;
149+ const setup = 'For setup instructions, see: https://github.com/peteretelej/directory-indexer#setup' ;
150+
151+ return `${ message } \n\n${ setup } ` ;
96152}
97153
98154/**
99155 * Validate all prerequisites for indexing (needs both Qdrant and embedding service)
100156 */
101157export async function validateIndexPrerequisites ( config : Config ) : Promise < void > {
102- const [ qdrantOk , embeddingOk ] = await Promise . all ( [
103- checkQdrant ( config ) ,
104- checkEmbeddingService ( config )
105- ] ) ;
158+ const result = await checkAllPrerequisitesDetailed ( config ) ;
106159
107- if ( ! qdrantOk || ! embeddingOk ) {
108- throw new PrerequisiteError ( createErrorMessage ( qdrantOk , embeddingOk , config . embedding . provider ) ) ;
160+ if ( ! result . allPassed ) {
161+ throw new PrerequisiteError ( createComprehensiveErrorMessage ( result ) ) ;
109162 }
110163}
111164
112165/**
113166 * Validate prerequisites for search (needs only Qdrant)
114167 */
115168export async function validateSearchPrerequisites ( config : Config ) : Promise < void > {
116- const qdrantOk = await checkQdrant ( config ) ;
169+ const result = await checkAllPrerequisitesDetailed ( config ) ;
170+ const qdrantService = result . services . find ( s => s . service === 'qdrant' ) ;
117171
118- if ( ! qdrantOk ) {
119- throw new PrerequisiteError ( createErrorMessage ( false , true , config . embedding . provider ) ) ;
172+ if ( qdrantService ?. status === 'unavailable' ) {
173+ // Create a result with only Qdrant for error message
174+ const qdrantOnlyResult : PrerequisiteValidationResult = {
175+ allPassed : false ,
176+ services : [ qdrantService ]
177+ } ;
178+ throw new PrerequisiteError ( createComprehensiveErrorMessage ( qdrantOnlyResult ) ) ;
120179 }
121180}
122181
0 commit comments