trellis 1.0.8 → 2.0.6
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/LICENSE +21 -0
- package/README.md +564 -83
- package/bin/trellis.mjs +2 -0
- package/dist/cli/index.js +4718 -0
- package/dist/core/index.js +12 -0
- package/dist/decisions/index.js +19 -0
- package/dist/embeddings/index.js +43 -0
- package/dist/index-1j1anhmr.js +4038 -0
- package/dist/index-3s0eak0p.js +1556 -0
- package/dist/index-8pce39mh.js +272 -0
- package/dist/index-a76rekgs.js +67 -0
- package/dist/index-cy9k1g6v.js +684 -0
- package/dist/index-fd4e26s4.js +69 -0
- package/dist/{store/eav-store.js → index-gkvhzm9f.js} +4 -6
- package/dist/index-gnw8d7d6.js +51 -0
- package/dist/index-vkpkfwhq.js +817 -0
- package/dist/index.js +118 -2876
- package/dist/links/index.js +55 -0
- package/dist/transformers-m9je15kg.js +32491 -0
- package/dist/vcs/index.js +110 -0
- package/logo.png +0 -0
- package/logo.svg +9 -0
- package/package.json +79 -76
- package/src/cli/index.ts +2340 -0
- package/src/core/index.ts +35 -0
- package/src/core/kernel/middleware.ts +44 -0
- package/src/core/persist/backend.ts +64 -0
- package/src/core/store/eav-store.ts +467 -0
- package/src/decisions/auto-capture.ts +136 -0
- package/src/decisions/hooks.ts +163 -0
- package/src/decisions/index.ts +261 -0
- package/src/decisions/types.ts +103 -0
- package/src/embeddings/chunker.ts +327 -0
- package/src/embeddings/index.ts +41 -0
- package/src/embeddings/model.ts +95 -0
- package/src/embeddings/search.ts +305 -0
- package/src/embeddings/store.ts +313 -0
- package/src/embeddings/types.ts +85 -0
- package/src/engine.ts +1083 -0
- package/src/garden/cluster.ts +330 -0
- package/src/garden/garden.ts +306 -0
- package/src/garden/index.ts +29 -0
- package/src/git/git-exporter.ts +286 -0
- package/src/git/git-importer.ts +329 -0
- package/src/git/git-reader.ts +189 -0
- package/src/git/index.ts +22 -0
- package/src/identity/governance.ts +211 -0
- package/src/identity/identity.ts +224 -0
- package/src/identity/index.ts +30 -0
- package/src/identity/signing-middleware.ts +97 -0
- package/src/index.ts +20 -0
- package/src/links/index.ts +49 -0
- package/src/links/lifecycle.ts +400 -0
- package/src/links/parser.ts +484 -0
- package/src/links/ref-index.ts +186 -0
- package/src/links/resolver.ts +314 -0
- package/src/links/types.ts +108 -0
- package/src/mcp/index.ts +22 -0
- package/src/mcp/server.ts +1278 -0
- package/src/semantic/csharp-parser.ts +493 -0
- package/src/semantic/go-parser.ts +585 -0
- package/src/semantic/index.ts +34 -0
- package/src/semantic/java-parser.ts +456 -0
- package/src/semantic/python-parser.ts +659 -0
- package/src/semantic/ruby-parser.ts +446 -0
- package/src/semantic/rust-parser.ts +784 -0
- package/src/semantic/semantic-merge.ts +210 -0
- package/src/semantic/ts-parser.ts +681 -0
- package/src/semantic/types.ts +175 -0
- package/src/sync/index.ts +32 -0
- package/src/sync/memory-transport.ts +66 -0
- package/src/sync/reconciler.ts +237 -0
- package/src/sync/sync-engine.ts +258 -0
- package/src/sync/types.ts +104 -0
- package/src/vcs/blob-store.ts +124 -0
- package/src/vcs/branch.ts +150 -0
- package/src/vcs/checkpoint.ts +64 -0
- package/src/vcs/decompose.ts +469 -0
- package/src/vcs/diff.ts +409 -0
- package/src/vcs/engine-context.ts +26 -0
- package/src/vcs/index.ts +23 -0
- package/src/vcs/issue.ts +800 -0
- package/src/vcs/merge.ts +425 -0
- package/src/vcs/milestone.ts +124 -0
- package/src/vcs/ops.ts +59 -0
- package/src/vcs/types.ts +213 -0
- package/src/vcs/vcs-middleware.ts +81 -0
- package/src/watcher/fs-watcher.ts +217 -0
- package/src/watcher/index.ts +9 -0
- package/src/watcher/ingestion.ts +116 -0
- package/dist/ai/index.js +0 -688
- package/dist/cli/server.js +0 -3321
- package/dist/cli/tql.js +0 -5282
- package/dist/client/tql-client.js +0 -108
- package/dist/graph/index.js +0 -2248
- package/dist/kernel/logic-middleware.js +0 -179
- package/dist/kernel/middleware.js +0 -0
- package/dist/kernel/operations.js +0 -32
- package/dist/kernel/schema-middleware.js +0 -34
- package/dist/kernel/security-middleware.js +0 -53
- package/dist/kernel/trellis-kernel.js +0 -2239
- package/dist/kernel/workspace.js +0 -91
- package/dist/persist/backend.js +0 -0
- package/dist/persist/sqlite-backend.js +0 -123
- package/dist/query/index.js +0 -1643
- package/dist/server/index.js +0 -3309
- package/dist/workflows/index.js +0 -3160
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__esm,
|
|
4
|
+
__export,
|
|
5
|
+
__require
|
|
6
|
+
} from "./index-a76rekgs.js";
|
|
7
|
+
|
|
8
|
+
// src/embeddings/types.ts
|
|
9
|
+
var DEFAULT_MODEL_CONFIG;
|
|
10
|
+
var init_types = __esm(() => {
|
|
11
|
+
DEFAULT_MODEL_CONFIG = {
|
|
12
|
+
modelName: "Xenova/all-MiniLM-L6-v2",
|
|
13
|
+
dimension: 384
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// src/embeddings/model.ts
|
|
18
|
+
async function loadModel(config = DEFAULT_MODEL_CONFIG) {
|
|
19
|
+
if (pipeline)
|
|
20
|
+
return pipeline;
|
|
21
|
+
if (!loadPromise) {
|
|
22
|
+
loadPromise = (async () => {
|
|
23
|
+
const { pipeline: createPipeline } = await import("./transformers-m9je15kg.js");
|
|
24
|
+
const opts = {};
|
|
25
|
+
if (config.cacheDir) {
|
|
26
|
+
opts.cache_dir = config.cacheDir;
|
|
27
|
+
}
|
|
28
|
+
pipeline = await createPipeline("feature-extraction", config.modelName, opts);
|
|
29
|
+
return pipeline;
|
|
30
|
+
})();
|
|
31
|
+
}
|
|
32
|
+
return loadPromise;
|
|
33
|
+
}
|
|
34
|
+
async function embed(text, config = DEFAULT_MODEL_CONFIG) {
|
|
35
|
+
const pipe = await loadModel(config);
|
|
36
|
+
const output = await pipe(text, { pooling: "mean", normalize: true });
|
|
37
|
+
return new Float32Array(output.data);
|
|
38
|
+
}
|
|
39
|
+
async function embedBatch(texts, config = DEFAULT_MODEL_CONFIG) {
|
|
40
|
+
if (texts.length === 0)
|
|
41
|
+
return [];
|
|
42
|
+
const pipe = await loadModel(config);
|
|
43
|
+
const results = [];
|
|
44
|
+
const batchSize = 32;
|
|
45
|
+
for (let i = 0;i < texts.length; i += batchSize) {
|
|
46
|
+
const batch = texts.slice(i, i + batchSize);
|
|
47
|
+
for (const text of batch) {
|
|
48
|
+
const output = await pipe(text, { pooling: "mean", normalize: true });
|
|
49
|
+
results.push(new Float32Array(output.data));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
function resetModel() {
|
|
55
|
+
pipeline = null;
|
|
56
|
+
loadPromise = null;
|
|
57
|
+
}
|
|
58
|
+
var pipeline = null, loadPromise = null;
|
|
59
|
+
var init_model = __esm(() => {
|
|
60
|
+
init_types();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// src/embeddings/store.ts
|
|
64
|
+
import { Database } from "bun:sqlite";
|
|
65
|
+
|
|
66
|
+
class VectorStore {
|
|
67
|
+
db;
|
|
68
|
+
constructor(dbPath) {
|
|
69
|
+
this.db = new Database(dbPath);
|
|
70
|
+
this.db.exec("PRAGMA journal_mode=WAL;");
|
|
71
|
+
this.db.exec("PRAGMA foreign_keys=ON;");
|
|
72
|
+
this.db.exec(SCHEMA_SQL);
|
|
73
|
+
}
|
|
74
|
+
upsert(record) {
|
|
75
|
+
const insertChunk = this.db.prepare(`
|
|
76
|
+
INSERT OR REPLACE INTO chunks (id, entity_id, content, chunk_type, file_path, updated_at)
|
|
77
|
+
VALUES ($id, $entityId, $content, $chunkType, $filePath, $updatedAt)
|
|
78
|
+
`);
|
|
79
|
+
const insertVector = this.db.prepare(`
|
|
80
|
+
INSERT OR REPLACE INTO vectors (id, embedding)
|
|
81
|
+
VALUES ($id, $embedding)
|
|
82
|
+
`);
|
|
83
|
+
const embeddingBlob = Buffer.from(record.embedding.buffer);
|
|
84
|
+
this.db.transaction(() => {
|
|
85
|
+
insertChunk.run({
|
|
86
|
+
$id: record.id,
|
|
87
|
+
$entityId: record.entityId,
|
|
88
|
+
$content: record.content,
|
|
89
|
+
$chunkType: record.chunkType,
|
|
90
|
+
$filePath: record.filePath ?? null,
|
|
91
|
+
$updatedAt: record.updatedAt
|
|
92
|
+
});
|
|
93
|
+
insertVector.run({
|
|
94
|
+
$id: record.id,
|
|
95
|
+
$embedding: embeddingBlob
|
|
96
|
+
});
|
|
97
|
+
})();
|
|
98
|
+
}
|
|
99
|
+
upsertBatch(records) {
|
|
100
|
+
if (records.length === 0)
|
|
101
|
+
return;
|
|
102
|
+
const insertChunk = this.db.prepare(`
|
|
103
|
+
INSERT OR REPLACE INTO chunks (id, entity_id, content, chunk_type, file_path, updated_at)
|
|
104
|
+
VALUES ($id, $entityId, $content, $chunkType, $filePath, $updatedAt)
|
|
105
|
+
`);
|
|
106
|
+
const insertVector = this.db.prepare(`
|
|
107
|
+
INSERT OR REPLACE INTO vectors (id, embedding)
|
|
108
|
+
VALUES ($id, $embedding)
|
|
109
|
+
`);
|
|
110
|
+
this.db.transaction(() => {
|
|
111
|
+
for (const record of records) {
|
|
112
|
+
const embeddingBlob = Buffer.from(record.embedding.buffer);
|
|
113
|
+
insertChunk.run({
|
|
114
|
+
$id: record.id,
|
|
115
|
+
$entityId: record.entityId,
|
|
116
|
+
$content: record.content,
|
|
117
|
+
$chunkType: record.chunkType,
|
|
118
|
+
$filePath: record.filePath ?? null,
|
|
119
|
+
$updatedAt: record.updatedAt
|
|
120
|
+
});
|
|
121
|
+
insertVector.run({
|
|
122
|
+
$id: record.id,
|
|
123
|
+
$embedding: embeddingBlob
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
})();
|
|
127
|
+
}
|
|
128
|
+
delete(id) {
|
|
129
|
+
this.db.prepare("DELETE FROM vectors WHERE id = ?").run(id);
|
|
130
|
+
this.db.prepare("DELETE FROM chunks WHERE id = ?").run(id);
|
|
131
|
+
}
|
|
132
|
+
deleteByEntity(entityId) {
|
|
133
|
+
const ids = this.db.prepare("SELECT id FROM chunks WHERE entity_id = ?").all(entityId);
|
|
134
|
+
if (ids.length === 0)
|
|
135
|
+
return;
|
|
136
|
+
this.db.transaction(() => {
|
|
137
|
+
for (const { id } of ids) {
|
|
138
|
+
this.db.prepare("DELETE FROM vectors WHERE id = ?").run(id);
|
|
139
|
+
this.db.prepare("DELETE FROM chunks WHERE id = ?").run(id);
|
|
140
|
+
}
|
|
141
|
+
})();
|
|
142
|
+
}
|
|
143
|
+
deleteByFile(filePath) {
|
|
144
|
+
const ids = this.db.prepare("SELECT id FROM chunks WHERE file_path = ?").all(filePath);
|
|
145
|
+
if (ids.length === 0)
|
|
146
|
+
return;
|
|
147
|
+
this.db.transaction(() => {
|
|
148
|
+
for (const { id } of ids) {
|
|
149
|
+
this.db.prepare("DELETE FROM vectors WHERE id = ?").run(id);
|
|
150
|
+
this.db.prepare("DELETE FROM chunks WHERE id = ?").run(id);
|
|
151
|
+
}
|
|
152
|
+
})();
|
|
153
|
+
}
|
|
154
|
+
getChunk(id) {
|
|
155
|
+
const row = this.db.prepare("SELECT * FROM chunks WHERE id = ?").get(id);
|
|
156
|
+
if (!row)
|
|
157
|
+
return null;
|
|
158
|
+
return rowToChunkMeta(row);
|
|
159
|
+
}
|
|
160
|
+
search(queryVector, opts = {}) {
|
|
161
|
+
const limit = opts.limit ?? 10;
|
|
162
|
+
const minScore = opts.minScore ?? 0;
|
|
163
|
+
const conditions = [];
|
|
164
|
+
const params = {};
|
|
165
|
+
if (opts.types && opts.types.length > 0) {
|
|
166
|
+
const placeholders = opts.types.map((_, i) => `$type${i}`).join(", ");
|
|
167
|
+
conditions.push(`c.chunk_type IN (${placeholders})`);
|
|
168
|
+
opts.types.forEach((t, i) => {
|
|
169
|
+
params[`$type${i}`] = t;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (opts.filePrefix) {
|
|
173
|
+
conditions.push("c.file_path LIKE $filePrefix");
|
|
174
|
+
params.$filePrefix = `${opts.filePrefix}%`;
|
|
175
|
+
}
|
|
176
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
177
|
+
const sql = `
|
|
178
|
+
SELECT c.id, c.entity_id, c.content, c.chunk_type, c.file_path, c.updated_at,
|
|
179
|
+
v.embedding
|
|
180
|
+
FROM chunks c
|
|
181
|
+
JOIN vectors v ON c.id = v.id
|
|
182
|
+
${where}
|
|
183
|
+
`;
|
|
184
|
+
const rows = this.db.prepare(sql).all(params);
|
|
185
|
+
const scored = [];
|
|
186
|
+
for (const row of rows) {
|
|
187
|
+
const storedVec = new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4);
|
|
188
|
+
const score = cosineSimilarity(queryVector, storedVec);
|
|
189
|
+
if (score >= minScore) {
|
|
190
|
+
scored.push({
|
|
191
|
+
chunk: rowToChunkMeta(row),
|
|
192
|
+
score
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
scored.sort((a, b) => b.score - a.score);
|
|
197
|
+
return scored.slice(0, limit);
|
|
198
|
+
}
|
|
199
|
+
count() {
|
|
200
|
+
const row = this.db.prepare("SELECT COUNT(*) as cnt FROM chunks").get();
|
|
201
|
+
return row?.cnt ?? 0;
|
|
202
|
+
}
|
|
203
|
+
countByType() {
|
|
204
|
+
const rows = this.db.prepare("SELECT chunk_type, COUNT(*) as cnt FROM chunks GROUP BY chunk_type").all();
|
|
205
|
+
const result = {};
|
|
206
|
+
for (const row of rows) {
|
|
207
|
+
result[row.chunk_type] = row.cnt;
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
clear() {
|
|
212
|
+
this.db.exec("DELETE FROM vectors");
|
|
213
|
+
this.db.exec("DELETE FROM chunks");
|
|
214
|
+
}
|
|
215
|
+
close() {
|
|
216
|
+
this.db.close();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function rowToChunkMeta(row) {
|
|
220
|
+
return {
|
|
221
|
+
id: row.id,
|
|
222
|
+
entityId: row.entity_id,
|
|
223
|
+
content: row.content,
|
|
224
|
+
chunkType: row.chunk_type,
|
|
225
|
+
filePath: row.file_path ?? undefined,
|
|
226
|
+
updatedAt: row.updated_at
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function cosineSimilarity(a, b) {
|
|
230
|
+
if (a.length !== b.length)
|
|
231
|
+
return 0;
|
|
232
|
+
let dot = 0;
|
|
233
|
+
let normA = 0;
|
|
234
|
+
let normB = 0;
|
|
235
|
+
for (let i = 0;i < a.length; i++) {
|
|
236
|
+
dot += a[i] * b[i];
|
|
237
|
+
normA += a[i] * a[i];
|
|
238
|
+
normB += b[i] * b[i];
|
|
239
|
+
}
|
|
240
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
241
|
+
return denom === 0 ? 0 : dot / denom;
|
|
242
|
+
}
|
|
243
|
+
var SCHEMA_SQL = `
|
|
244
|
+
CREATE TABLE IF NOT EXISTS chunks (
|
|
245
|
+
id TEXT PRIMARY KEY,
|
|
246
|
+
entity_id TEXT NOT NULL,
|
|
247
|
+
content TEXT NOT NULL,
|
|
248
|
+
chunk_type TEXT NOT NULL,
|
|
249
|
+
file_path TEXT,
|
|
250
|
+
updated_at TEXT NOT NULL
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
CREATE TABLE IF NOT EXISTS vectors (
|
|
254
|
+
id TEXT PRIMARY KEY,
|
|
255
|
+
embedding BLOB NOT NULL,
|
|
256
|
+
FOREIGN KEY (id) REFERENCES chunks(id) ON DELETE CASCADE
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
CREATE INDEX IF NOT EXISTS idx_chunks_entity ON chunks(entity_id);
|
|
260
|
+
CREATE INDEX IF NOT EXISTS idx_chunks_type ON chunks(chunk_type);
|
|
261
|
+
CREATE INDEX IF NOT EXISTS idx_chunks_file ON chunks(file_path);
|
|
262
|
+
`;
|
|
263
|
+
var init_store = () => {};
|
|
264
|
+
|
|
265
|
+
// src/embeddings/chunker.ts
|
|
266
|
+
function chunkIssue(issue) {
|
|
267
|
+
const now = new Date().toISOString();
|
|
268
|
+
const chunks = [];
|
|
269
|
+
if (issue.title) {
|
|
270
|
+
chunks.push({
|
|
271
|
+
id: `issue:${issue.id}:title`,
|
|
272
|
+
entityId: `issue:${issue.id}`,
|
|
273
|
+
content: issue.title,
|
|
274
|
+
chunkType: "issue_title",
|
|
275
|
+
updatedAt: now
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
if (issue.description) {
|
|
279
|
+
chunks.push({
|
|
280
|
+
id: `issue:${issue.id}:desc`,
|
|
281
|
+
entityId: `issue:${issue.id}`,
|
|
282
|
+
content: issue.description,
|
|
283
|
+
chunkType: "issue_desc",
|
|
284
|
+
updatedAt: now
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
return chunks;
|
|
288
|
+
}
|
|
289
|
+
function chunkDecision(decision) {
|
|
290
|
+
const parts = [];
|
|
291
|
+
parts.push(`Decision ${decision.id}: ${decision.toolName}`);
|
|
292
|
+
if (decision.rationale)
|
|
293
|
+
parts.push(`Rationale: ${decision.rationale}`);
|
|
294
|
+
if (decision.context)
|
|
295
|
+
parts.push(`Context: ${decision.context}`);
|
|
296
|
+
if (decision.outputSummary)
|
|
297
|
+
parts.push(`Output: ${decision.outputSummary}`);
|
|
298
|
+
const content = parts.join(`
|
|
299
|
+
`);
|
|
300
|
+
if (!content.trim())
|
|
301
|
+
return [];
|
|
302
|
+
return [
|
|
303
|
+
{
|
|
304
|
+
id: `decision:${decision.id}:rationale`,
|
|
305
|
+
entityId: `decision:${decision.id}`,
|
|
306
|
+
content,
|
|
307
|
+
chunkType: "decision_rationale",
|
|
308
|
+
updatedAt: new Date().toISOString()
|
|
309
|
+
}
|
|
310
|
+
];
|
|
311
|
+
}
|
|
312
|
+
function chunkMilestone(milestone) {
|
|
313
|
+
if (!milestone.message)
|
|
314
|
+
return [];
|
|
315
|
+
return [
|
|
316
|
+
{
|
|
317
|
+
id: `milestone:${milestone.id}:msg`,
|
|
318
|
+
entityId: `milestone:${milestone.id}`,
|
|
319
|
+
content: milestone.message,
|
|
320
|
+
chunkType: "milestone_msg",
|
|
321
|
+
updatedAt: new Date().toISOString()
|
|
322
|
+
}
|
|
323
|
+
];
|
|
324
|
+
}
|
|
325
|
+
function chunkMarkdown(filePath, content) {
|
|
326
|
+
if (!content.trim())
|
|
327
|
+
return [];
|
|
328
|
+
const entityId = `file:${filePath}`;
|
|
329
|
+
const now = new Date().toISOString();
|
|
330
|
+
const sections = splitByHeadings(content);
|
|
331
|
+
const chunks = [];
|
|
332
|
+
for (let i = 0;i < sections.length; i++) {
|
|
333
|
+
const section = sections[i];
|
|
334
|
+
if (!section.text.trim())
|
|
335
|
+
continue;
|
|
336
|
+
if (section.text.length <= MAX_CHUNK_CHARS) {
|
|
337
|
+
chunks.push({
|
|
338
|
+
id: `${entityId}:section:${i}`,
|
|
339
|
+
entityId,
|
|
340
|
+
content: section.text,
|
|
341
|
+
chunkType: "markdown",
|
|
342
|
+
filePath,
|
|
343
|
+
updatedAt: now
|
|
344
|
+
});
|
|
345
|
+
} else {
|
|
346
|
+
const windows = slidingWindow(section.text);
|
|
347
|
+
for (let w = 0;w < windows.length; w++) {
|
|
348
|
+
chunks.push({
|
|
349
|
+
id: `${entityId}:section:${i}:w${w}`,
|
|
350
|
+
entityId,
|
|
351
|
+
content: windows[w],
|
|
352
|
+
chunkType: "markdown",
|
|
353
|
+
filePath,
|
|
354
|
+
updatedAt: now
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return chunks;
|
|
360
|
+
}
|
|
361
|
+
function chunkCodeEntities(filePath, declarations) {
|
|
362
|
+
const now = new Date().toISOString();
|
|
363
|
+
const chunks = [];
|
|
364
|
+
for (const decl of declarations) {
|
|
365
|
+
const parts = [];
|
|
366
|
+
if (decl.docComment)
|
|
367
|
+
parts.push(decl.docComment);
|
|
368
|
+
parts.push(`${decl.kind} ${decl.name}`);
|
|
369
|
+
parts.push(decl.signature);
|
|
370
|
+
const content = parts.join(`
|
|
371
|
+
`).slice(0, MAX_CHUNK_CHARS);
|
|
372
|
+
chunks.push({
|
|
373
|
+
id: `symbol:${filePath}#${decl.name}`,
|
|
374
|
+
entityId: `symbol:${filePath}#${decl.name}`,
|
|
375
|
+
content,
|
|
376
|
+
chunkType: "code_entity",
|
|
377
|
+
filePath,
|
|
378
|
+
updatedAt: now
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return chunks;
|
|
382
|
+
}
|
|
383
|
+
function chunkDocComments(filePath, comments) {
|
|
384
|
+
if (comments.length === 0)
|
|
385
|
+
return [];
|
|
386
|
+
const entityId = `file:${filePath}`;
|
|
387
|
+
const now = new Date().toISOString();
|
|
388
|
+
const chunks = [];
|
|
389
|
+
for (let i = 0;i < comments.length; i++) {
|
|
390
|
+
const comment = comments[i];
|
|
391
|
+
if (!comment.text.trim())
|
|
392
|
+
continue;
|
|
393
|
+
chunks.push({
|
|
394
|
+
id: `${entityId}:doc:${i}`,
|
|
395
|
+
entityId,
|
|
396
|
+
content: comment.text.slice(0, MAX_CHUNK_CHARS),
|
|
397
|
+
chunkType: "doc_comment",
|
|
398
|
+
filePath,
|
|
399
|
+
updatedAt: now
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
return chunks;
|
|
403
|
+
}
|
|
404
|
+
function chunkSummary(filePath, content) {
|
|
405
|
+
if (!content.trim())
|
|
406
|
+
return [];
|
|
407
|
+
const entityId = `file:${filePath}`;
|
|
408
|
+
const now = new Date().toISOString();
|
|
409
|
+
if (content.length <= MAX_CHUNK_CHARS) {
|
|
410
|
+
return [
|
|
411
|
+
{
|
|
412
|
+
id: `${entityId}:summary`,
|
|
413
|
+
entityId,
|
|
414
|
+
content,
|
|
415
|
+
chunkType: "summary_md",
|
|
416
|
+
filePath,
|
|
417
|
+
updatedAt: now
|
|
418
|
+
}
|
|
419
|
+
];
|
|
420
|
+
}
|
|
421
|
+
return chunkMarkdown(filePath, content).map((c) => ({
|
|
422
|
+
...c,
|
|
423
|
+
chunkType: "summary_md"
|
|
424
|
+
}));
|
|
425
|
+
}
|
|
426
|
+
function chunkFile(filePath, content) {
|
|
427
|
+
if (!content.trim())
|
|
428
|
+
return [];
|
|
429
|
+
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
|
|
430
|
+
if (filePath.endsWith("summary.md")) {
|
|
431
|
+
return chunkSummary(filePath, content);
|
|
432
|
+
}
|
|
433
|
+
if (ext === "md") {
|
|
434
|
+
return chunkMarkdown(filePath, content);
|
|
435
|
+
}
|
|
436
|
+
return [];
|
|
437
|
+
}
|
|
438
|
+
function splitByHeadings(content) {
|
|
439
|
+
const lines = content.split(`
|
|
440
|
+
`);
|
|
441
|
+
const sections = [];
|
|
442
|
+
let currentSection = { text: "" };
|
|
443
|
+
for (const line of lines) {
|
|
444
|
+
if (/^#{1,3}\s/.test(line)) {
|
|
445
|
+
if (currentSection.text.trim()) {
|
|
446
|
+
sections.push(currentSection);
|
|
447
|
+
}
|
|
448
|
+
currentSection = { heading: line, text: line + `
|
|
449
|
+
` };
|
|
450
|
+
} else {
|
|
451
|
+
currentSection.text += line + `
|
|
452
|
+
`;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (currentSection.text.trim()) {
|
|
456
|
+
sections.push(currentSection);
|
|
457
|
+
}
|
|
458
|
+
return sections;
|
|
459
|
+
}
|
|
460
|
+
function slidingWindow(text) {
|
|
461
|
+
const windows = [];
|
|
462
|
+
let start = 0;
|
|
463
|
+
while (start < text.length) {
|
|
464
|
+
const end = Math.min(start + MAX_CHUNK_CHARS, text.length);
|
|
465
|
+
windows.push(text.slice(start, end));
|
|
466
|
+
if (end >= text.length)
|
|
467
|
+
break;
|
|
468
|
+
start += MAX_CHUNK_CHARS - OVERLAP_CHARS;
|
|
469
|
+
}
|
|
470
|
+
return windows;
|
|
471
|
+
}
|
|
472
|
+
var MAX_CHUNK_CHARS = 512, OVERLAP_CHARS = 64;
|
|
473
|
+
var init_chunker = () => {};
|
|
474
|
+
|
|
475
|
+
// src/embeddings/search.ts
|
|
476
|
+
import { join } from "path";
|
|
477
|
+
import { readFileSync, existsSync } from "fs";
|
|
478
|
+
|
|
479
|
+
class EmbeddingManager {
|
|
480
|
+
store;
|
|
481
|
+
embedFn;
|
|
482
|
+
constructor(dbPath, embedFn) {
|
|
483
|
+
this.store = new VectorStore(dbPath);
|
|
484
|
+
this.embedFn = embedFn ?? embed;
|
|
485
|
+
}
|
|
486
|
+
async reindex(engine) {
|
|
487
|
+
this.store.clear();
|
|
488
|
+
const allChunks = [];
|
|
489
|
+
const issues = engine.listIssues();
|
|
490
|
+
for (const issue of issues) {
|
|
491
|
+
allChunks.push(...chunkIssue(issue));
|
|
492
|
+
}
|
|
493
|
+
const milestones = engine.listMilestones();
|
|
494
|
+
for (const ms of milestones) {
|
|
495
|
+
allChunks.push(...chunkMilestone(ms));
|
|
496
|
+
}
|
|
497
|
+
if (engine.queryDecisions) {
|
|
498
|
+
const decisions = engine.queryDecisions();
|
|
499
|
+
for (const dec of decisions) {
|
|
500
|
+
allChunks.push(...chunkDecision(dec));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const rootPath = engine.getRootPath();
|
|
504
|
+
const trackedFiles = engine.trackedFiles();
|
|
505
|
+
for (const tf of trackedFiles) {
|
|
506
|
+
try {
|
|
507
|
+
const absPath = join(rootPath, tf.path);
|
|
508
|
+
if (!existsSync(absPath))
|
|
509
|
+
continue;
|
|
510
|
+
const content = readFileSync(absPath, "utf-8");
|
|
511
|
+
allChunks.push(...chunkFile(tf.path, content));
|
|
512
|
+
} catch {}
|
|
513
|
+
}
|
|
514
|
+
if (engine.parseFile) {
|
|
515
|
+
for (const tf of trackedFiles) {
|
|
516
|
+
const ext = tf.path.split(".").pop()?.toLowerCase() ?? "";
|
|
517
|
+
if (![
|
|
518
|
+
"ts",
|
|
519
|
+
"js",
|
|
520
|
+
"tsx",
|
|
521
|
+
"jsx",
|
|
522
|
+
"py",
|
|
523
|
+
"go",
|
|
524
|
+
"rs",
|
|
525
|
+
"rb",
|
|
526
|
+
"java",
|
|
527
|
+
"cs"
|
|
528
|
+
].includes(ext)) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
const parsed = engine.parseFile(tf.path);
|
|
533
|
+
if (parsed && Array.isArray(parsed.entities)) {
|
|
534
|
+
const declarations = parsed.entities.map((e) => ({
|
|
535
|
+
id: e.id ?? e.name,
|
|
536
|
+
name: e.name,
|
|
537
|
+
kind: e.kind,
|
|
538
|
+
signature: e.signature ?? e.rawText?.split(`
|
|
539
|
+
`)[0] ?? "",
|
|
540
|
+
docComment: e.docComment
|
|
541
|
+
}));
|
|
542
|
+
allChunks.push(...chunkCodeEntities(tf.path, declarations));
|
|
543
|
+
}
|
|
544
|
+
} catch {}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const records = [];
|
|
548
|
+
for (const chunk of allChunks) {
|
|
549
|
+
try {
|
|
550
|
+
const vector = await this.embedFn(chunk.content);
|
|
551
|
+
records.push({ ...chunk, embedding: vector });
|
|
552
|
+
} catch {}
|
|
553
|
+
}
|
|
554
|
+
this.store.upsertBatch(records);
|
|
555
|
+
return { chunks: records.length };
|
|
556
|
+
}
|
|
557
|
+
async indexFile(filePath, content, engine) {
|
|
558
|
+
this.store.deleteByFile(filePath);
|
|
559
|
+
const chunks = chunkFile(filePath, content);
|
|
560
|
+
if (engine?.parseFile) {
|
|
561
|
+
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
|
|
562
|
+
if ([
|
|
563
|
+
"ts",
|
|
564
|
+
"js",
|
|
565
|
+
"tsx",
|
|
566
|
+
"jsx",
|
|
567
|
+
"py",
|
|
568
|
+
"go",
|
|
569
|
+
"rs",
|
|
570
|
+
"rb",
|
|
571
|
+
"java",
|
|
572
|
+
"cs"
|
|
573
|
+
].includes(ext)) {
|
|
574
|
+
try {
|
|
575
|
+
const parsed = engine.parseFile(filePath);
|
|
576
|
+
if (parsed && Array.isArray(parsed.entities)) {
|
|
577
|
+
const declarations = parsed.entities.map((e) => ({
|
|
578
|
+
id: e.id ?? e.name,
|
|
579
|
+
name: e.name,
|
|
580
|
+
kind: e.kind,
|
|
581
|
+
signature: e.signature ?? e.rawText?.split(`
|
|
582
|
+
`)[0] ?? "",
|
|
583
|
+
docComment: e.docComment
|
|
584
|
+
}));
|
|
585
|
+
chunks.push(...chunkCodeEntities(filePath, declarations));
|
|
586
|
+
}
|
|
587
|
+
} catch {}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const records = [];
|
|
591
|
+
for (const chunk of chunks) {
|
|
592
|
+
try {
|
|
593
|
+
const vector = await this.embedFn(chunk.content);
|
|
594
|
+
records.push({ ...chunk, embedding: vector });
|
|
595
|
+
} catch {}
|
|
596
|
+
}
|
|
597
|
+
if (records.length > 0) {
|
|
598
|
+
this.store.upsertBatch(records);
|
|
599
|
+
}
|
|
600
|
+
return records.length;
|
|
601
|
+
}
|
|
602
|
+
async indexIssue(issue) {
|
|
603
|
+
this.store.deleteByEntity(`issue:${issue.id}`);
|
|
604
|
+
const chunks = chunkIssue(issue);
|
|
605
|
+
const records = [];
|
|
606
|
+
for (const chunk of chunks) {
|
|
607
|
+
try {
|
|
608
|
+
const vector = await this.embedFn(chunk.content);
|
|
609
|
+
records.push({ ...chunk, embedding: vector });
|
|
610
|
+
} catch {}
|
|
611
|
+
}
|
|
612
|
+
if (records.length > 0) {
|
|
613
|
+
this.store.upsertBatch(records);
|
|
614
|
+
}
|
|
615
|
+
return records.length;
|
|
616
|
+
}
|
|
617
|
+
async indexMilestone(milestone) {
|
|
618
|
+
this.store.deleteByEntity(`milestone:${milestone.id}`);
|
|
619
|
+
const chunks = chunkMilestone(milestone);
|
|
620
|
+
const records = [];
|
|
621
|
+
for (const chunk of chunks) {
|
|
622
|
+
try {
|
|
623
|
+
const vector = await this.embedFn(chunk.content);
|
|
624
|
+
records.push({ ...chunk, embedding: vector });
|
|
625
|
+
} catch {}
|
|
626
|
+
}
|
|
627
|
+
if (records.length > 0) {
|
|
628
|
+
this.store.upsertBatch(records);
|
|
629
|
+
}
|
|
630
|
+
return records.length;
|
|
631
|
+
}
|
|
632
|
+
async search(query, opts) {
|
|
633
|
+
const queryVector = await this.embedFn(query);
|
|
634
|
+
return this.store.search(queryVector, opts);
|
|
635
|
+
}
|
|
636
|
+
removeFile(filePath) {
|
|
637
|
+
this.store.deleteByFile(filePath);
|
|
638
|
+
}
|
|
639
|
+
stats() {
|
|
640
|
+
return {
|
|
641
|
+
total: this.store.count(),
|
|
642
|
+
byType: this.store.countByType()
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
close() {
|
|
646
|
+
this.store.close();
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
var init_search = __esm(() => {
|
|
650
|
+
init_store();
|
|
651
|
+
init_model();
|
|
652
|
+
init_chunker();
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// src/embeddings/index.ts
|
|
656
|
+
var exports_embeddings = {};
|
|
657
|
+
__export(exports_embeddings, {
|
|
658
|
+
slidingWindow: () => slidingWindow,
|
|
659
|
+
resetModel: () => resetModel,
|
|
660
|
+
loadModel: () => loadModel,
|
|
661
|
+
embedBatch: () => embedBatch,
|
|
662
|
+
embed: () => embed,
|
|
663
|
+
cosineSimilarity: () => cosineSimilarity,
|
|
664
|
+
chunkSummary: () => chunkSummary,
|
|
665
|
+
chunkMilestone: () => chunkMilestone,
|
|
666
|
+
chunkMarkdown: () => chunkMarkdown,
|
|
667
|
+
chunkIssue: () => chunkIssue,
|
|
668
|
+
chunkFile: () => chunkFile,
|
|
669
|
+
chunkDocComments: () => chunkDocComments,
|
|
670
|
+
chunkDecision: () => chunkDecision,
|
|
671
|
+
chunkCodeEntities: () => chunkCodeEntities,
|
|
672
|
+
VectorStore: () => VectorStore,
|
|
673
|
+
EmbeddingManager: () => EmbeddingManager,
|
|
674
|
+
DEFAULT_MODEL_CONFIG: () => DEFAULT_MODEL_CONFIG
|
|
675
|
+
});
|
|
676
|
+
var init_embeddings = __esm(() => {
|
|
677
|
+
init_types();
|
|
678
|
+
init_model();
|
|
679
|
+
init_store();
|
|
680
|
+
init_search();
|
|
681
|
+
init_chunker();
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
export { DEFAULT_MODEL_CONFIG, loadModel, embed, embedBatch, resetModel, VectorStore, cosineSimilarity, chunkIssue, chunkDecision, chunkMilestone, chunkMarkdown, chunkCodeEntities, chunkDocComments, chunkSummary, chunkFile, slidingWindow, EmbeddingManager, exports_embeddings, init_embeddings };
|