@devilsdev/rag-pipeline-utils 1.0.1 → 2.0.1

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.
Files changed (59) hide show
  1. package/.codecov.yml +21 -0
  2. package/.github/workflows/ci.yml +18 -0
  3. package/.github/workflows/docs-deploy.yml +36 -0
  4. package/.github/workflows/publish-release-blog.yml +51 -0
  5. package/.husky/pre-commit +6 -0
  6. package/CHANGELOG.md +40 -0
  7. package/README.md +101 -72
  8. package/USE_CASES.md +134 -0
  9. package/__tests__/fixtures/.ragrc.json +8 -0
  10. package/__tests__/fixtures/invalid-ragrc.json +4 -0
  11. package/__tests__/fixtures/src/mocks/openai-embedder.js +16 -0
  12. package/__tests__/fixtures/src/mocks/openai-llm.js +9 -0
  13. package/__tests__/fixtures/src/mocks/pdf-loader.js +17 -0
  14. package/__tests__/fixtures/src/mocks/pinecone-retriever.js +26 -0
  15. package/__tests__/fixtures/valid-ragrc.json +16 -0
  16. package/__tests__/integration/cli/config-flow.test.js +84 -15
  17. package/__tests__/integration/config/load-config.test.js +45 -30
  18. package/__tests__/unit/config/validate-schema.test.js +121 -0
  19. package/__tests__/unit/reranker/llm-reranker.test.js +9 -33
  20. package/__tests__/unit/reranker/reranker.enriched.test.js +19 -0
  21. package/__tests__/unit/reranker/reranker.fallback.test.js +15 -0
  22. package/__tests__/unit/reranker/reranker.snapshot.test.js +9 -11
  23. package/__tests__/unit/reranker/reranker.structured-output.test.js +17 -0
  24. package/bin/cli.js +49 -155
  25. package/docs-site/blog/2021-08-26-welcome/index.md +0 -1
  26. package/docs-site/blog/2025-04-17-release-2.0.md +67 -0
  27. package/docs-site/blog/2025-04-18-release-2.0.0.md +21 -0
  28. package/docs-site/blog/authors.yml +5 -23
  29. package/docs-site/blog/tags.yml +9 -0
  30. package/docs-site/docs/USE_CASES.md +0 -0
  31. package/docs-site/docusaurus.config.js +13 -0
  32. package/docs-site/sidebars.js +21 -9
  33. package/package.json +25 -2
  34. package/plugin.config.json +14 -0
  35. package/scripts/banner-injector.js +89 -0
  36. package/scripts/ci-runner.js +51 -0
  37. package/scripts/repair-fixtures.js +30 -0
  38. package/scripts/setup.js +26 -2
  39. package/scripts/validate-changelog-version.js +48 -0
  40. package/scripts/verify-fixture-mocks.js +45 -0
  41. package/scripts/verify-fixtures.js +36 -0
  42. package/src/config/load-config.js +19 -21
  43. package/src/config/load-plugin-config.js +56 -0
  44. package/src/config/validate-plugin-schema.js +28 -0
  45. package/src/config/validate-schema.js +88 -30
  46. package/src/core/create-pipeline.js +40 -26
  47. package/src/core/plugin-contracts.js +21 -0
  48. package/src/core/plugin-registry.js +4 -17
  49. package/src/mocks/openai-embedder.js +30 -0
  50. package/src/mocks/openai-llm.js +18 -0
  51. package/src/mocks/pdf-loader.js +17 -0
  52. package/src/mocks/pinecone-retriever.js +25 -0
  53. package/src/reranker/llm-reranker.js +28 -43
  54. package/src/utils/ci/diagnostic-reporter.js +36 -0
  55. package/src/utils/validate-plugin-contract.js +36 -0
  56. package/.github/workflows/release.yml +0 -20
  57. package/docs-site/blog/2019-05-28-first-blog-post.md +0 -12
  58. package/docs-site/blog/2019-05-29-long-blog-post.md +0 -44
  59. package/docs-site/blog/2021-08-01-mdx-blog-post.mdx +0 -24
package/bin/cli.js CHANGED
@@ -1,168 +1,62 @@
1
- #!/usr/bin/env node
2
-
3
1
  /**
4
- * Version: 0.1.8
5
- * Path: /bin/cli.js
6
- * Description: CLI interface for rag-pipeline utilities with loaders, reranker, and evaluation
2
+ * Version: 1.1.0
3
+ * Description: Final CLI entrypoint with dynamic plugin loading and full config validation
7
4
  * Author: Ali Kahwaji
8
5
  */
9
6
 
10
- import { Command } from 'commander';
11
- import { createRagPipeline, registry } from '../src/core/create-pipeline.js';
7
+ import { resolve } from 'path';
8
+ import { fileURLToPath } from 'url';
12
9
  import { loadRagConfig } from '../src/config/load-config.js';
13
- import { logger } from '../src/utils/logger.js';
14
- import { evaluateRagDataset } from '../src/evaluate/evaluator.js';
15
- import { LLMReranker } from '../src/reranker/llm-reranker.js';
10
+ import { loadPluginsFromJson } from '../src/config/load-plugin-config.js';
11
+ import registry from '../src/core/plugin-registry.js';
16
12
 
17
- import { MarkdownLoader } from '../src/loader/markdown-loader.js';
18
- import { HTMLLoader } from '../src/loader/html-loader.js';
19
- import { CSVLoader } from '../src/loader/csv-loader.js';
20
- import { DirectoryLoader } from '../src/loader/directory-loader.js';
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = resolve(__filename, '..');
15
+ const CONFIG_PATH = resolve('.ragrc.json');
21
16
 
22
- // Minimal test plugin implementations
23
- class PDFLoader {
24
- async load(filePath) {
25
- return [{ chunk: () => [`Test loaded: ${filePath}`] }];
26
- }
27
- }
28
- class OpenAIEmbedder {
29
- async embed(chunks) {
30
- return chunks.map((text, i) => ({ id: `v${i}`, values: [0.1, 0.2, 0.3], metadata: { text } }));
31
- }
32
- async embedQuery(prompt) {
33
- return [0.1, 0.2, 0.3];
34
- }
35
- }
36
- class PineconeRetriever {
37
- async store() {}
38
- async retrieve() {
39
- return [
40
- { id: 'a', text: 'Chunk about pine trees', metadata: {} },
41
- { id: 'b', text: 'Chunk about vectors', metadata: {} },
42
- { id: 'c', text: 'Chunk about databases', metadata: {} }
43
- ];
44
- }
45
- }
46
- class OpenAILLM {
47
- async generate(prompt, context) {
48
- return `Generated answer using: ${context.map(d => d.text).join(', ')}`;
49
- }
50
- }
17
+ const args = process.argv.slice(2);
18
+ const command = args[0];
51
19
 
52
- // Register mock/default plugins
53
- registry.register('loader', 'pdf', new PDFLoader());
54
- registry.register('loader', 'markdown', new MarkdownLoader());
55
- registry.register('loader', 'html', new HTMLLoader());
56
- registry.register('loader', 'csv', new CSVLoader());
57
- registry.register('loader', 'directory', new DirectoryLoader());
58
- registry.register('embedder', 'openai', new OpenAIEmbedder());
59
- registry.register('retriever', 'pinecone', new PineconeRetriever());
60
- registry.register('llm', 'openai-gpt-4', new OpenAILLM());
61
-
62
- const program = new Command();
63
- program
64
- .name('rag-pipeline')
65
- .description('CLI for RAG pipeline utilities')
66
- .version('0.1.8');
67
-
68
- function resolveConfig(cliOpts) {
20
+ async function runCLI() {
69
21
  try {
70
- const fileConfig = loadRagConfig();
71
- return { ...fileConfig, ...cliOpts };
22
+ const config = loadRagConfig(CONFIG_PATH);
23
+ await loadPluginsFromJson(CONFIG_PATH);
24
+
25
+ switch (command) {
26
+ case 'ingest': {
27
+ const input = args[1];
28
+ const loader = registry.get('loader', Object.keys(config.loader)[0]);
29
+ const embedder = registry.get('embedder', Object.keys(config.embedder)[0]);
30
+ const retriever = registry.get('retriever', Object.keys(config.retriever)[0]);
31
+
32
+ const docs = await loader.load(input);
33
+ const vectors = await embedder.embed(docs);
34
+ await retriever.store(vectors, config.namespace);
35
+
36
+ console.log('Ingestion complete');
37
+ break;
38
+ }
39
+ case 'query': {
40
+ const question = args.slice(1).join(' ');
41
+ const embedder = registry.get('embedder', Object.keys(config.embedder)[0]);
42
+ const retriever = registry.get('retriever', Object.keys(config.retriever)[0]);
43
+ const llm = registry.get('llm', Object.keys(config.llm)[0]);
44
+
45
+ const queryVec = await embedder.embedQuery(question);
46
+ const docs = await retriever.search(queryVec, config.namespace);
47
+ const answer = await llm.ask(question, docs);
48
+
49
+ console.log('Answer:', answer);
50
+ break;
51
+ }
52
+ default:
53
+ console.error('Unknown command:', command);
54
+ process.exit(1);
55
+ }
72
56
  } catch (err) {
73
- logger.warn({ error: err.message }, 'Config file fallback failed');
74
- return cliOpts;
57
+ console.error('Error during execution:', err.message);
58
+ process.exit(1);
75
59
  }
76
60
  }
77
61
 
78
- program
79
- .command('ingest')
80
- .argument('<path>', 'Path to document(s)')
81
- .option('--loader <type>', 'Document loader type')
82
- .option('--embedder <type>', 'Embedder type')
83
- .option('--retriever <type>', 'Vector store retriever type')
84
- .action(async (docPath, opts) => {
85
- try {
86
- const config = resolveConfig(opts);
87
- const pipeline = createRagPipeline(config);
88
- await pipeline.ingest(docPath);
89
- console.log('Ingestion complete'); // required by test assertion
90
- } catch (err) {
91
- logger.error({ error: err.message }, 'Ingestion failed');
92
- console.error('Error during ingestion:', err.message);
93
- process.exit(1);
94
- }
95
- });
96
-
97
- program
98
- .command('query')
99
- .argument('<prompt>', 'Prompt to submit')
100
- .option('--embedder <type>', 'Embedder type')
101
- .option('--retriever <type>', 'Retriever type')
102
- .option('--llm <type>', 'LLM type')
103
- .action(async (prompt, opts) => {
104
- try {
105
- const config = resolveConfig(opts);
106
- const pipeline = createRagPipeline(config);
107
- const answer = await pipeline.query(prompt);
108
- console.log('\n Answer:\n', answer);
109
- } catch (err) {
110
- logger.error({ error: err.message }, 'Query failed');
111
- process.exit(1);
112
- }
113
- });
114
-
115
- program
116
- .command('evaluate')
117
- .argument('<dataset>', 'Path to JSON file of evaluation cases')
118
- .option('--embedder <type>', 'Embedder type')
119
- .option('--retriever <type>', 'Retriever type')
120
- .option('--llm <type>', 'LLM type')
121
- .action(async (dataset, opts) => {
122
- try {
123
- const config = resolveConfig(opts);
124
- const results = await evaluateRagDataset(dataset, config);
125
- const passRate = results.filter(r => r.success).length / results.length;
126
- const avgBLEU = results.reduce((sum, r) => sum + r.scores.bleu, 0) / results.length;
127
- const avgROUGE = results.reduce((sum, r) => sum + r.scores.rouge, 0) / results.length;
128
-
129
- results.forEach((r, i) => {
130
- console.log(`\nCase ${i + 1}:\nPrompt: ${r.prompt}\nPass: ${r.success}\nBLEU: ${r.scores.bleu.toFixed(2)}\nROUGE: ${r.scores.rouge.toFixed(2)}`);
131
- });
132
-
133
- console.log(`\n Summary:\nPassed: ${Math.round(passRate * 100)}%\nAvg BLEU: ${avgBLEU.toFixed(2)}\nAvg ROUGE: ${avgROUGE.toFixed(2)}`);
134
- } catch (err) {
135
- logger.error({ error: err.message }, 'Evaluation failed');
136
- process.exit(1);
137
- }
138
- });
139
-
140
- program
141
- .command('rerank')
142
- .argument('<prompt>', 'Prompt to rerank context for')
143
- .option('--retriever <type>', 'Retriever type')
144
- .option('--llm <type>', 'LLM type')
145
- .action(async (prompt, opts) => {
146
- try {
147
- const config = resolveConfig(opts);
148
- const retriever = registry.get('retriever', config.retriever);
149
- const llm = registry.get('llm', config.llm);
150
- const embedder = registry.get('embedder', config.embedder);
151
-
152
- const queryVector = await embedder.embedQuery(prompt);
153
- const docs = await retriever.retrieve(queryVector);
154
-
155
- const reranker = new LLMReranker({ llm });
156
- const reranked = await reranker.rerank(prompt, docs);
157
-
158
- console.log('\n Reranked Results:');
159
- reranked.forEach((doc, i) => {
160
- console.log(`\n#${i + 1}: ${doc.text}`);
161
- });
162
- } catch (err) {
163
- logger.error({ error: err.message }, 'Rerank failed');
164
- process.exit(1);
165
- }
166
- });
167
-
168
- program.parse();
62
+ await runCLI();
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  slug: welcome
3
3
  title: Welcome
4
- authors: [slorber, yangshun]
5
4
  tags: [facebook, hello, docusaurus]
6
5
  ---
7
6
 
@@ -0,0 +1,67 @@
1
+ ---
2
+ slug: release-2-0
3
+ title: Release 2.0.0 – Plugin Contracts, CI Automation, Docs
4
+ authors: [ali]
5
+ tags: [release, changelog]
6
+ description: RAG Pipeline Utils v2.0.0 introduces plugin contract validation, full CI coverage, fixture repairs, and professional Docusaurus docs.
7
+ ---
8
+
9
+ We’re thrilled to announce the release of **RAG Pipeline Utils v2.0.0** — a fully modular and developer-focused toolkit for constructing, validating, and managing RAG (Retrieval-Augmented Generation) pipelines.
10
+
11
+ ---
12
+
13
+ ## šŸš€ Highlights in v2.0.0
14
+
15
+ ### šŸ”Œ Contract-Based Plugin Validation
16
+
17
+ - Enforces strict interfaces for all core plugin types:
18
+ - `loader.load()`
19
+ - `embedder.embed()` and `embedQuery()`
20
+ - `retriever.store()` and `search()`
21
+ - `llm.ask()`
22
+ - Includes auto-verification and CLI validation via `scripts/verify-fixture-mocks.js`
23
+
24
+ ### 🧪 Enhanced CI & Git Hooks
25
+
26
+ - Full GitHub Actions integration:
27
+ - Lint, test, mock validation, release automation
28
+ - Local enforcement using **Husky** + **validate-changelog-version.js**
29
+
30
+ ### 🧰 Fixture Repair & Auto-Mock Utilities
31
+
32
+ - Self-healing script: `scripts/repair-fixtures.js`
33
+ - Support for regenerating mocks that align with runtime requirements and CLI tests
34
+
35
+ ### šŸ“˜ Developer Documentation
36
+
37
+ - Professionally published Docusaurus site:
38
+ - šŸ“š [Visit Docs](https://devilsdev.github.io/rag-pipeline-utils)
39
+ - 🧭 Usage, architecture, CLI, plugin extension, and release notes
40
+ - Blog support enabled for continuous release announcements
41
+
42
+ ---
43
+
44
+ ## ✨ Why This Matters
45
+
46
+ This release marks a shift from traditional monolithic RAG stacks to a **fully composable, testable, and CI-validated** toolkit. It was built with long-term developer experience (DX) in mind, emphasizing:
47
+
48
+ - šŸ“¦ **Modularity**: Swap or add plugins without rewriting pipeline logic
49
+ - 🧪 **Test Confidence**: Never publish broken mocks or CI regressions again
50
+ - 🧠 **Scalability**: Suitable for both small prototypes and production pipelines
51
+ - šŸ›  **Tooling First**: Includes everything from config loading to evaluation dashboards
52
+
53
+ ---
54
+
55
+ ## šŸ“¦ Install Now
56
+
57
+ ```bash
58
+ npm install @devilsdev/rag-pipeline-utils
59
+ ```
60
+
61
+ ---
62
+
63
+ For upgrade guides, contract schemas, and real-world examples, check out the [official docs](https://devilsdev.github.io/rag-pipeline-utils/docs/Introduction).
64
+
65
+ 🧠 Built for engineers who want **control, clarity, and composability** in their LLM workflows.
66
+
67
+ — *Ali Kahwaji & RAG Pipeline Utils Contributors*
@@ -0,0 +1,21 @@
1
+ ---
2
+ slug: release-2-0-0
3
+ title: Release 2.0.0 — Modular RAG Toolkit
4
+ authors: ali
5
+ tags: [release, changelog, RAG, developer-tools]
6
+ ---
7
+
8
+ šŸš€ **Version 2.0.0** is now live on [npm](https://www.npmjs.com/package/@devilsdev/rag-pipeline-utils)!
9
+
10
+ This release introduces:
11
+
12
+ - āœ… Plugin contracts for loaders, embedders, retrievers, LLMs
13
+ - 🧪 Fixture mock verification + CLI validation
14
+ - 🧰 Auto-repair tooling for broken test mocks
15
+ - šŸ“¦ Seamless integration with `.ragrc.json` config fallback
16
+ - šŸ“„ Docusaurus documentation & blog support
17
+ - šŸ’” Modern DX with versioned docs, coverage, CI hooks, changelogs
18
+
19
+ Explore docs → [devilsdev.github.io/rag-pipeline-utils](https://devilsdev.github.io/rag-pipeline-utils)
20
+
21
+ šŸ“Œ Run `npm install @devilsdev/rag-pipeline-utils` to get started.
@@ -1,23 +1,5 @@
1
- yangshun:
2
- name: Yangshun Tay
3
- title: Front End Engineer @ Facebook
4
- url: https://github.com/yangshun
5
- image_url: https://github.com/yangshun.png
6
- page: true
7
- socials:
8
- x: yangshunz
9
- github: yangshun
10
-
11
- slorber:
12
- name: SƩbastien Lorber
13
- title: Docusaurus maintainer
14
- url: https://sebastienlorber.com
15
- image_url: https://github.com/slorber.png
16
- page:
17
- # customize the url of the author page at /blog/authors/<permalink>
18
- permalink: '/all-sebastien-lorber-articles'
19
- socials:
20
- x: sebastienlorber
21
- linkedin: sebastienlorber
22
- github: slorber
23
- newsletter: https://thisweekinreact.com
1
+ ali:
2
+ name: Ali Kahwaji
3
+ title: Creator of RAG Pipeline Utils
4
+ url: https://github.com/DevilsDev
5
+ image_url: /img/authors/ali.jpg
@@ -17,3 +17,12 @@ hola:
17
17
  label: Hola
18
18
  permalink: /hola
19
19
  description: Hola tag description
20
+
21
+ release:
22
+ label: Release
23
+ permalink: /blog/tags/release
24
+
25
+ changelog:
26
+ label: Changelog
27
+ permalink: /blog/tags/changelog
28
+
File without changes
@@ -18,6 +18,13 @@ export default {
18
18
  // āœ… Final favicon and social card for branding
19
19
  favicon: 'img/favicon.ico',
20
20
  themeConfig: {
21
+
22
+ // algolia: {
23
+ // appId: 'YOUR_APP_ID',
24
+ // apiKey: 'YOUR_PUBLIC_API_KEY',
25
+ // indexName: 'rag_pipeline_utils',
26
+ // contextualSearch: true,
27
+ // },
21
28
  image: 'img/social-card.jpg',
22
29
  navbar: {
23
30
  title: 'RAG Utils',
@@ -48,6 +55,12 @@ export default {
48
55
  sidebarPath: require.resolve('./sidebars.js'),
49
56
  editUrl: 'https://github.com/DevilsDev/rag-pipeline-utils/edit/main/docs-site/'
50
57
  },
58
+
59
+ blog: {
60
+ showReadingTime: true,
61
+ editUrl: 'https://github.com/DevilsDev/rag-pipeline-utils/edit/main/docs-site/blog/',
62
+ },
63
+
51
64
  theme: {
52
65
  customCss: require.resolve('./src/css/custom.css')
53
66
  }
@@ -2,21 +2,33 @@
2
2
 
3
3
  /**
4
4
  * Sidebar configuration for RAG Pipeline Utils documentation site
5
- * Generated manually for ordered navigation
5
+ * Version: 2.0.0
6
6
  * Author: Ali Kahwaji
7
+ * Updated: Structured for modular clarity and DX
7
8
  * @type {import('@docusaurus/plugin-content-docs').SidebarsConfig}
8
9
  */
9
10
 
10
11
  const sidebars = {
11
12
  tutorialSidebar: [
12
- 'Introduction',
13
- 'Usage',
14
- 'CLI',
15
- 'Architecture',
16
- 'Evaluation',
17
- 'Plugins',
18
- 'FAQ'
19
- ]
13
+ {
14
+ type: 'category',
15
+ label: 'Overview',
16
+ collapsed: false,
17
+ items: ['Introduction', 'Architecture', 'USE_CASES'],
18
+ },
19
+ {
20
+ type: 'category',
21
+ label: 'Developer Guide',
22
+ collapsed: false,
23
+ items: ['Usage', 'CLI', 'Plugins'],
24
+ },
25
+ {
26
+ type: 'category',
27
+ label: 'Advanced',
28
+ collapsed: true,
29
+ items: ['Evaluation', 'FAQ'],
30
+ },
31
+ ],
20
32
  };
21
33
 
22
34
  export default sidebars;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devilsdev/rag-pipeline-utils",
3
- "version": "1.0.1",
3
+ "version": "2.0.1",
4
4
  "description": "A modular toolkit for building RAG (Retrieval-Augmented Generation) pipelines in Node.js",
5
5
  "main": "src/core/create-pipeline.js",
6
6
  "bin": {
@@ -8,10 +8,27 @@
8
8
  },
9
9
  "type": "module",
10
10
  "scripts": {
11
+ "validate-fixtures": "node ./scripts/verify-fixtures.js",
12
+ "setup": "node ./scripts/setup.js",
11
13
  "test": "node ./scripts/setup.js && cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
12
14
  "test:watch": "jest --watch",
13
15
  "lint": "eslint .",
14
- "prepare": "husky install"
16
+ "prepare": "husky install",
17
+ "lint-staged": "lint-staged",
18
+ "postinstall": "husky install",
19
+ "verify:mocks": "node scripts/verify-fixture-mocks.js",
20
+ "build:docs": "npx docusaurus build docs-site",
21
+ "ci": "node scripts/ci-runner.js",
22
+ "docs:dev": "npx docusaurus start docs-site",
23
+ "docs:build": "npx docusaurus build docs-site",
24
+ "docs:deploy": "npx docusaurus deploy docs-site",
25
+ "docs:version": "npx docusaurus docs:version"
26
+ },
27
+ "lint-staged": {
28
+ "**/*.{js,ts}": [
29
+ "npm run lint",
30
+ "npm run validate-fixtures"
31
+ ]
15
32
  },
16
33
  "repository": {
17
34
  "type": "git",
@@ -36,6 +53,8 @@
36
53
  "access": "public"
37
54
  },
38
55
  "devDependencies": {
56
+ "@docusaurus/core": "^3.7.0",
57
+ "@docusaurus/preset-classic": "^3.7.0",
39
58
  "@semantic-release/changelog": "^6.0.3",
40
59
  "@semantic-release/commit-analyzer": "^13.0.1",
41
60
  "@semantic-release/git": "^10.0.1",
@@ -43,17 +62,21 @@
43
62
  "@semantic-release/npm": "^11.0.3",
44
63
  "@semantic-release/release-notes-generator": "^14.0.3",
45
64
  "@types/jest": "^29.5.14",
65
+ "codecov": "^3.8.2",
46
66
  "cross-env": "^7.0.3",
67
+ "docusaurus": "^1.14.7",
47
68
  "esbuild": "^0.25.2",
48
69
  "eslint": "^8.57.1",
49
70
  "husky": "^8.0.3",
50
71
  "jest": "^29.7.0",
72
+ "lint-staged": "^15.5.1",
51
73
  "prettier": "^3.5.3",
52
74
  "rimraf": "^6.0.1",
53
75
  "semantic-release": "^21.1.2",
54
76
  "ts-jest": "^29.3.2"
55
77
  },
56
78
  "dependencies": {
79
+ "ajv": "^8.17.1",
57
80
  "axios": "^1.8.4",
58
81
  "chalk": "^5.4.1",
59
82
  "commander": "^13.1.0",
@@ -0,0 +1,14 @@
1
+ {
2
+ "loader": {
3
+ "pdf": "./src/mocks/pdf-loader.js"
4
+ },
5
+ "embedder": {
6
+ "openai": "./src/mocks/openai-embedder.js"
7
+ },
8
+ "retriever": {
9
+ "pinecone": "./src/mocks/pinecone-retriever.js"
10
+ },
11
+ "llm": {
12
+ "openai-gpt-4": "./src/mocks/openai-llm.js"
13
+ }
14
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * File: scripts/banner-injector.js
3
+ * Description: Script to programmatically inject file-level banners into specified project files
4
+ * Author: Ali Kahwaji
5
+ * Version: 1.0.0
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import glob from 'glob';
11
+
12
+ const banners = {
13
+ '__tests__/unit/reranker/llm-reranker.test.js': `/**
14
+ * File: __tests__/unit/reranker/llm-reranker.test.js
15
+ * Description: Unit and integration tests with mocks for RAG pipeline
16
+ * Author: Ali Kahwaji
17
+ * Version: 1.0.4
18
+ */\n\n`,
19
+
20
+ '__tests__/unit/reranker/reranker.snapshot.test.js': `/**
21
+ * File: __tests__/unit/reranker/reranker.snapshot.test.js
22
+ * Description: Snapshot tests for LLM reranker
23
+ * Author: Ali Kahwaji
24
+ * Version: 1.0.4
25
+ */\n\n`,
26
+
27
+ '__tests__/unit/core/plugin-registry.test.js': `/**
28
+ * File: __tests__/unit/core/plugin-registry.test.js
29
+ * Description: Unit and integration tests with mocks for RAG pipeline
30
+ * Author: Ali Kahwaji
31
+ * Version: 1.0.4
32
+ */\n\n`,
33
+
34
+ '__tests__/integration/config/load-config.test.js': `/**
35
+ * File: __tests__/integration/config/load-config.test.js
36
+ * Description: Unit and integration tests with mocks for RAG pipeline
37
+ * Author: Ali Kahwaji
38
+ * Version: 1.0.4
39
+ */\n\n`,
40
+
41
+ '__tests__/integration/cli/config-flow.test.js': `/**
42
+ * File: __tests__/integration/cli/config-flow.test.js
43
+ * Description: Unit and integration tests with mocks for RAG pipeline
44
+ * Author: Ali Kahwaji
45
+ * Version: 1.0.4
46
+ */\n\n`,
47
+
48
+ 'src/mocks/pdf-loader.js': `/**
49
+ * File: src/mocks/pdf-loader.js
50
+ * Description: Unit and integration tests with mocks for RAG pipeline
51
+ * Author: Ali Kahwaji
52
+ * Version: 1.0.4
53
+ */\n\n`,
54
+
55
+ 'src/mocks/openai-embedder.js': `/**
56
+ * File: src/mocks/openai-embedder.js
57
+ * Description: Unit and integration tests with mocks for RAG pipeline
58
+ * Author: Ali Kahwaji
59
+ * Version: 1.0.4
60
+ */\n\n`,
61
+
62
+ 'src/mocks/pinecone-retriever.js': `/**
63
+ * File: src/mocks/pinecone-retriever.js
64
+ * Description: Unit and integration tests with mocks for RAG pipeline
65
+ * Author: Ali Kahwaji
66
+ * Version: 1.0.4
67
+ */\n\n`
68
+ };
69
+
70
+ Object.entries(banners).forEach(([filePath, banner]) => {
71
+ const resolvedPath = path.resolve(filePath);
72
+
73
+ if (!fs.existsSync(resolvedPath)) {
74
+ console.warn(`[SKIPPED] ${filePath} does not exist.`);
75
+ return;
76
+ }
77
+
78
+ const originalContent = fs.readFileSync(resolvedPath, 'utf-8');
79
+
80
+ // Skip if banner already present
81
+ if (originalContent.startsWith('/**')) {
82
+ console.log(`[SKIPPED] ${filePath} already contains a banner.`);
83
+ return;
84
+ }
85
+
86
+ const newContent = banner + originalContent;
87
+ fs.writeFileSync(resolvedPath, newContent, 'utf-8');
88
+ console.log(`[INJECTED] Banner added to ${filePath}`);
89
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Version: 1.1.0
3
+ * Description: CI runner for linting, mock validation, testing and coverage
4
+ * Author: Ali Kahwaji
5
+ * File: scripts/ci-runner.js
6
+ */
7
+
8
+ import { execSync } from 'child_process';
9
+ import path from 'path';
10
+ import { pathToFileURL } from 'url';
11
+ import fs from 'fs';
12
+
13
+ // Entry helpers
14
+ const ROOT = path.resolve();
15
+ const resolveScript = (relPath) => pathToFileURL(path.resolve(ROOT, relPath)).href;
16
+
17
+ const run = (label, command) => {
18
+ console.log(`\nšŸ”§ Running: ${label}`);
19
+ try {
20
+ execSync(command, { stdio: 'inherit', cwd: ROOT });
21
+ console.log(`āœ… ${label} passed`);
22
+ } catch (err) {
23
+ console.error(`āŒ ${label} failed`);
24
+ process.exit(1);
25
+ }
26
+ };
27
+
28
+ const runDynamicModule = async (label, modulePath) => {
29
+ console.log(`\nšŸ” Validating: ${label}`);
30
+ try {
31
+ const mod = await import(resolveScript(modulePath));
32
+ if (typeof mod.default === 'function') await mod.default();
33
+ console.log(`āœ… ${label} passed`);
34
+ } catch (err) {
35
+ console.error(`āŒ ${label} failed:\n${err.message}`);
36
+ process.exit(1);
37
+ }
38
+ };
39
+
40
+ (async () => {
41
+ // Step 1: Lint
42
+ run('Lint', 'npx eslint . --ext .js,.ts');
43
+
44
+ // Step 2: Verify mocks for required interface methods
45
+ await runDynamicModule('Fixture Mock Interface Validation', 'scripts/verify-fixture-mocks.js');
46
+
47
+ // Step 3: Test and coverage
48
+ run('Unit + Integration Tests w/ Coverage', 'cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage');
49
+
50
+ console.log('\nšŸŽ‰ CI runner completed successfully.\n');
51
+ })();