ko-qmd 2.8.3-ko.2
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/CHANGELOG.md +1376 -0
- package/LICENSE +21 -0
- package/README.ko.md +86 -0
- package/README.md +1307 -0
- package/bin/qmd +192 -0
- package/dist/ast.d.ts +65 -0
- package/dist/ast.js +334 -0
- package/dist/bench/bench.d.ts +35 -0
- package/dist/bench/bench.js +327 -0
- package/dist/bench/score.d.ts +33 -0
- package/dist/bench/score.js +88 -0
- package/dist/bench/types.d.ts +80 -0
- package/dist/bench/types.js +8 -0
- package/dist/cli/build-info.json +4 -0
- package/dist/cli/embed-lock.d.ts +24 -0
- package/dist/cli/embed-lock.js +94 -0
- package/dist/cli/formatter.d.ts +120 -0
- package/dist/cli/formatter.js +355 -0
- package/dist/cli/mcp-pid.d.ts +25 -0
- package/dist/cli/mcp-pid.js +86 -0
- package/dist/cli/qmd.d.ts +43 -0
- package/dist/cli/qmd.js +4424 -0
- package/dist/cli/version.d.ts +42 -0
- package/dist/cli/version.js +80 -0
- package/dist/collections.d.ts +167 -0
- package/dist/collections.js +410 -0
- package/dist/db.d.ts +63 -0
- package/dist/db.js +130 -0
- package/dist/hangul.d.ts +54 -0
- package/dist/hangul.js +140 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.js +244 -0
- package/dist/llm.d.ts +543 -0
- package/dist/llm.js +1747 -0
- package/dist/maintenance.d.ts +33 -0
- package/dist/maintenance.js +52 -0
- package/dist/mcp/origin-guard.d.ts +67 -0
- package/dist/mcp/origin-guard.js +137 -0
- package/dist/mcp/server.d.ts +116 -0
- package/dist/mcp/server.js +883 -0
- package/dist/paths.d.ts +1 -0
- package/dist/paths.js +4 -0
- package/dist/store.d.ts +1100 -0
- package/dist/store.js +4965 -0
- package/dist/trust.d.ts +152 -0
- package/dist/trust.js +249 -0
- package/package.json +114 -0
- package/scripts/build.mjs +72 -0
- package/scripts/check-package-grammars.mjs +29 -0
- package/scripts/package-smoke.mjs +65 -0
- package/scripts/test-all.mjs +38 -0
- package/skills/qmd/SKILL.md +316 -0
- package/skills/qmd/references/mcp-setup.md +119 -0
- package/skills/release/SKILL.md +141 -0
- package/skills/release/scripts/install-hooks.sh +38 -0
- package/skills/release/scripts/release-context.sh +129 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QMD SDK - Library mode for programmatic access to QMD search and indexing.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { createStore } from '@tobilu/qmd'
|
|
6
|
+
*
|
|
7
|
+
* const store = await createStore({
|
|
8
|
+
* dbPath: './my-index.sqlite',
|
|
9
|
+
* config: {
|
|
10
|
+
* collections: {
|
|
11
|
+
* docs: { path: '/path/to/docs', pattern: '**\/*.md' }
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
16
|
+
* const results = await store.search({ query: "how does auth work?" })
|
|
17
|
+
* await store.close()
|
|
18
|
+
*/
|
|
19
|
+
import { createStore as createStoreInternal, hybridQuery, structuredSearch, extractSnippet, addLineNumbers, DEFAULT_MULTI_GET_MAX_BYTES, reindexCollection, generateEmbeddings, listCollections as storeListCollections, syncConfigToDb, getStoreCollections, getStoreCollection, getStoreGlobalContext, getStoreContexts, upsertStoreCollection, deleteStoreCollection, renameStoreCollection, updateStoreContext, removeStoreContext, setStoreGlobalContext, vacuumDatabase, cleanupOrphanedContent, cleanupOrphanedVectors, deleteLLMCache, deleteInactiveDocuments, clearAllEmbeddings, } from "./store.js";
|
|
20
|
+
import { LlamaCpp, } from "./llm.js";
|
|
21
|
+
import { setConfigSource, loadConfig, addCollection as collectionsAddCollection, removeCollection as collectionsRemoveCollection, renameCollection as collectionsRenameCollection, addContext as collectionsAddContext, removeContext as collectionsRemoveContext, setGlobalContext as collectionsSetGlobalContext, } from "./collections.js";
|
|
22
|
+
// Re-export utility functions and types used by frontends
|
|
23
|
+
export { extractSnippet, addLineNumbers, DEFAULT_MULTI_GET_MAX_BYTES };
|
|
24
|
+
// Re-export getDefaultDbPath for CLI/MCP that need the default database location
|
|
25
|
+
export { getDefaultDbPath } from "./store.js";
|
|
26
|
+
// Re-export Maintenance class for CLI housekeeping operations
|
|
27
|
+
export { Maintenance } from "./maintenance.js";
|
|
28
|
+
/**
|
|
29
|
+
* Create a QMD store for programmatic access to search and indexing.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // With a YAML config file
|
|
34
|
+
* const store = await createStore({
|
|
35
|
+
* dbPath: './index.sqlite',
|
|
36
|
+
* configPath: './qmd.yml',
|
|
37
|
+
* })
|
|
38
|
+
*
|
|
39
|
+
* // With inline config (no files needed besides the DB)
|
|
40
|
+
* const store = await createStore({
|
|
41
|
+
* dbPath: './index.sqlite',
|
|
42
|
+
* config: {
|
|
43
|
+
* collections: {
|
|
44
|
+
* docs: { path: '/path/to/docs', pattern: '**\/*.md' }
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* })
|
|
48
|
+
*
|
|
49
|
+
* const results = await store.search({ query: "authentication flow" })
|
|
50
|
+
* await store.close()
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export async function createStore(options) {
|
|
54
|
+
if (!options.dbPath) {
|
|
55
|
+
throw new Error("dbPath is required");
|
|
56
|
+
}
|
|
57
|
+
if (options.configPath && options.config) {
|
|
58
|
+
throw new Error("Provide either configPath or config, not both");
|
|
59
|
+
}
|
|
60
|
+
// Create the internal store (opens DB, creates tables)
|
|
61
|
+
const internal = createStoreInternal(options.dbPath);
|
|
62
|
+
const db = internal.db;
|
|
63
|
+
// Track whether we have a YAML config path for write-through
|
|
64
|
+
const hasYamlConfig = !!options.configPath;
|
|
65
|
+
// Sync config into SQLite store_collections
|
|
66
|
+
let config;
|
|
67
|
+
if (options.configPath) {
|
|
68
|
+
// YAML mode: inject config source for write-through, sync to DB
|
|
69
|
+
setConfigSource({ configPath: options.configPath });
|
|
70
|
+
config = loadConfig();
|
|
71
|
+
syncConfigToDb(db, config);
|
|
72
|
+
}
|
|
73
|
+
else if (options.config) {
|
|
74
|
+
// Inline config mode: inject config source for mutations, sync to DB
|
|
75
|
+
setConfigSource({ config: options.config });
|
|
76
|
+
config = options.config;
|
|
77
|
+
syncConfigToDb(db, config);
|
|
78
|
+
}
|
|
79
|
+
// else: DB-only mode — no external config, use existing store_collections
|
|
80
|
+
// Create a per-store LlamaCpp instance — lazy-loads models on first use,
|
|
81
|
+
// auto-unloads after 5 min inactivity to free VRAM.
|
|
82
|
+
const llm = new LlamaCpp({
|
|
83
|
+
embedModel: config?.models?.embed,
|
|
84
|
+
generateModel: config?.models?.generate,
|
|
85
|
+
rerankModel: config?.models?.rerank,
|
|
86
|
+
inactivityTimeoutMs: 5 * 60 * 1000,
|
|
87
|
+
disposeModelsOnInactivity: true,
|
|
88
|
+
});
|
|
89
|
+
internal.llm = llm;
|
|
90
|
+
const store = {
|
|
91
|
+
internal,
|
|
92
|
+
dbPath: internal.dbPath,
|
|
93
|
+
// Search
|
|
94
|
+
search: async (opts) => {
|
|
95
|
+
if (!opts.query && !opts.queries) {
|
|
96
|
+
throw new Error("search() requires either 'query' or 'queries'");
|
|
97
|
+
}
|
|
98
|
+
// Normalize collection/collections
|
|
99
|
+
const collections = [
|
|
100
|
+
...(opts.collection ? [opts.collection] : []),
|
|
101
|
+
...(opts.collections ?? []),
|
|
102
|
+
];
|
|
103
|
+
const skipRerank = opts.rerank === false;
|
|
104
|
+
if (opts.queries) {
|
|
105
|
+
// Pre-expanded queries — use structuredSearch
|
|
106
|
+
return structuredSearch(internal, opts.queries, {
|
|
107
|
+
collections: collections.length > 0 ? collections : undefined,
|
|
108
|
+
limit: opts.limit,
|
|
109
|
+
minScore: opts.minScore,
|
|
110
|
+
explain: opts.explain,
|
|
111
|
+
intent: opts.intent,
|
|
112
|
+
candidateLimit: opts.candidateLimit,
|
|
113
|
+
skipRerank,
|
|
114
|
+
chunkStrategy: opts.chunkStrategy,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// Simple query string — use hybridQuery (expand + search + rerank)
|
|
118
|
+
return hybridQuery(internal, opts.query, {
|
|
119
|
+
collection: collections.length > 0 ? collections : undefined,
|
|
120
|
+
limit: opts.limit,
|
|
121
|
+
minScore: opts.minScore,
|
|
122
|
+
explain: opts.explain,
|
|
123
|
+
intent: opts.intent,
|
|
124
|
+
candidateLimit: opts.candidateLimit,
|
|
125
|
+
skipRerank,
|
|
126
|
+
chunkStrategy: opts.chunkStrategy,
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
searchLex: async (q, opts) => internal.searchFTS(q, opts?.limit, opts?.collection),
|
|
130
|
+
searchVector: async (q, opts) => internal.searchVec(q, llm.embedModelName, opts?.limit, opts?.collection),
|
|
131
|
+
expandQuery: async (q) => internal.expandQuery(q),
|
|
132
|
+
get: async (pathOrDocid, opts) => internal.findDocument(pathOrDocid, opts),
|
|
133
|
+
getDocumentBody: async (pathOrDocid, opts) => {
|
|
134
|
+
const result = internal.findDocument(pathOrDocid, { includeBody: false });
|
|
135
|
+
if ("error" in result)
|
|
136
|
+
return null;
|
|
137
|
+
return internal.getDocumentBody(result, opts?.fromLine, opts?.maxLines);
|
|
138
|
+
},
|
|
139
|
+
multiGet: async (pattern, opts) => internal.findDocuments(pattern, opts),
|
|
140
|
+
// Collection Management — write to SQLite + write-through to YAML/inline if configured
|
|
141
|
+
addCollection: async (name, opts) => {
|
|
142
|
+
upsertStoreCollection(db, name, { path: opts.path, pattern: opts.pattern, ignore: opts.ignore });
|
|
143
|
+
if (hasYamlConfig || options.config) {
|
|
144
|
+
collectionsAddCollection(name, opts.path, opts.pattern);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
removeCollection: async (name) => {
|
|
148
|
+
const result = deleteStoreCollection(db, name);
|
|
149
|
+
if (hasYamlConfig || options.config) {
|
|
150
|
+
collectionsRemoveCollection(name);
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
},
|
|
154
|
+
renameCollection: async (oldName, newName) => {
|
|
155
|
+
const result = renameStoreCollection(db, oldName, newName);
|
|
156
|
+
if (hasYamlConfig || options.config) {
|
|
157
|
+
collectionsRenameCollection(oldName, newName);
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
},
|
|
161
|
+
listCollections: async () => storeListCollections(db),
|
|
162
|
+
getDefaultCollectionNames: async () => {
|
|
163
|
+
const collections = storeListCollections(db);
|
|
164
|
+
return collections.filter(c => c.includeByDefault).map(c => c.name);
|
|
165
|
+
},
|
|
166
|
+
// Context Management — write to SQLite + write-through to YAML/inline if configured
|
|
167
|
+
addContext: async (collectionName, pathPrefix, contextText) => {
|
|
168
|
+
const result = updateStoreContext(db, collectionName, pathPrefix, contextText);
|
|
169
|
+
if (hasYamlConfig || options.config) {
|
|
170
|
+
collectionsAddContext(collectionName, pathPrefix, contextText);
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
},
|
|
174
|
+
removeContext: async (collectionName, pathPrefix) => {
|
|
175
|
+
const result = removeStoreContext(db, collectionName, pathPrefix);
|
|
176
|
+
if (hasYamlConfig || options.config) {
|
|
177
|
+
collectionsRemoveContext(collectionName, pathPrefix);
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
},
|
|
181
|
+
setGlobalContext: async (context) => {
|
|
182
|
+
setStoreGlobalContext(db, context);
|
|
183
|
+
if (hasYamlConfig || options.config) {
|
|
184
|
+
collectionsSetGlobalContext(context);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
getGlobalContext: async () => getStoreGlobalContext(db),
|
|
188
|
+
listContexts: async () => getStoreContexts(db),
|
|
189
|
+
// Indexing — reads collections from SQLite
|
|
190
|
+
update: async (updateOpts) => {
|
|
191
|
+
const collections = getStoreCollections(db);
|
|
192
|
+
const filtered = updateOpts?.collections
|
|
193
|
+
? collections.filter(c => updateOpts.collections.includes(c.name))
|
|
194
|
+
: collections;
|
|
195
|
+
internal.clearCache();
|
|
196
|
+
let totalIndexed = 0, totalUpdated = 0, totalUnchanged = 0, totalRemoved = 0, totalSkipped = 0;
|
|
197
|
+
for (const col of filtered) {
|
|
198
|
+
const result = await reindexCollection(internal, col.path, col.pattern || "**/*.md", col.name, {
|
|
199
|
+
ignorePatterns: col.ignore,
|
|
200
|
+
onProgress: updateOpts?.onProgress
|
|
201
|
+
? (info) => updateOpts.onProgress({ collection: col.name, ...info })
|
|
202
|
+
: undefined,
|
|
203
|
+
});
|
|
204
|
+
totalIndexed += result.indexed;
|
|
205
|
+
totalUpdated += result.updated;
|
|
206
|
+
totalUnchanged += result.unchanged;
|
|
207
|
+
totalRemoved += result.removed;
|
|
208
|
+
totalSkipped += result.skipped;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
collections: filtered.length,
|
|
212
|
+
indexed: totalIndexed,
|
|
213
|
+
updated: totalUpdated,
|
|
214
|
+
unchanged: totalUnchanged,
|
|
215
|
+
removed: totalRemoved,
|
|
216
|
+
skipped: totalSkipped,
|
|
217
|
+
needsEmbedding: internal.getHashesNeedingEmbedding(),
|
|
218
|
+
};
|
|
219
|
+
},
|
|
220
|
+
embed: async (embedOpts) => {
|
|
221
|
+
return generateEmbeddings(internal, {
|
|
222
|
+
force: embedOpts?.force,
|
|
223
|
+
model: embedOpts?.model,
|
|
224
|
+
collection: embedOpts?.collection,
|
|
225
|
+
maxDocsPerBatch: embedOpts?.maxDocsPerBatch,
|
|
226
|
+
maxBatchBytes: embedOpts?.maxBatchBytes,
|
|
227
|
+
chunkStrategy: embedOpts?.chunkStrategy,
|
|
228
|
+
onProgress: embedOpts?.onProgress,
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
// Index Health
|
|
232
|
+
getStatus: async () => internal.getStatus(),
|
|
233
|
+
getIndexHealth: async () => internal.getIndexHealth(),
|
|
234
|
+
// Lifecycle
|
|
235
|
+
close: async () => {
|
|
236
|
+
await llm.dispose();
|
|
237
|
+
internal.close();
|
|
238
|
+
if (hasYamlConfig || options.config) {
|
|
239
|
+
setConfigSource(undefined); // Reset config source
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
return store;
|
|
244
|
+
}
|