ragpipe 0.0.1 → 0.1.0-alpha.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.
- package/README.md +109 -0
- package/dist/cli.js +372 -0
- package/package.json +8 -3
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# ragpipe
|
|
2
|
+
|
|
3
|
+
Pluggable TypeScript RAG toolkit — `defineConfig()` one file, embed → search → generate.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add ragpipe
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### CLI
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Scaffold a ragpipe.config.ts
|
|
17
|
+
npx ragpipe init
|
|
18
|
+
|
|
19
|
+
# Ingest documents
|
|
20
|
+
npx ragpipe ingest ./docs
|
|
21
|
+
|
|
22
|
+
# Ask a question
|
|
23
|
+
npx ragpipe ask "What is the refund policy?"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Programmatic
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { loadConfig, createPipeline } from "ragpipe";
|
|
30
|
+
|
|
31
|
+
const config = await loadConfig();
|
|
32
|
+
const rag = createPipeline(config);
|
|
33
|
+
|
|
34
|
+
await rag.ingest(markdownText, "docs/guide.md");
|
|
35
|
+
|
|
36
|
+
const result = await rag.ask("How does authentication work?");
|
|
37
|
+
console.log(result.answer);
|
|
38
|
+
console.log(result.sources.map((s) => s.source));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
|
|
43
|
+
Create a `ragpipe.config.ts` at your project root:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { defineConfig } from "ragpipe";
|
|
47
|
+
import { geminiEmbedding, geminiGeneration } from "@ragpipe/plugin-gemini";
|
|
48
|
+
import { supabaseVectorStore } from "@ragpipe/plugin-supabase";
|
|
49
|
+
|
|
50
|
+
export default defineConfig({
|
|
51
|
+
embedding: geminiEmbedding({
|
|
52
|
+
apiKey: process.env.GEMINI_API_KEY ?? "",
|
|
53
|
+
}),
|
|
54
|
+
vectorStore: supabaseVectorStore({
|
|
55
|
+
databaseUrl: process.env.DATABASE_URL ?? "",
|
|
56
|
+
}),
|
|
57
|
+
generation: geminiGeneration({
|
|
58
|
+
apiKey: process.env.GEMINI_API_KEY ?? "",
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
### `defineConfig(config)`
|
|
66
|
+
|
|
67
|
+
Identity helper that provides type-safe autocompletion for your config file.
|
|
68
|
+
|
|
69
|
+
### `loadConfig(overrides?)`
|
|
70
|
+
|
|
71
|
+
Loads `ragpipe.config.ts` from the project root using [c12](https://github.com/unjs/c12). Validates that `embedding`, `vectorStore`, and `generation` plugins are present.
|
|
72
|
+
|
|
73
|
+
### `createPipeline(config)`
|
|
74
|
+
|
|
75
|
+
Returns a pipeline with three methods:
|
|
76
|
+
|
|
77
|
+
| Method | Description |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `ingest(text, source)` | Chunk text, embed each chunk, and store vectors. Returns chunk count. |
|
|
80
|
+
| `search(query, topK?)` | Embed the query and return the top-K matching documents. |
|
|
81
|
+
| `ask(query, topK?)` | Search for context, then generate an answer. Returns `{ answer, sources }`. |
|
|
82
|
+
|
|
83
|
+
### `defaultChunker(options?)`
|
|
84
|
+
|
|
85
|
+
Built-in paragraph-based chunker. Options: `chunkSize` (default 500), `overlap` (default 50).
|
|
86
|
+
|
|
87
|
+
### `createRateLimitedEmbedder(plugin)`
|
|
88
|
+
|
|
89
|
+
Wraps an `EmbeddingPlugin` with throttling based on its `rateLimit.delayMs`.
|
|
90
|
+
|
|
91
|
+
## Plugin Interfaces
|
|
92
|
+
|
|
93
|
+
Implement any of these to create a custom plugin:
|
|
94
|
+
|
|
95
|
+
- **`EmbeddingPlugin`** — `embed(text)`, optional `embedMany(texts)`, `rateLimit`
|
|
96
|
+
- **`VectorStorePlugin`** — `search(vector, topK)`, `upsert(source, content, vector)`, optional `clear()`, `disconnect()`
|
|
97
|
+
- **`GenerationPlugin`** — `generate(question, context, options?)`, optional `generateStream()`
|
|
98
|
+
- **`ChunkerPlugin`** — `chunk(text, source)`
|
|
99
|
+
|
|
100
|
+
## Official Plugins
|
|
101
|
+
|
|
102
|
+
| Package | Description |
|
|
103
|
+
|---|---|
|
|
104
|
+
| [`@ragpipe/plugin-gemini`](https://www.npmjs.com/package/@ragpipe/plugin-gemini) | Google Gemini embedding + generation |
|
|
105
|
+
| [`@ragpipe/plugin-supabase`](https://www.npmjs.com/package/@ragpipe/plugin-supabase) | Supabase pgvector store |
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { defineCommand as defineCommand4, runMain } from "citty";
|
|
5
|
+
|
|
6
|
+
// src/cli/ask.ts
|
|
7
|
+
import { defineCommand } from "citty";
|
|
8
|
+
import consola from "consola";
|
|
9
|
+
|
|
10
|
+
// src/config.ts
|
|
11
|
+
import { loadConfig as c12LoadConfig } from "c12";
|
|
12
|
+
async function loadConfig(overrides) {
|
|
13
|
+
const { config } = await c12LoadConfig({
|
|
14
|
+
name: "ragpipe",
|
|
15
|
+
defaults: overrides
|
|
16
|
+
});
|
|
17
|
+
if (!config) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"No ragpipe config found. Create a ragpipe.config.ts or pass config directly."
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
const cfg = config;
|
|
23
|
+
if (!cfg.embedding) {
|
|
24
|
+
throw new Error("ragpipe config is missing 'embedding' plugin.");
|
|
25
|
+
}
|
|
26
|
+
if (!cfg.vectorStore) {
|
|
27
|
+
throw new Error("ragpipe config is missing 'vectorStore' plugin.");
|
|
28
|
+
}
|
|
29
|
+
if (!cfg.generation) {
|
|
30
|
+
throw new Error("ragpipe config is missing 'generation' plugin.");
|
|
31
|
+
}
|
|
32
|
+
return cfg;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/chunker.ts
|
|
36
|
+
var DEFAULT_CHUNK_SIZE = 400;
|
|
37
|
+
var DEFAULT_OVERLAP = 50;
|
|
38
|
+
function defaultChunker(options) {
|
|
39
|
+
const chunkSize = options?.chunkSize ?? DEFAULT_CHUNK_SIZE;
|
|
40
|
+
const overlap = options?.overlap ?? DEFAULT_OVERLAP;
|
|
41
|
+
return {
|
|
42
|
+
name: "default",
|
|
43
|
+
chunk(text, source) {
|
|
44
|
+
const paragraphs = text.split(/\n\s*\n/).map((p) => p.trim()).filter(Boolean);
|
|
45
|
+
const chunks = [];
|
|
46
|
+
let current = "";
|
|
47
|
+
for (const paragraph of paragraphs) {
|
|
48
|
+
if (current && current.length + paragraph.length + 1 > chunkSize) {
|
|
49
|
+
chunks.push({ source, content: current });
|
|
50
|
+
const overlapSlice = current.slice(-overlap);
|
|
51
|
+
current = overlapSlice + paragraph;
|
|
52
|
+
} else {
|
|
53
|
+
current = current ? `${current}
|
|
54
|
+
${paragraph}` : paragraph;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (current.trim()) {
|
|
58
|
+
chunks.push({ source, content: current });
|
|
59
|
+
}
|
|
60
|
+
if (chunks.length === 0 && text.trim()) {
|
|
61
|
+
chunks.push({ source, content: text.trim() });
|
|
62
|
+
}
|
|
63
|
+
return chunks;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/rate-limiter.ts
|
|
69
|
+
function sleep(ms) {
|
|
70
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
71
|
+
}
|
|
72
|
+
function createRateLimitedEmbedder(plugin, delayMs) {
|
|
73
|
+
const delay = delayMs ?? plugin.rateLimit?.delayMs ?? 0;
|
|
74
|
+
let lastCall = 0;
|
|
75
|
+
async function throttle() {
|
|
76
|
+
if (delay <= 0) return;
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
const elapsed = now - lastCall;
|
|
79
|
+
if (elapsed < delay) {
|
|
80
|
+
await sleep(delay - elapsed);
|
|
81
|
+
}
|
|
82
|
+
lastCall = Date.now();
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
name: plugin.name,
|
|
86
|
+
dimensions: plugin.dimensions,
|
|
87
|
+
rateLimit: plugin.rateLimit,
|
|
88
|
+
async embed(text) {
|
|
89
|
+
await throttle();
|
|
90
|
+
return plugin.embed(text);
|
|
91
|
+
},
|
|
92
|
+
async embedMany(texts) {
|
|
93
|
+
if (plugin.embedMany) {
|
|
94
|
+
await throttle();
|
|
95
|
+
return plugin.embedMany(texts);
|
|
96
|
+
}
|
|
97
|
+
const results = [];
|
|
98
|
+
for (const text of texts) {
|
|
99
|
+
await throttle();
|
|
100
|
+
results.push(await plugin.embed(text));
|
|
101
|
+
}
|
|
102
|
+
return results;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/pipeline.ts
|
|
108
|
+
function createPipeline(config) {
|
|
109
|
+
const chunker = config.chunker ?? defaultChunker();
|
|
110
|
+
const embedder = config.embedding.rateLimit ? createRateLimitedEmbedder(config.embedding) : config.embedding;
|
|
111
|
+
return {
|
|
112
|
+
async ingest(text, source) {
|
|
113
|
+
const chunks = chunker.chunk(text, source);
|
|
114
|
+
for (const chunk of chunks) {
|
|
115
|
+
const vector = await embedder.embed(chunk.content);
|
|
116
|
+
await config.vectorStore.upsert(chunk.source, chunk.content, vector);
|
|
117
|
+
}
|
|
118
|
+
return chunks.length;
|
|
119
|
+
},
|
|
120
|
+
async search(query, topK = 5) {
|
|
121
|
+
const vector = await embedder.embed(query);
|
|
122
|
+
return config.vectorStore.search(vector, topK);
|
|
123
|
+
},
|
|
124
|
+
async ask(query, topK = 5) {
|
|
125
|
+
const chunks = await this.search(query, topK);
|
|
126
|
+
const context = chunks.map((c) => `[${c.source}]
|
|
127
|
+
${c.content}`).join("\n\n---\n\n");
|
|
128
|
+
const answer = await config.generation.generate(query, context, {
|
|
129
|
+
systemPrompt: config.systemPrompt
|
|
130
|
+
});
|
|
131
|
+
return { answer, sources: chunks };
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/cli/ask.ts
|
|
137
|
+
var askCommand = defineCommand({
|
|
138
|
+
meta: {
|
|
139
|
+
name: "ask",
|
|
140
|
+
description: "Ask a question against ingested documents"
|
|
141
|
+
},
|
|
142
|
+
args: {
|
|
143
|
+
query: {
|
|
144
|
+
type: "positional",
|
|
145
|
+
description: "The question to ask",
|
|
146
|
+
required: true
|
|
147
|
+
},
|
|
148
|
+
topK: {
|
|
149
|
+
type: "string",
|
|
150
|
+
description: "Number of context chunks to retrieve",
|
|
151
|
+
default: "5"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
async run({ args }) {
|
|
155
|
+
const query = args.query;
|
|
156
|
+
const topK = Number.parseInt(args.topK, 10);
|
|
157
|
+
consola.start(`Asking: "${query}"`);
|
|
158
|
+
const config = await loadConfig();
|
|
159
|
+
const pipeline = createPipeline(config);
|
|
160
|
+
const result = await pipeline.ask(query, topK);
|
|
161
|
+
console.log(`
|
|
162
|
+
${result.answer}
|
|
163
|
+
`);
|
|
164
|
+
if (result.sources.length > 0) {
|
|
165
|
+
consola.info("Sources:");
|
|
166
|
+
for (const source of result.sources) {
|
|
167
|
+
consola.log(` \u2022 ${source.source} (score: ${source.score.toFixed(3)})`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (config.vectorStore.disconnect) {
|
|
171
|
+
await config.vectorStore.disconnect();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// src/cli/ingest.ts
|
|
177
|
+
import { readFile, readdir, stat } from "fs/promises";
|
|
178
|
+
import { extname, join, relative } from "path";
|
|
179
|
+
import { defineCommand as defineCommand2 } from "citty";
|
|
180
|
+
import consola2 from "consola";
|
|
181
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
182
|
+
".md",
|
|
183
|
+
".mdx",
|
|
184
|
+
".txt",
|
|
185
|
+
".csv",
|
|
186
|
+
".json",
|
|
187
|
+
".html",
|
|
188
|
+
".htm",
|
|
189
|
+
".xml",
|
|
190
|
+
".yaml",
|
|
191
|
+
".yml",
|
|
192
|
+
".rst",
|
|
193
|
+
".adoc",
|
|
194
|
+
".tex",
|
|
195
|
+
".log"
|
|
196
|
+
]);
|
|
197
|
+
async function collectFiles(dir) {
|
|
198
|
+
const files = [];
|
|
199
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
200
|
+
for (const entry of entries) {
|
|
201
|
+
const full = join(dir, entry.name);
|
|
202
|
+
if (entry.isDirectory()) {
|
|
203
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
files.push(...await collectFiles(full));
|
|
207
|
+
} else if (TEXT_EXTENSIONS.has(extname(entry.name).toLowerCase())) {
|
|
208
|
+
files.push(full);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return files;
|
|
212
|
+
}
|
|
213
|
+
var ingestCommand = defineCommand2({
|
|
214
|
+
meta: {
|
|
215
|
+
name: "ingest",
|
|
216
|
+
description: "Ingest documents into the vector store"
|
|
217
|
+
},
|
|
218
|
+
args: {
|
|
219
|
+
path: {
|
|
220
|
+
type: "positional",
|
|
221
|
+
description: "File or directory path to ingest",
|
|
222
|
+
required: true
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
async run({ args }) {
|
|
226
|
+
const target = args.path;
|
|
227
|
+
consola2.start(`Ingesting from ${target}...`);
|
|
228
|
+
const config = await loadConfig();
|
|
229
|
+
const pipeline = createPipeline(config);
|
|
230
|
+
const targetStat = await stat(target);
|
|
231
|
+
const files = targetStat.isDirectory() ? await collectFiles(target) : [target];
|
|
232
|
+
if (files.length === 0) {
|
|
233
|
+
consola2.warn("No text files found to ingest.");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
consola2.info(`Found ${files.length} file(s)`);
|
|
237
|
+
let totalChunks = 0;
|
|
238
|
+
for (const file of files) {
|
|
239
|
+
const content = await readFile(file, "utf-8");
|
|
240
|
+
const source = relative(process.cwd(), file);
|
|
241
|
+
const chunks = await pipeline.ingest(content, source);
|
|
242
|
+
totalChunks += chunks;
|
|
243
|
+
consola2.success(`${source} \u2192 ${chunks} chunks`);
|
|
244
|
+
}
|
|
245
|
+
consola2.success(`Done! ${totalChunks} total chunks ingested.`);
|
|
246
|
+
if (config.vectorStore.disconnect) {
|
|
247
|
+
await config.vectorStore.disconnect();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// src/cli/init.ts
|
|
253
|
+
import { writeFile } from "fs/promises";
|
|
254
|
+
import { resolve } from "path";
|
|
255
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
256
|
+
import consola3 from "consola";
|
|
257
|
+
var EMBEDDING_PROVIDERS = [
|
|
258
|
+
{
|
|
259
|
+
label: "Gemini (Google)",
|
|
260
|
+
value: "gemini",
|
|
261
|
+
package: "@ragpipe/plugin-gemini",
|
|
262
|
+
importName: "geminiEmbedding"
|
|
263
|
+
}
|
|
264
|
+
];
|
|
265
|
+
var VECTORSTORE_PROVIDERS = [
|
|
266
|
+
{
|
|
267
|
+
label: "Supabase (pgvector)",
|
|
268
|
+
value: "supabase",
|
|
269
|
+
package: "@ragpipe/plugin-supabase",
|
|
270
|
+
importName: "supabaseVectorStore"
|
|
271
|
+
}
|
|
272
|
+
];
|
|
273
|
+
var GENERATION_PROVIDERS = [
|
|
274
|
+
{
|
|
275
|
+
label: "Gemini",
|
|
276
|
+
value: "gemini",
|
|
277
|
+
package: "@ragpipe/plugin-gemini",
|
|
278
|
+
importName: "geminiGeneration"
|
|
279
|
+
}
|
|
280
|
+
];
|
|
281
|
+
function generateConfig(embedding, vectorStore, generation) {
|
|
282
|
+
const imports = /* @__PURE__ */ new Map();
|
|
283
|
+
for (const p of [embedding, vectorStore, generation]) {
|
|
284
|
+
const existing = imports.get(p.package) ?? [];
|
|
285
|
+
if (!existing.includes(p.importName)) {
|
|
286
|
+
existing.push(p.importName);
|
|
287
|
+
}
|
|
288
|
+
imports.set(p.package, existing);
|
|
289
|
+
}
|
|
290
|
+
const importLines = [
|
|
291
|
+
'import { defineConfig } from "ragpipe";',
|
|
292
|
+
...Array.from(imports.entries()).map(
|
|
293
|
+
([pkg, names]) => `import { ${names.join(", ")} } from "${pkg}";`
|
|
294
|
+
)
|
|
295
|
+
].join("\n");
|
|
296
|
+
return `${importLines}
|
|
297
|
+
|
|
298
|
+
export default defineConfig({
|
|
299
|
+
embedding: ${embedding.importName}({
|
|
300
|
+
apiKey: process.env.${embedding.value === "gemini" ? "GEMINI_API_KEY" : "API_KEY"}!,
|
|
301
|
+
}),
|
|
302
|
+
vectorStore: ${vectorStore.importName}({
|
|
303
|
+
${vectorStore.value === "supabase" ? "databaseUrl: process.env.DATABASE_URL!," : ""}
|
|
304
|
+
}),
|
|
305
|
+
generation: ${generation.importName}({
|
|
306
|
+
apiKey: process.env.${generation.value === "gemini" ? "GEMINI_API_KEY" : "API_KEY"}!,
|
|
307
|
+
}),
|
|
308
|
+
});
|
|
309
|
+
`;
|
|
310
|
+
}
|
|
311
|
+
async function selectProvider(label, providers) {
|
|
312
|
+
if (providers.length === 1) {
|
|
313
|
+
consola3.info(`${label}: ${providers[0].label} (only available option)`);
|
|
314
|
+
return providers[0];
|
|
315
|
+
}
|
|
316
|
+
const selected = await consola3.prompt(label, {
|
|
317
|
+
type: "select",
|
|
318
|
+
options: providers.map((p) => p.label)
|
|
319
|
+
});
|
|
320
|
+
if (typeof selected === "symbol") {
|
|
321
|
+
throw new Error("Selection cancelled");
|
|
322
|
+
}
|
|
323
|
+
return providers.find((p) => p.label === selected) ?? providers[0];
|
|
324
|
+
}
|
|
325
|
+
var initCommand = defineCommand3({
|
|
326
|
+
meta: {
|
|
327
|
+
name: "init",
|
|
328
|
+
description: "Initialize a ragpipe project \u2014 scaffold ragpipe.config.ts"
|
|
329
|
+
},
|
|
330
|
+
async run() {
|
|
331
|
+
consola3.start("Initializing ragpipe project...\n");
|
|
332
|
+
const embedding = await selectProvider(
|
|
333
|
+
"Select an Embedding provider",
|
|
334
|
+
EMBEDDING_PROVIDERS
|
|
335
|
+
);
|
|
336
|
+
const vectorStore = await selectProvider(
|
|
337
|
+
"Select a VectorStore",
|
|
338
|
+
VECTORSTORE_PROVIDERS
|
|
339
|
+
);
|
|
340
|
+
const generation = await selectProvider(
|
|
341
|
+
"Select a Generation LLM",
|
|
342
|
+
GENERATION_PROVIDERS
|
|
343
|
+
);
|
|
344
|
+
const configContent = generateConfig(embedding, vectorStore, generation);
|
|
345
|
+
const configPath = resolve(process.cwd(), "ragpipe.config.ts");
|
|
346
|
+
await writeFile(configPath, configContent, "utf-8");
|
|
347
|
+
consola3.success("ragpipe.config.ts created");
|
|
348
|
+
const packages = /* @__PURE__ */ new Set();
|
|
349
|
+
for (const p of [embedding, vectorStore, generation]) {
|
|
350
|
+
packages.add(p.package);
|
|
351
|
+
}
|
|
352
|
+
consola3.info(
|
|
353
|
+
`Required packages: ragpipe, ${Array.from(packages).join(", ")}`
|
|
354
|
+
);
|
|
355
|
+
consola3.info(`Run: pnpm add ragpipe ${Array.from(packages).join(" ")}`);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// src/cli.ts
|
|
360
|
+
var main = defineCommand4({
|
|
361
|
+
meta: {
|
|
362
|
+
name: "ragpipe",
|
|
363
|
+
description: "Pluggable TypeScript RAG toolkit",
|
|
364
|
+
version: "0.0.1"
|
|
365
|
+
},
|
|
366
|
+
subCommands: {
|
|
367
|
+
init: initCommand,
|
|
368
|
+
ingest: ingestCommand,
|
|
369
|
+
ask: askCommand
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
runMain(main);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ragpipe",
|
|
3
|
-
"version": "0.0.1",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
4
|
"description": "Pluggable TypeScript RAG toolkit — defineConfig() one file, embed → search → generate.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,10 +27,13 @@
|
|
|
27
27
|
"require": "./dist/index.cjs"
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
|
+
"bin": {
|
|
31
|
+
"ragpipe": "./dist/cli.js"
|
|
32
|
+
},
|
|
30
33
|
"main": "./dist/index.cjs",
|
|
31
34
|
"module": "./dist/index.js",
|
|
32
35
|
"types": "./dist/index.d.ts",
|
|
33
|
-
"files": ["dist"],
|
|
36
|
+
"files": ["dist", "README.md"],
|
|
34
37
|
"scripts": {
|
|
35
38
|
"build": "tsup",
|
|
36
39
|
"dev": "tsup --watch",
|
|
@@ -55,6 +58,8 @@
|
|
|
55
58
|
"vitest": "^3.1.1"
|
|
56
59
|
},
|
|
57
60
|
"dependencies": {
|
|
58
|
-
"c12": "^2.0.4"
|
|
61
|
+
"c12": "^2.0.4",
|
|
62
|
+
"citty": "^0.1.6",
|
|
63
|
+
"consola": "^3.4.0"
|
|
59
64
|
}
|
|
60
65
|
}
|