rag-lite-ts 2.1.1 → 2.3.0
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 +88 -5
- package/dist/{cli → cjs/cli}/indexer.js +73 -15
- package/dist/cjs/cli/ui-server.d.ts +5 -0
- package/dist/cjs/cli/ui-server.js +152 -0
- package/dist/{cli.js → cjs/cli.js} +25 -6
- package/dist/{core → cjs/core}/binary-index-format.js +6 -3
- package/dist/{core → cjs/core}/db.d.ts +56 -0
- package/dist/{core → cjs/core}/db.js +105 -0
- package/dist/{core → cjs/core}/ingestion.js +3 -0
- package/dist/cjs/core/knowledge-base-manager.d.ts +109 -0
- package/dist/cjs/core/knowledge-base-manager.js +256 -0
- package/dist/{core → cjs/core}/model-validator.js +1 -1
- package/dist/{core → cjs/core}/search-pipeline.js +1 -1
- package/dist/{core → cjs/core}/search.js +1 -1
- package/dist/cjs/core/vector-index-messages.d.ts +52 -0
- package/dist/cjs/core/vector-index-messages.js +5 -0
- package/dist/cjs/core/vector-index-worker.d.ts +6 -0
- package/dist/cjs/core/vector-index-worker.js +304 -0
- package/dist/cjs/core/vector-index.d.ts +107 -0
- package/dist/cjs/core/vector-index.js +344 -0
- package/dist/{factories → cjs/factories}/ingestion-factory.js +3 -7
- package/dist/{factories → cjs/factories}/search-factory.js +11 -0
- package/dist/{index-manager.d.ts → cjs/index-manager.d.ts} +23 -3
- package/dist/{index-manager.js → cjs/index-manager.js} +84 -15
- package/dist/{index.d.ts → cjs/index.d.ts} +2 -1
- package/dist/{index.js → cjs/index.js} +3 -1
- package/dist/esm/api-errors.d.ts +90 -0
- package/dist/esm/api-errors.js +320 -0
- package/dist/esm/cli/indexer.d.ts +11 -0
- package/dist/esm/cli/indexer.js +529 -0
- package/dist/esm/cli/search.d.ts +7 -0
- package/dist/esm/cli/search.js +332 -0
- package/dist/esm/cli/ui-server.d.ts +5 -0
- package/dist/esm/cli/ui-server.js +152 -0
- package/dist/esm/cli.d.ts +3 -0
- package/dist/esm/cli.js +548 -0
- package/dist/esm/config.d.ts +51 -0
- package/dist/esm/config.js +79 -0
- package/dist/esm/core/abstract-embedder.d.ts +125 -0
- package/dist/esm/core/abstract-embedder.js +264 -0
- package/dist/esm/core/actionable-error-messages.d.ts +60 -0
- package/dist/esm/core/actionable-error-messages.js +397 -0
- package/dist/esm/core/adapters.d.ts +93 -0
- package/dist/esm/core/adapters.js +139 -0
- package/dist/esm/core/batch-processing-optimizer.d.ts +155 -0
- package/dist/esm/core/batch-processing-optimizer.js +536 -0
- package/dist/esm/core/binary-index-format.d.ts +78 -0
- package/dist/esm/core/binary-index-format.js +294 -0
- package/dist/esm/core/chunker.d.ts +119 -0
- package/dist/esm/core/chunker.js +73 -0
- package/dist/esm/core/cli-database-utils.d.ts +53 -0
- package/dist/esm/core/cli-database-utils.js +239 -0
- package/dist/esm/core/config.d.ts +102 -0
- package/dist/esm/core/config.js +247 -0
- package/dist/esm/core/content-errors.d.ts +111 -0
- package/dist/esm/core/content-errors.js +362 -0
- package/dist/esm/core/content-manager.d.ts +335 -0
- package/dist/esm/core/content-manager.js +1476 -0
- package/dist/esm/core/content-performance-optimizer.d.ts +150 -0
- package/dist/esm/core/content-performance-optimizer.js +516 -0
- package/dist/esm/core/content-resolver.d.ts +104 -0
- package/dist/esm/core/content-resolver.js +285 -0
- package/dist/esm/core/cross-modal-search.d.ts +164 -0
- package/dist/esm/core/cross-modal-search.js +342 -0
- package/dist/esm/core/database-connection-manager.d.ts +109 -0
- package/dist/esm/core/database-connection-manager.js +310 -0
- package/dist/esm/core/db.d.ts +269 -0
- package/dist/esm/core/db.js +1000 -0
- package/dist/esm/core/embedder-factory.d.ts +154 -0
- package/dist/esm/core/embedder-factory.js +311 -0
- package/dist/esm/core/error-handler.d.ts +112 -0
- package/dist/esm/core/error-handler.js +239 -0
- package/dist/esm/core/index.d.ts +59 -0
- package/dist/esm/core/index.js +69 -0
- package/dist/esm/core/ingestion.d.ts +202 -0
- package/dist/esm/core/ingestion.js +904 -0
- package/dist/esm/core/interfaces.d.ts +408 -0
- package/dist/esm/core/interfaces.js +106 -0
- package/dist/esm/core/knowledge-base-manager.d.ts +109 -0
- package/dist/esm/core/knowledge-base-manager.js +256 -0
- package/dist/esm/core/lazy-dependency-loader.d.ts +147 -0
- package/dist/esm/core/lazy-dependency-loader.js +435 -0
- package/dist/esm/core/mode-detection-service.d.ts +150 -0
- package/dist/esm/core/mode-detection-service.js +565 -0
- package/dist/esm/core/mode-model-validator.d.ts +92 -0
- package/dist/esm/core/mode-model-validator.js +203 -0
- package/dist/esm/core/model-registry.d.ts +116 -0
- package/dist/esm/core/model-registry.js +411 -0
- package/dist/esm/core/model-validator.d.ts +217 -0
- package/dist/esm/core/model-validator.js +782 -0
- package/dist/esm/core/path-manager.d.ts +47 -0
- package/dist/esm/core/path-manager.js +71 -0
- package/dist/esm/core/raglite-paths.d.ts +121 -0
- package/dist/esm/core/raglite-paths.js +145 -0
- package/dist/esm/core/reranking-config.d.ts +42 -0
- package/dist/esm/core/reranking-config.js +147 -0
- package/dist/esm/core/reranking-factory.d.ts +92 -0
- package/dist/esm/core/reranking-factory.js +410 -0
- package/dist/esm/core/reranking-strategies.d.ts +310 -0
- package/dist/esm/core/reranking-strategies.js +650 -0
- package/dist/esm/core/resource-cleanup.d.ts +163 -0
- package/dist/esm/core/resource-cleanup.js +371 -0
- package/dist/esm/core/resource-manager.d.ts +212 -0
- package/dist/esm/core/resource-manager.js +564 -0
- package/dist/esm/core/search-pipeline.d.ts +111 -0
- package/dist/esm/core/search-pipeline.js +287 -0
- package/dist/esm/core/search.d.ts +141 -0
- package/dist/esm/core/search.js +320 -0
- package/dist/esm/core/streaming-operations.d.ts +145 -0
- package/dist/esm/core/streaming-operations.js +409 -0
- package/dist/esm/core/types.d.ts +66 -0
- package/dist/esm/core/types.js +6 -0
- package/dist/esm/core/universal-embedder.d.ts +177 -0
- package/dist/esm/core/universal-embedder.js +139 -0
- package/dist/esm/core/validation-messages.d.ts +99 -0
- package/dist/esm/core/validation-messages.js +334 -0
- package/dist/esm/core/vector-index-messages.d.ts +52 -0
- package/dist/esm/core/vector-index-messages.js +5 -0
- package/dist/esm/core/vector-index-worker.d.ts +6 -0
- package/dist/esm/core/vector-index-worker.js +304 -0
- package/dist/esm/core/vector-index.d.ts +107 -0
- package/dist/esm/core/vector-index.js +344 -0
- package/dist/esm/dom-polyfills.d.ts +6 -0
- package/dist/esm/dom-polyfills.js +37 -0
- package/dist/esm/factories/index.d.ts +27 -0
- package/dist/esm/factories/index.js +29 -0
- package/dist/esm/factories/ingestion-factory.d.ts +200 -0
- package/dist/esm/factories/ingestion-factory.js +473 -0
- package/dist/esm/factories/search-factory.d.ts +154 -0
- package/dist/esm/factories/search-factory.js +355 -0
- package/dist/esm/file-processor.d.ts +147 -0
- package/dist/esm/file-processor.js +963 -0
- package/dist/esm/index-manager.d.ts +136 -0
- package/dist/esm/index-manager.js +667 -0
- package/dist/esm/index.d.ts +76 -0
- package/dist/esm/index.js +112 -0
- package/dist/esm/indexer.d.ts +7 -0
- package/dist/esm/indexer.js +54 -0
- package/dist/esm/ingestion.d.ts +63 -0
- package/dist/esm/ingestion.js +124 -0
- package/dist/esm/mcp-server.d.ts +46 -0
- package/dist/esm/mcp-server.js +1820 -0
- package/dist/esm/multimodal/clip-embedder.d.ts +327 -0
- package/dist/esm/multimodal/clip-embedder.js +996 -0
- package/dist/esm/multimodal/index.d.ts +6 -0
- package/dist/esm/multimodal/index.js +6 -0
- package/dist/esm/preprocess.d.ts +19 -0
- package/dist/esm/preprocess.js +203 -0
- package/dist/esm/preprocessors/index.d.ts +17 -0
- package/dist/esm/preprocessors/index.js +38 -0
- package/dist/esm/preprocessors/mdx.d.ts +25 -0
- package/dist/esm/preprocessors/mdx.js +101 -0
- package/dist/esm/preprocessors/mermaid.d.ts +68 -0
- package/dist/esm/preprocessors/mermaid.js +329 -0
- package/dist/esm/preprocessors/registry.d.ts +56 -0
- package/dist/esm/preprocessors/registry.js +179 -0
- package/dist/esm/run-error-recovery-tests.d.ts +7 -0
- package/dist/esm/run-error-recovery-tests.js +101 -0
- package/dist/esm/search-standalone.d.ts +7 -0
- package/dist/esm/search-standalone.js +117 -0
- package/dist/esm/search.d.ts +99 -0
- package/dist/esm/search.js +177 -0
- package/dist/esm/test-utils.d.ts +18 -0
- package/dist/esm/test-utils.js +27 -0
- package/dist/esm/text/chunker.d.ts +33 -0
- package/dist/esm/text/chunker.js +279 -0
- package/dist/esm/text/embedder.d.ts +111 -0
- package/dist/esm/text/embedder.js +386 -0
- package/dist/esm/text/index.d.ts +8 -0
- package/dist/esm/text/index.js +9 -0
- package/dist/esm/text/preprocessors/index.d.ts +17 -0
- package/dist/esm/text/preprocessors/index.js +38 -0
- package/dist/esm/text/preprocessors/mdx.d.ts +25 -0
- package/dist/esm/text/preprocessors/mdx.js +101 -0
- package/dist/esm/text/preprocessors/mermaid.d.ts +68 -0
- package/dist/esm/text/preprocessors/mermaid.js +330 -0
- package/dist/esm/text/preprocessors/registry.d.ts +56 -0
- package/dist/esm/text/preprocessors/registry.js +180 -0
- package/dist/esm/text/reranker.d.ts +49 -0
- package/dist/esm/text/reranker.js +274 -0
- package/dist/esm/text/sentence-transformer-embedder.d.ts +96 -0
- package/dist/esm/text/sentence-transformer-embedder.js +340 -0
- package/dist/esm/text/tokenizer.d.ts +22 -0
- package/dist/esm/text/tokenizer.js +64 -0
- package/dist/esm/types.d.ts +83 -0
- package/dist/esm/types.js +3 -0
- package/dist/esm/utils/vector-math.d.ts +31 -0
- package/dist/esm/utils/vector-math.js +70 -0
- package/package.json +39 -14
- package/dist/core/vector-index.d.ts +0 -72
- package/dist/core/vector-index.js +0 -331
- /package/dist/{api-errors.d.ts → cjs/api-errors.d.ts} +0 -0
- /package/dist/{api-errors.js → cjs/api-errors.js} +0 -0
- /package/dist/{cli → cjs/cli}/indexer.d.ts +0 -0
- /package/dist/{cli → cjs/cli}/search.d.ts +0 -0
- /package/dist/{cli → cjs/cli}/search.js +0 -0
- /package/dist/{cli.d.ts → cjs/cli.d.ts} +0 -0
- /package/dist/{config.d.ts → cjs/config.d.ts} +0 -0
- /package/dist/{config.js → cjs/config.js} +0 -0
- /package/dist/{core → cjs/core}/abstract-embedder.d.ts +0 -0
- /package/dist/{core → cjs/core}/abstract-embedder.js +0 -0
- /package/dist/{core → cjs/core}/actionable-error-messages.d.ts +0 -0
- /package/dist/{core → cjs/core}/actionable-error-messages.js +0 -0
- /package/dist/{core → cjs/core}/adapters.d.ts +0 -0
- /package/dist/{core → cjs/core}/adapters.js +0 -0
- /package/dist/{core → cjs/core}/batch-processing-optimizer.d.ts +0 -0
- /package/dist/{core → cjs/core}/batch-processing-optimizer.js +0 -0
- /package/dist/{core → cjs/core}/binary-index-format.d.ts +0 -0
- /package/dist/{core → cjs/core}/chunker.d.ts +0 -0
- /package/dist/{core → cjs/core}/chunker.js +0 -0
- /package/dist/{core → cjs/core}/cli-database-utils.d.ts +0 -0
- /package/dist/{core → cjs/core}/cli-database-utils.js +0 -0
- /package/dist/{core → cjs/core}/config.d.ts +0 -0
- /package/dist/{core → cjs/core}/config.js +0 -0
- /package/dist/{core → cjs/core}/content-errors.d.ts +0 -0
- /package/dist/{core → cjs/core}/content-errors.js +0 -0
- /package/dist/{core → cjs/core}/content-manager.d.ts +0 -0
- /package/dist/{core → cjs/core}/content-manager.js +0 -0
- /package/dist/{core → cjs/core}/content-performance-optimizer.d.ts +0 -0
- /package/dist/{core → cjs/core}/content-performance-optimizer.js +0 -0
- /package/dist/{core → cjs/core}/content-resolver.d.ts +0 -0
- /package/dist/{core → cjs/core}/content-resolver.js +0 -0
- /package/dist/{core → cjs/core}/cross-modal-search.d.ts +0 -0
- /package/dist/{core → cjs/core}/cross-modal-search.js +0 -0
- /package/dist/{core → cjs/core}/database-connection-manager.d.ts +0 -0
- /package/dist/{core → cjs/core}/database-connection-manager.js +0 -0
- /package/dist/{core → cjs/core}/embedder-factory.d.ts +0 -0
- /package/dist/{core → cjs/core}/embedder-factory.js +0 -0
- /package/dist/{core → cjs/core}/error-handler.d.ts +0 -0
- /package/dist/{core → cjs/core}/error-handler.js +0 -0
- /package/dist/{core → cjs/core}/index.d.ts +0 -0
- /package/dist/{core → cjs/core}/index.js +0 -0
- /package/dist/{core → cjs/core}/ingestion.d.ts +0 -0
- /package/dist/{core → cjs/core}/interfaces.d.ts +0 -0
- /package/dist/{core → cjs/core}/interfaces.js +0 -0
- /package/dist/{core → cjs/core}/lazy-dependency-loader.d.ts +0 -0
- /package/dist/{core → cjs/core}/lazy-dependency-loader.js +0 -0
- /package/dist/{core → cjs/core}/mode-detection-service.d.ts +0 -0
- /package/dist/{core → cjs/core}/mode-detection-service.js +0 -0
- /package/dist/{core → cjs/core}/mode-model-validator.d.ts +0 -0
- /package/dist/{core → cjs/core}/mode-model-validator.js +0 -0
- /package/dist/{core → cjs/core}/model-registry.d.ts +0 -0
- /package/dist/{core → cjs/core}/model-registry.js +0 -0
- /package/dist/{core → cjs/core}/model-validator.d.ts +0 -0
- /package/dist/{core → cjs/core}/path-manager.d.ts +0 -0
- /package/dist/{core → cjs/core}/path-manager.js +0 -0
- /package/dist/{core → cjs/core}/raglite-paths.d.ts +0 -0
- /package/dist/{core → cjs/core}/raglite-paths.js +0 -0
- /package/dist/{core → cjs/core}/reranking-config.d.ts +0 -0
- /package/dist/{core → cjs/core}/reranking-config.js +0 -0
- /package/dist/{core → cjs/core}/reranking-factory.d.ts +0 -0
- /package/dist/{core → cjs/core}/reranking-factory.js +0 -0
- /package/dist/{core → cjs/core}/reranking-strategies.d.ts +0 -0
- /package/dist/{core → cjs/core}/reranking-strategies.js +0 -0
- /package/dist/{core → cjs/core}/resource-cleanup.d.ts +0 -0
- /package/dist/{core → cjs/core}/resource-cleanup.js +0 -0
- /package/dist/{core → cjs/core}/resource-manager.d.ts +0 -0
- /package/dist/{core → cjs/core}/resource-manager.js +0 -0
- /package/dist/{core → cjs/core}/search-pipeline.d.ts +0 -0
- /package/dist/{core → cjs/core}/search.d.ts +0 -0
- /package/dist/{core → cjs/core}/streaming-operations.d.ts +0 -0
- /package/dist/{core → cjs/core}/streaming-operations.js +0 -0
- /package/dist/{core → cjs/core}/types.d.ts +0 -0
- /package/dist/{core → cjs/core}/types.js +0 -0
- /package/dist/{core → cjs/core}/universal-embedder.d.ts +0 -0
- /package/dist/{core → cjs/core}/universal-embedder.js +0 -0
- /package/dist/{core → cjs/core}/validation-messages.d.ts +0 -0
- /package/dist/{core → cjs/core}/validation-messages.js +0 -0
- /package/dist/{dom-polyfills.d.ts → cjs/dom-polyfills.d.ts} +0 -0
- /package/dist/{dom-polyfills.js → cjs/dom-polyfills.js} +0 -0
- /package/dist/{factories → cjs/factories}/index.d.ts +0 -0
- /package/dist/{factories → cjs/factories}/index.js +0 -0
- /package/dist/{factories → cjs/factories}/ingestion-factory.d.ts +0 -0
- /package/dist/{factories → cjs/factories}/search-factory.d.ts +0 -0
- /package/dist/{file-processor.d.ts → cjs/file-processor.d.ts} +0 -0
- /package/dist/{file-processor.js → cjs/file-processor.js} +0 -0
- /package/dist/{indexer.d.ts → cjs/indexer.d.ts} +0 -0
- /package/dist/{indexer.js → cjs/indexer.js} +0 -0
- /package/dist/{ingestion.d.ts → cjs/ingestion.d.ts} +0 -0
- /package/dist/{ingestion.js → cjs/ingestion.js} +0 -0
- /package/dist/{mcp-server.d.ts → cjs/mcp-server.d.ts} +0 -0
- /package/dist/{mcp-server.js → cjs/mcp-server.js} +0 -0
- /package/dist/{multimodal → cjs/multimodal}/clip-embedder.d.ts +0 -0
- /package/dist/{multimodal → cjs/multimodal}/clip-embedder.js +0 -0
- /package/dist/{multimodal → cjs/multimodal}/index.d.ts +0 -0
- /package/dist/{multimodal → cjs/multimodal}/index.js +0 -0
- /package/dist/{preprocess.d.ts → cjs/preprocess.d.ts} +0 -0
- /package/dist/{preprocess.js → cjs/preprocess.js} +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/index.d.ts +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/index.js +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/mdx.d.ts +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/mdx.js +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/mermaid.d.ts +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/mermaid.js +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/registry.d.ts +0 -0
- /package/dist/{preprocessors → cjs/preprocessors}/registry.js +0 -0
- /package/dist/{run-error-recovery-tests.d.ts → cjs/run-error-recovery-tests.d.ts} +0 -0
- /package/dist/{run-error-recovery-tests.js → cjs/run-error-recovery-tests.js} +0 -0
- /package/dist/{search-standalone.d.ts → cjs/search-standalone.d.ts} +0 -0
- /package/dist/{search-standalone.js → cjs/search-standalone.js} +0 -0
- /package/dist/{search.d.ts → cjs/search.d.ts} +0 -0
- /package/dist/{search.js → cjs/search.js} +0 -0
- /package/dist/{test-utils.d.ts → cjs/test-utils.d.ts} +0 -0
- /package/dist/{test-utils.js → cjs/test-utils.js} +0 -0
- /package/dist/{text → cjs/text}/chunker.d.ts +0 -0
- /package/dist/{text → cjs/text}/chunker.js +0 -0
- /package/dist/{text → cjs/text}/embedder.d.ts +0 -0
- /package/dist/{text → cjs/text}/embedder.js +0 -0
- /package/dist/{text → cjs/text}/index.d.ts +0 -0
- /package/dist/{text → cjs/text}/index.js +0 -0
- /package/dist/{text → cjs/text}/preprocessors/index.d.ts +0 -0
- /package/dist/{text → cjs/text}/preprocessors/index.js +0 -0
- /package/dist/{text → cjs/text}/preprocessors/mdx.d.ts +0 -0
- /package/dist/{text → cjs/text}/preprocessors/mdx.js +0 -0
- /package/dist/{text → cjs/text}/preprocessors/mermaid.d.ts +0 -0
- /package/dist/{text → cjs/text}/preprocessors/mermaid.js +0 -0
- /package/dist/{text → cjs/text}/preprocessors/registry.d.ts +0 -0
- /package/dist/{text → cjs/text}/preprocessors/registry.js +0 -0
- /package/dist/{text → cjs/text}/reranker.d.ts +0 -0
- /package/dist/{text → cjs/text}/reranker.js +0 -0
- /package/dist/{text → cjs/text}/sentence-transformer-embedder.d.ts +0 -0
- /package/dist/{text → cjs/text}/sentence-transformer-embedder.js +0 -0
- /package/dist/{text → cjs/text}/tokenizer.d.ts +0 -0
- /package/dist/{text → cjs/text}/tokenizer.js +0 -0
- /package/dist/{types.d.ts → cjs/types.d.ts} +0 -0
- /package/dist/{types.js → cjs/types.js} +0 -0
- /package/dist/{utils → cjs/utils}/vector-math.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/vector-math.js +0 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'fs';
|
|
2
|
+
import { extname } from 'path';
|
|
3
|
+
import { SearchFactory } from '../factories/search-factory.js';
|
|
4
|
+
import { withCLIDatabaseAccess, setupCLICleanup } from '../core/cli-database-utils.js';
|
|
5
|
+
import { config, EXIT_CODES, ConfigurationError } from '../core/config.js';
|
|
6
|
+
/**
|
|
7
|
+
* Detect if query is an image file path
|
|
8
|
+
* @param query - Query string to check
|
|
9
|
+
* @returns True if query is a valid image file path
|
|
10
|
+
*/
|
|
11
|
+
function isImageFile(query) {
|
|
12
|
+
// Check if file exists
|
|
13
|
+
if (!existsSync(query)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
// Check if it's a file (not a directory)
|
|
17
|
+
try {
|
|
18
|
+
const stats = statSync(query);
|
|
19
|
+
if (!stats.isFile()) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
// Check file extension
|
|
27
|
+
const ext = extname(query).toLowerCase();
|
|
28
|
+
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'];
|
|
29
|
+
return imageExtensions.includes(ext);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Run search from CLI
|
|
33
|
+
* @param query - Search query string or image file path
|
|
34
|
+
* @param options - CLI options including top-k and rerank settings
|
|
35
|
+
*/
|
|
36
|
+
export async function runSearch(query, options = {}) {
|
|
37
|
+
try {
|
|
38
|
+
// Search uses the model that was used during ingestion (stored in database)
|
|
39
|
+
const effectiveConfig = config;
|
|
40
|
+
// Validate query
|
|
41
|
+
if (!query || query.trim().length === 0) {
|
|
42
|
+
console.error('Error: Search query cannot be empty');
|
|
43
|
+
console.error('');
|
|
44
|
+
console.error('Usage: raglite search <query>');
|
|
45
|
+
console.error(' raglite search <image-path>');
|
|
46
|
+
console.error('');
|
|
47
|
+
console.error('Examples:');
|
|
48
|
+
console.error(' raglite search "machine learning"');
|
|
49
|
+
console.error(' raglite search "how to install"');
|
|
50
|
+
console.error(' raglite search ./photo.jpg');
|
|
51
|
+
process.exit(EXIT_CODES.INVALID_ARGUMENTS);
|
|
52
|
+
}
|
|
53
|
+
// Detect if query is an image file
|
|
54
|
+
const isImage = isImageFile(query);
|
|
55
|
+
// Validate query length for text queries
|
|
56
|
+
if (!isImage && query.trim().length > 500) {
|
|
57
|
+
console.error('Error: Search query is too long (maximum 500 characters)');
|
|
58
|
+
console.error('');
|
|
59
|
+
console.error('Please use a shorter, more specific query.');
|
|
60
|
+
process.exit(EXIT_CODES.INVALID_ARGUMENTS);
|
|
61
|
+
}
|
|
62
|
+
// Check if database exists
|
|
63
|
+
if (!existsSync(effectiveConfig.db_file)) {
|
|
64
|
+
console.error('Error: No database found. You need to ingest documents first.');
|
|
65
|
+
console.error('');
|
|
66
|
+
console.error('To get started:');
|
|
67
|
+
console.error('1. First ingest your documents: raglite ingest <path>');
|
|
68
|
+
console.error('2. Then search: raglite search "your query"');
|
|
69
|
+
console.error('');
|
|
70
|
+
console.error('Examples:');
|
|
71
|
+
console.error(' raglite ingest ./docs/ # Ingest all .md/.txt files');
|
|
72
|
+
console.error(' raglite search "machine learning" # Search your documents');
|
|
73
|
+
process.exit(EXIT_CODES.FILE_NOT_FOUND);
|
|
74
|
+
}
|
|
75
|
+
// Check if vector index exists
|
|
76
|
+
if (!existsSync(effectiveConfig.index_file)) {
|
|
77
|
+
console.error('Error: No vector index found. The ingestion may not have completed successfully.');
|
|
78
|
+
console.error('');
|
|
79
|
+
console.error('To fix this:');
|
|
80
|
+
console.error('1. Try re-ingesting: raglite ingest <path>');
|
|
81
|
+
console.error('2. Or rebuild the index: raglite rebuild');
|
|
82
|
+
console.error('');
|
|
83
|
+
console.error('If the problem persists, check that your documents were processed correctly.');
|
|
84
|
+
process.exit(EXIT_CODES.INDEX_ERROR);
|
|
85
|
+
}
|
|
86
|
+
// Display search type
|
|
87
|
+
if (isImage) {
|
|
88
|
+
console.log(`Searching with image: "${query}"`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.log(`Searching for: "${query}"`);
|
|
92
|
+
}
|
|
93
|
+
console.log('');
|
|
94
|
+
// Setup graceful cleanup
|
|
95
|
+
setupCLICleanup(effectiveConfig.db_file);
|
|
96
|
+
// Initialize search engine using polymorphic factory with database protection
|
|
97
|
+
let searchEngine;
|
|
98
|
+
let embedder;
|
|
99
|
+
try {
|
|
100
|
+
// Create search engine using SearchFactory (auto-detects mode)
|
|
101
|
+
searchEngine = await withCLIDatabaseAccess(effectiveConfig.db_file, () => SearchFactory.create(effectiveConfig.index_file, effectiveConfig.db_file), {
|
|
102
|
+
commandName: 'Search command',
|
|
103
|
+
showProgress: true
|
|
104
|
+
});
|
|
105
|
+
// For image queries, we need to check if the mode supports images
|
|
106
|
+
if (isImage) {
|
|
107
|
+
// Get system info to check mode
|
|
108
|
+
const { ModeDetectionService } = await import('../core/mode-detection-service.js');
|
|
109
|
+
const modeService = new ModeDetectionService(effectiveConfig.db_file);
|
|
110
|
+
const systemInfo = await modeService.detectMode();
|
|
111
|
+
if (systemInfo.mode !== 'multimodal') {
|
|
112
|
+
console.error('Error: Image search is only supported in multimodal mode');
|
|
113
|
+
console.error('');
|
|
114
|
+
console.error('Your database is configured for text-only mode.');
|
|
115
|
+
console.error('To enable image search:');
|
|
116
|
+
console.error('1. Re-ingest your documents with multimodal mode:');
|
|
117
|
+
console.error(' raglite ingest <path> --mode multimodal');
|
|
118
|
+
console.error('2. Then search with images:');
|
|
119
|
+
console.error(' raglite search ./photo.jpg');
|
|
120
|
+
process.exit(EXIT_CODES.INVALID_ARGUMENTS);
|
|
121
|
+
}
|
|
122
|
+
// Create embedder for image embedding
|
|
123
|
+
const { createEmbedder } = await import('../core/embedder-factory.js');
|
|
124
|
+
embedder = await createEmbedder(systemInfo.modelName);
|
|
125
|
+
// Check if embedder supports images
|
|
126
|
+
const { supportsImages } = await import('../core/universal-embedder.js');
|
|
127
|
+
if (!supportsImages(embedder)) {
|
|
128
|
+
console.error('Error: The current model does not support image embedding');
|
|
129
|
+
console.error('');
|
|
130
|
+
console.error(`Model: ${systemInfo.modelName}`);
|
|
131
|
+
console.error('Image search requires a multimodal model like CLIP.');
|
|
132
|
+
process.exit(EXIT_CODES.MODEL_ERROR);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Prepare search options
|
|
136
|
+
const searchOptions = {};
|
|
137
|
+
if (options['top-k'] !== undefined) {
|
|
138
|
+
searchOptions.top_k = options['top-k'];
|
|
139
|
+
}
|
|
140
|
+
// Set content type filter for search-level filtering
|
|
141
|
+
const contentTypeFilter = options['content-type'];
|
|
142
|
+
if (contentTypeFilter && contentTypeFilter !== 'all') {
|
|
143
|
+
searchOptions.contentType = contentTypeFilter;
|
|
144
|
+
}
|
|
145
|
+
// Phase 2: Disable reranking for image-to-image searches to preserve visual similarity
|
|
146
|
+
let rerankingForciblyDisabled = false;
|
|
147
|
+
if (isImage && embedder) {
|
|
148
|
+
// Force disable reranking for image searches, regardless of user setting
|
|
149
|
+
searchOptions.rerank = false;
|
|
150
|
+
rerankingForciblyDisabled = true;
|
|
151
|
+
// Warn user if they tried to enable reranking for image search
|
|
152
|
+
if (options.rerank === true) {
|
|
153
|
+
console.warn('⚠️ Reranking is disabled for image-to-image search to preserve visual similarity.');
|
|
154
|
+
console.warn(' Image-to-image search uses CLIP embeddings for direct visual matching.');
|
|
155
|
+
console.warn(' For text-to-image search, use: raglite search "description" --rerank');
|
|
156
|
+
console.warn('');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// For text searches, use user setting (defaults to false from Phase 1)
|
|
161
|
+
if (options.rerank !== undefined) {
|
|
162
|
+
searchOptions.rerank = options.rerank;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Track whether reranking will actually be used in this search
|
|
166
|
+
const rerankingUsed = searchOptions.rerank === true;
|
|
167
|
+
// Perform search
|
|
168
|
+
const startTime = Date.now();
|
|
169
|
+
let results;
|
|
170
|
+
if (isImage && embedder) {
|
|
171
|
+
// Image-based search: embed the image and search with the vector
|
|
172
|
+
console.log('Embedding image...');
|
|
173
|
+
const imageEmbedding = await embedder.embedImage(query);
|
|
174
|
+
console.log('Searching with image embedding...');
|
|
175
|
+
results = await searchEngine.searchWithVector(imageEmbedding.vector, searchOptions);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Text-based search
|
|
179
|
+
results = await searchEngine.search(query, searchOptions);
|
|
180
|
+
}
|
|
181
|
+
const searchTime = Date.now() - startTime;
|
|
182
|
+
// Display results
|
|
183
|
+
if (results.length === 0) {
|
|
184
|
+
console.log('No results found.');
|
|
185
|
+
console.log('\nTips:');
|
|
186
|
+
console.log('- Try different keywords or phrases');
|
|
187
|
+
console.log('- Make sure you have ingested relevant documents');
|
|
188
|
+
console.log('- Check if your query matches the content of your documents');
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.log(`Found ${results.length} result${results.length === 1 ? '' : 's'} in ${searchTime}ms:\n`);
|
|
192
|
+
results.forEach((result, index) => {
|
|
193
|
+
// Add content type icon for visual distinction
|
|
194
|
+
const contentTypeIcon = result.contentType === 'image' ? '🖼️ ' : '📄 ';
|
|
195
|
+
const contentTypeLabel = result.contentType === 'image' ? '[IMAGE]' : '[TEXT]';
|
|
196
|
+
console.log(`${index + 1}. ${contentTypeIcon}${result.document.title}`);
|
|
197
|
+
console.log(` Source: ${result.document.source}`);
|
|
198
|
+
console.log(` Type: ${contentTypeLabel}`);
|
|
199
|
+
console.log(` Score: ${(result.score * 100).toFixed(1)}%`);
|
|
200
|
+
// Display content differently based on type
|
|
201
|
+
if (result.contentType === 'image') {
|
|
202
|
+
// For images, show metadata if available
|
|
203
|
+
if (result.metadata?.description) {
|
|
204
|
+
console.log(` Description: ${truncateText(result.metadata.description, 200)}`);
|
|
205
|
+
}
|
|
206
|
+
if (result.metadata?.dimensions) {
|
|
207
|
+
console.log(` Dimensions: ${result.metadata.dimensions}`);
|
|
208
|
+
}
|
|
209
|
+
if (result.metadata?.format) {
|
|
210
|
+
console.log(` Format: ${result.metadata.format}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
// For text, show content preview
|
|
215
|
+
console.log(` Text: ${truncateText(result.content, 200)}`);
|
|
216
|
+
}
|
|
217
|
+
console.log('');
|
|
218
|
+
});
|
|
219
|
+
// Show search statistics
|
|
220
|
+
const stats = await searchEngine.getStats();
|
|
221
|
+
console.log('─'.repeat(50));
|
|
222
|
+
console.log(`Search completed in ${searchTime}ms`);
|
|
223
|
+
console.log(`Searched ${stats.totalChunks} chunks`);
|
|
224
|
+
if (rerankingUsed) {
|
|
225
|
+
console.log('Reranking: enabled');
|
|
226
|
+
}
|
|
227
|
+
else if (rerankingForciblyDisabled) {
|
|
228
|
+
console.log('Reranking: disabled');
|
|
229
|
+
}
|
|
230
|
+
else if (stats.rerankingEnabled) {
|
|
231
|
+
console.log('Reranking: available (not used)');
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
console.log('Reranking: disabled');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
// Cleanup resources
|
|
240
|
+
if (embedder) {
|
|
241
|
+
await embedder.cleanup();
|
|
242
|
+
}
|
|
243
|
+
if (searchEngine) {
|
|
244
|
+
await searchEngine.cleanup();
|
|
245
|
+
}
|
|
246
|
+
// Ensure clean exit for CLI commands
|
|
247
|
+
const { DatabaseConnectionManager } = await import('../core/database-connection-manager.js');
|
|
248
|
+
await DatabaseConnectionManager.closeAllConnections();
|
|
249
|
+
// Force exit for CLI commands to prevent hanging
|
|
250
|
+
setTimeout(() => {
|
|
251
|
+
process.exit(0);
|
|
252
|
+
}, 100);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
console.error('\n' + '='.repeat(50));
|
|
257
|
+
console.error('SEARCH FAILED');
|
|
258
|
+
console.error('='.repeat(50));
|
|
259
|
+
if (error instanceof ConfigurationError) {
|
|
260
|
+
console.error('Configuration Error:');
|
|
261
|
+
console.error(error.message);
|
|
262
|
+
process.exit(error.exitCode);
|
|
263
|
+
}
|
|
264
|
+
else if (error instanceof Error) {
|
|
265
|
+
console.error('Error:', error.message);
|
|
266
|
+
console.error('');
|
|
267
|
+
if (error.message.includes('SQLITE') || error.message.includes('database')) {
|
|
268
|
+
console.error('Database Error:');
|
|
269
|
+
console.error('- The database may be corrupted or inaccessible');
|
|
270
|
+
console.error('- Try rebuilding the index: raglite rebuild');
|
|
271
|
+
console.error('- Ensure the database file is not locked by another process');
|
|
272
|
+
console.error('- Check file permissions and available disk space');
|
|
273
|
+
process.exit(EXIT_CODES.DATABASE_ERROR);
|
|
274
|
+
}
|
|
275
|
+
else if (error.message.includes('model') || error.message.includes('ONNX')) {
|
|
276
|
+
console.error('Model Error:');
|
|
277
|
+
console.error('- The embedding model failed to load');
|
|
278
|
+
console.error('- Try restarting the search command');
|
|
279
|
+
console.error('- Ensure you have internet connection for model download');
|
|
280
|
+
console.error('- Check available disk space in the models directory');
|
|
281
|
+
process.exit(EXIT_CODES.MODEL_ERROR);
|
|
282
|
+
}
|
|
283
|
+
else if (error.message.includes('index') || error.message.includes('vector')) {
|
|
284
|
+
console.error('Vector Index Error:');
|
|
285
|
+
console.error('- The vector index may be corrupted or incompatible');
|
|
286
|
+
console.error('- Try rebuilding the index: raglite rebuild');
|
|
287
|
+
console.error('- Ensure the index file is not corrupted');
|
|
288
|
+
console.error('- Check available disk space');
|
|
289
|
+
process.exit(EXIT_CODES.INDEX_ERROR);
|
|
290
|
+
}
|
|
291
|
+
else if (error.message.includes('not initialized') || error.message.includes('empty')) {
|
|
292
|
+
console.error('No Data Found:');
|
|
293
|
+
console.error('- Make sure you have ingested documents first');
|
|
294
|
+
console.error('- Run: raglite ingest <path>');
|
|
295
|
+
console.error('- Check that your documents contain searchable text');
|
|
296
|
+
console.error('- Verify documents are in supported formats (.md, .txt)');
|
|
297
|
+
process.exit(EXIT_CODES.FILE_NOT_FOUND);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
console.error('General Error:');
|
|
301
|
+
console.error('- An unexpected error occurred during search');
|
|
302
|
+
console.error('- Try running the search again');
|
|
303
|
+
console.error('- If the problem persists, try: raglite rebuild');
|
|
304
|
+
console.error('- Check that your query is valid and not too complex');
|
|
305
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
console.error('Unknown error:', String(error));
|
|
310
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Truncate text to specified length with ellipsis
|
|
316
|
+
* @param text - Text to truncate
|
|
317
|
+
* @param maxLength - Maximum length before truncation
|
|
318
|
+
* @returns Truncated text with ellipsis if needed
|
|
319
|
+
*/
|
|
320
|
+
function truncateText(text, maxLength) {
|
|
321
|
+
if (text.length <= maxLength) {
|
|
322
|
+
return text;
|
|
323
|
+
}
|
|
324
|
+
// Try to break at word boundary
|
|
325
|
+
const truncated = text.substring(0, maxLength);
|
|
326
|
+
const lastSpaceIndex = truncated.lastIndexOf(' ');
|
|
327
|
+
if (lastSpaceIndex > maxLength * 0.8) {
|
|
328
|
+
return truncated.substring(0, lastSpaceIndex) + '...';
|
|
329
|
+
}
|
|
330
|
+
return truncated + '...';
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { fileURLToPath } from 'url';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
/**
|
|
8
|
+
* Get the project root directory
|
|
9
|
+
* When built, CLI is at dist/esm/cli/ui-server.js, so go up 3 levels
|
|
10
|
+
* When running from source, CLI is at src/cli/ui-server.ts, so go up 2 levels
|
|
11
|
+
*/
|
|
12
|
+
function getProjectRoot() {
|
|
13
|
+
// Try going up 3 levels first (for built version)
|
|
14
|
+
const builtPath = join(__dirname, '../../..');
|
|
15
|
+
if (fs.existsSync(join(builtPath, 'package.json'))) {
|
|
16
|
+
return builtPath;
|
|
17
|
+
}
|
|
18
|
+
// Fallback: go up 2 levels (for source execution)
|
|
19
|
+
return join(__dirname, '../..');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Launch the UI server
|
|
23
|
+
*/
|
|
24
|
+
export async function runUI(options = {}) {
|
|
25
|
+
const port = options.port || 3000;
|
|
26
|
+
const backendPort = options.backendPort || 3001;
|
|
27
|
+
console.log('🚀 Launching RAG-lite TS UI...');
|
|
28
|
+
// Resolve UI paths from project root
|
|
29
|
+
const projectRoot = getProjectRoot();
|
|
30
|
+
const backendBuiltPath = join(projectRoot, 'ui', 'backend', 'dist', 'index.js');
|
|
31
|
+
const backendSourcePath = join(projectRoot, 'ui', 'backend', 'src', 'index.ts');
|
|
32
|
+
const frontendBuiltPath = join(projectRoot, 'ui', 'frontend', 'dist');
|
|
33
|
+
const frontendSourcePath = join(projectRoot, 'ui', 'frontend');
|
|
34
|
+
// Check if built files exist
|
|
35
|
+
const useBuiltBackend = fs.existsSync(backendBuiltPath);
|
|
36
|
+
const useBuiltFrontend = fs.existsSync(frontendBuiltPath);
|
|
37
|
+
if (!useBuiltBackend && !fs.existsSync(backendSourcePath)) {
|
|
38
|
+
console.error(`❌ UI backend not found at: ${backendSourcePath}`);
|
|
39
|
+
console.error(' Make sure the UI is set up in the ui/ directory.');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
if (!useBuiltFrontend && !fs.existsSync(frontendSourcePath)) {
|
|
43
|
+
console.error(`❌ UI frontend not found at: ${frontendSourcePath}`);
|
|
44
|
+
console.error(' Make sure the UI is set up in the ui/ directory.');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
// Pass the working directory where 'raglite ui' was called to the backend
|
|
48
|
+
const workingDir = process.cwd();
|
|
49
|
+
// Built mode: single server on port (UI + API). Dev mode: backend on backendPort, frontend on port.
|
|
50
|
+
const effectiveBackendPort = useBuiltFrontend ? port : backendPort;
|
|
51
|
+
console.log(`📡 Starting backend on port ${effectiveBackendPort}...`);
|
|
52
|
+
// Start backend server - use built version if available
|
|
53
|
+
const backendCommand = useBuiltBackend ? 'node' : 'npx';
|
|
54
|
+
const backendArgs = useBuiltBackend
|
|
55
|
+
? [backendBuiltPath]
|
|
56
|
+
: ['tsx', backendSourcePath];
|
|
57
|
+
const backendProcess = spawn(backendCommand, backendArgs, {
|
|
58
|
+
stdio: 'pipe',
|
|
59
|
+
env: {
|
|
60
|
+
...process.env,
|
|
61
|
+
PORT: effectiveBackendPort.toString(),
|
|
62
|
+
RAG_WORKING_DIR: workingDir,
|
|
63
|
+
UI_FRONTEND_DIST: useBuiltFrontend ? frontendBuiltPath : undefined
|
|
64
|
+
},
|
|
65
|
+
shell: true
|
|
66
|
+
});
|
|
67
|
+
backendProcess.on('error', (err) => {
|
|
68
|
+
console.error('❌ Failed to start backend process:', err);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
|
71
|
+
// Forward backend output with prefix
|
|
72
|
+
backendProcess.stdout?.on('data', (data) => {
|
|
73
|
+
process.stdout.write(`[Backend] ${data}`);
|
|
74
|
+
});
|
|
75
|
+
backendProcess.stderr?.on('data', (data) => {
|
|
76
|
+
process.stderr.write(`[Backend] ${data}`);
|
|
77
|
+
});
|
|
78
|
+
// Only start frontend dev server if built version doesn't exist
|
|
79
|
+
let frontendProcess = null;
|
|
80
|
+
if (!useBuiltFrontend) {
|
|
81
|
+
console.log(`🎨 Starting frontend dev server on port ${port}...`);
|
|
82
|
+
frontendProcess = spawn('npm', ['run', 'dev'], {
|
|
83
|
+
cwd: frontendSourcePath,
|
|
84
|
+
stdio: 'pipe',
|
|
85
|
+
env: {
|
|
86
|
+
...process.env,
|
|
87
|
+
VITE_API_URL: `http://localhost:${effectiveBackendPort}`
|
|
88
|
+
},
|
|
89
|
+
shell: true
|
|
90
|
+
});
|
|
91
|
+
frontendProcess.on('error', (err) => {
|
|
92
|
+
console.error('❌ Failed to start frontend process:', err);
|
|
93
|
+
backendProcess.kill();
|
|
94
|
+
process.exit(1);
|
|
95
|
+
});
|
|
96
|
+
// Forward frontend output with prefix
|
|
97
|
+
frontendProcess.stdout?.on('data', (data) => {
|
|
98
|
+
process.stdout.write(`[Frontend] ${data}`);
|
|
99
|
+
});
|
|
100
|
+
frontendProcess.stderr?.on('data', (data) => {
|
|
101
|
+
process.stderr.write(`[Frontend] ${data}`);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log(`🎨 Using built frontend from ${frontendBuiltPath}`);
|
|
106
|
+
console.log(` Frontend will be served by backend on port ${effectiveBackendPort}`);
|
|
107
|
+
}
|
|
108
|
+
// Wait a bit for servers to start
|
|
109
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
110
|
+
console.log(`\n✨ UI Access:`);
|
|
111
|
+
if (useBuiltFrontend) {
|
|
112
|
+
console.log(` Frontend & Backend: http://localhost:${port}`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(` Frontend: http://localhost:${port}`);
|
|
116
|
+
console.log(` Backend: http://localhost:${effectiveBackendPort}`);
|
|
117
|
+
}
|
|
118
|
+
console.log(`\n💡 Press Ctrl+C to stop both servers\n`);
|
|
119
|
+
// Keep the process alive and handle cleanup
|
|
120
|
+
return new Promise((resolve) => {
|
|
121
|
+
const cleanup = () => {
|
|
122
|
+
console.log('\n🛑 Shutting down servers...');
|
|
123
|
+
backendProcess.kill();
|
|
124
|
+
if (frontendProcess) {
|
|
125
|
+
frontendProcess.kill();
|
|
126
|
+
}
|
|
127
|
+
resolve();
|
|
128
|
+
};
|
|
129
|
+
process.on('SIGINT', cleanup);
|
|
130
|
+
process.on('SIGTERM', cleanup);
|
|
131
|
+
// Handle process exits
|
|
132
|
+
backendProcess.on('exit', (code) => {
|
|
133
|
+
if (code !== 0 && code !== null) {
|
|
134
|
+
console.error(`\n❌ Backend process exited with code ${code}`);
|
|
135
|
+
if (frontendProcess) {
|
|
136
|
+
frontendProcess.kill();
|
|
137
|
+
}
|
|
138
|
+
resolve();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
if (frontendProcess) {
|
|
142
|
+
frontendProcess.on('exit', (code) => {
|
|
143
|
+
if (code !== 0 && code !== null) {
|
|
144
|
+
console.error(`\n❌ Frontend process exited with code ${code}`);
|
|
145
|
+
backendProcess.kill();
|
|
146
|
+
resolve();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=ui-server.js.map
|