trellis 2.0.8 → 2.0.13

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 (42) hide show
  1. package/README.md +279 -116
  2. package/dist/cli/index.js +655 -4
  3. package/dist/core/index.js +471 -2
  4. package/dist/embeddings/index.js +5 -1
  5. package/dist/{index-s603ev6w.js → index-5b01h414.js} +1 -1
  6. package/dist/index-5m0g9r0y.js +1100 -0
  7. package/dist/{index-zf6htvnm.js → index-7gvjxt27.js} +166 -2
  8. package/dist/index-hybgxe40.js +1174 -0
  9. package/dist/index.js +7 -2
  10. package/dist/transformers.node-bx3q9d7k.js +33130 -0
  11. package/package.json +9 -4
  12. package/src/cli/index.ts +939 -0
  13. package/src/core/agents/harness.ts +380 -0
  14. package/src/core/agents/index.ts +18 -0
  15. package/src/core/agents/types.ts +90 -0
  16. package/src/core/index.ts +85 -2
  17. package/src/core/kernel/trellis-kernel.ts +593 -0
  18. package/src/core/ontology/builtins.ts +248 -0
  19. package/src/core/ontology/index.ts +34 -0
  20. package/src/core/ontology/registry.ts +209 -0
  21. package/src/core/ontology/types.ts +124 -0
  22. package/src/core/ontology/validator.ts +382 -0
  23. package/src/core/persist/backend.ts +10 -0
  24. package/src/core/persist/sqlite-backend.ts +298 -0
  25. package/src/core/plugins/index.ts +17 -0
  26. package/src/core/plugins/registry.ts +322 -0
  27. package/src/core/plugins/types.ts +126 -0
  28. package/src/core/query/datalog.ts +188 -0
  29. package/src/core/query/engine.ts +370 -0
  30. package/src/core/query/index.ts +34 -0
  31. package/src/core/query/parser.ts +481 -0
  32. package/src/core/query/types.ts +200 -0
  33. package/src/embeddings/auto-embed.ts +248 -0
  34. package/src/embeddings/index.ts +7 -0
  35. package/src/embeddings/model.ts +21 -4
  36. package/src/embeddings/types.ts +8 -1
  37. package/src/index.ts +9 -0
  38. package/src/sync/http-transport.ts +144 -0
  39. package/src/sync/index.ts +11 -0
  40. package/src/sync/multi-repo.ts +200 -0
  41. package/src/sync/ws-transport.ts +145 -0
  42. package/dist/index-5bhe57y9.js +0 -326
@@ -0,0 +1,1174 @@
1
+ // @bun
2
+ import {
3
+ __esm
4
+ } from "./index-a76rekgs.js";
5
+
6
+ // src/core/store/eav-store.ts
7
+ function* flatten(obj, base = "") {
8
+ if (Array.isArray(obj)) {
9
+ for (const v of obj) {
10
+ yield* flatten(v, base);
11
+ }
12
+ } else if (obj && typeof obj === "object") {
13
+ for (const [k, v] of Object.entries(obj)) {
14
+ yield* flatten(v, base ? `${base}.${k}` : k);
15
+ }
16
+ } else {
17
+ yield [base, obj];
18
+ }
19
+ }
20
+ function jsonEntityFacts(entityId, root, type) {
21
+ const facts = [{ e: entityId, a: "type", v: type }];
22
+ for (const [a, v] of flatten(root)) {
23
+ if (v === undefined || v === null)
24
+ continue;
25
+ if (Array.isArray(v)) {
26
+ for (const el of v) {
27
+ facts.push({ e: entityId, a, v: el });
28
+ }
29
+ } else if (typeof v === "object") {} else {
30
+ facts.push({ e: entityId, a, v });
31
+ }
32
+ }
33
+ return facts;
34
+ }
35
+
36
+ class EAVStore {
37
+ facts = [];
38
+ links = [];
39
+ catalog = new Map;
40
+ eavIndex = new Map;
41
+ aevIndex = new Map;
42
+ aveIndex = new Map;
43
+ linkIndex = new Map;
44
+ linkReverseIndex = new Map;
45
+ linkAttrIndex = new Map;
46
+ distinct = new Map;
47
+ addFacts(facts) {
48
+ for (let i = 0;i < facts.length; i++) {
49
+ const fact = facts[i];
50
+ if (fact) {
51
+ this.facts.push(fact);
52
+ this.updateIndexes(fact, this.facts.length - 1);
53
+ this.updateCatalog(fact);
54
+ }
55
+ }
56
+ }
57
+ addLinks(links) {
58
+ for (const link of links) {
59
+ this.links.push(link);
60
+ this.updateLinkIndexes(link);
61
+ }
62
+ }
63
+ deleteFacts(factsToDelete) {
64
+ for (const fact of factsToDelete) {
65
+ const valueKey = this.valueKey(fact.v);
66
+ const indices = this.aveIndex.get(fact.a)?.get(valueKey);
67
+ if (!indices)
68
+ continue;
69
+ let foundIdx = -1;
70
+ for (const idx of indices) {
71
+ const storedFact = this.facts[idx];
72
+ if (storedFact && storedFact.e === fact.e && storedFact.a === fact.a) {
73
+ foundIdx = idx;
74
+ break;
75
+ }
76
+ }
77
+ if (foundIdx !== -1) {
78
+ this.facts[foundIdx] = undefined;
79
+ this.eavIndex.get(fact.e)?.get(fact.a)?.delete(foundIdx);
80
+ this.aevIndex.get(fact.a)?.get(fact.e)?.delete(foundIdx);
81
+ this.aveIndex.get(fact.a)?.get(valueKey)?.delete(foundIdx);
82
+ const entry = this.catalog.get(fact.a);
83
+ if (entry) {}
84
+ }
85
+ }
86
+ }
87
+ deleteLinks(linksToDelete) {
88
+ for (const link of linksToDelete) {
89
+ const initialLen = this.links.length;
90
+ this.links = this.links.filter((l) => !(l.e1 === link.e1 && l.a === link.a && l.e2 === link.e2));
91
+ if (this.links.length < initialLen) {
92
+ this.linkIndex.get(link.e1)?.get(link.a)?.delete(link.e2);
93
+ this.linkReverseIndex.get(link.e2)?.get(link.a)?.delete(link.e1);
94
+ const attrPairs = this.linkAttrIndex.get(link.a);
95
+ if (attrPairs) {
96
+ for (const pair of attrPairs) {
97
+ if (pair[0] === link.e1 && pair[1] === link.e2) {
98
+ attrPairs.delete(pair);
99
+ break;
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ updateIndexes(fact, index) {
107
+ if (!this.eavIndex.has(fact.e)) {
108
+ this.eavIndex.set(fact.e, new Map);
109
+ }
110
+ if (!this.eavIndex.get(fact.e).has(fact.a)) {
111
+ this.eavIndex.get(fact.e).set(fact.a, new Set);
112
+ }
113
+ this.eavIndex.get(fact.e).get(fact.a).add(index);
114
+ if (!this.aevIndex.has(fact.a)) {
115
+ this.aevIndex.set(fact.a, new Map);
116
+ }
117
+ if (!this.aevIndex.get(fact.a).has(fact.e)) {
118
+ this.aevIndex.get(fact.a).set(fact.e, new Set);
119
+ }
120
+ this.aevIndex.get(fact.a).get(fact.e).add(index);
121
+ if (!this.aveIndex.has(fact.a)) {
122
+ this.aveIndex.set(fact.a, new Map);
123
+ }
124
+ const valueKey = this.valueKey(fact.v);
125
+ if (!this.aveIndex.get(fact.a).has(valueKey)) {
126
+ this.aveIndex.get(fact.a).set(valueKey, new Set);
127
+ }
128
+ this.aveIndex.get(fact.a).get(valueKey).add(index);
129
+ }
130
+ updateLinkIndexes(link) {
131
+ if (!this.linkIndex.has(link.e1)) {
132
+ this.linkIndex.set(link.e1, new Map);
133
+ }
134
+ const e1Attrs = this.linkIndex.get(link.e1);
135
+ if (!e1Attrs.has(link.a)) {
136
+ e1Attrs.set(link.a, new Set);
137
+ }
138
+ e1Attrs.get(link.a).add(link.e2);
139
+ if (!this.linkReverseIndex.has(link.e2)) {
140
+ this.linkReverseIndex.set(link.e2, new Map);
141
+ }
142
+ const e2Attrs = this.linkReverseIndex.get(link.e2);
143
+ if (!e2Attrs.has(link.a)) {
144
+ e2Attrs.set(link.a, new Set);
145
+ }
146
+ e2Attrs.get(link.a).add(link.e1);
147
+ if (!this.linkAttrIndex.has(link.a)) {
148
+ this.linkAttrIndex.set(link.a, new Set);
149
+ }
150
+ this.linkAttrIndex.get(link.a).add([link.e1, link.e2]);
151
+ }
152
+ valueKey(v) {
153
+ if (v instanceof Date)
154
+ return `date:${v.toISOString()}`;
155
+ return `${typeof v}:${v}`;
156
+ }
157
+ updateCatalog(fact) {
158
+ const entry = this.catalog.get(fact.a) || {
159
+ attribute: fact.a,
160
+ type: this.inferType(fact.v),
161
+ cardinality: "one",
162
+ distinctCount: 0,
163
+ examples: []
164
+ };
165
+ const factType = this.inferType(fact.v);
166
+ if (entry.type !== factType && entry.type !== "mixed") {
167
+ entry.type = "mixed";
168
+ }
169
+ const entityAttrs = this.eavIndex.get(fact.e)?.get(fact.a);
170
+ if (entityAttrs && entityAttrs.size > 1) {
171
+ entry.cardinality = "many";
172
+ }
173
+ const k = this.valueKey(fact.v);
174
+ const s = this.distinct.get(fact.a) || (this.distinct.set(fact.a, new Set), this.distinct.get(fact.a));
175
+ s.add(k);
176
+ entry.distinctCount = s.size;
177
+ if (entry.examples.length < 5 && !entry.examples.includes(fact.v)) {
178
+ entry.examples.push(fact.v);
179
+ }
180
+ if (typeof fact.v === "number") {
181
+ entry.min = Math.min(entry.min ?? fact.v, fact.v);
182
+ entry.max = Math.max(entry.max ?? fact.v, fact.v);
183
+ }
184
+ this.catalog.set(fact.a, entry);
185
+ }
186
+ inferType(v) {
187
+ if (typeof v === "string")
188
+ return "string";
189
+ if (typeof v === "number")
190
+ return "number";
191
+ if (typeof v === "boolean")
192
+ return "boolean";
193
+ if (v instanceof Date)
194
+ return "date";
195
+ return "mixed";
196
+ }
197
+ getFactsByEntity(entity) {
198
+ const indices = this.eavIndex.get(entity);
199
+ if (!indices)
200
+ return [];
201
+ const result = [];
202
+ for (const attrIndices of indices.values()) {
203
+ for (const idx of attrIndices) {
204
+ const fact = this.facts[idx];
205
+ if (fact) {
206
+ result.push(fact);
207
+ }
208
+ }
209
+ }
210
+ return result;
211
+ }
212
+ getFactsByAttribute(attribute) {
213
+ const indices = this.aevIndex.get(attribute);
214
+ if (!indices)
215
+ return [];
216
+ const result = [];
217
+ for (const entityIndices of indices.values()) {
218
+ for (const idx of entityIndices) {
219
+ const fact = this.facts[idx];
220
+ if (fact) {
221
+ result.push(fact);
222
+ }
223
+ }
224
+ }
225
+ return result;
226
+ }
227
+ getFactsByValue(attribute, value) {
228
+ const indices = this.aveIndex.get(attribute)?.get(this.valueKey(value));
229
+ if (!indices)
230
+ return [];
231
+ return Array.from(indices).map((idx) => this.facts[idx]).filter((fact) => fact !== undefined);
232
+ }
233
+ getCatalog() {
234
+ return Array.from(this.catalog.values());
235
+ }
236
+ getCatalogEntry(attribute) {
237
+ return this.catalog.get(attribute);
238
+ }
239
+ getAllFacts() {
240
+ return this.facts.filter((f) => f !== undefined);
241
+ }
242
+ getAllLinks() {
243
+ return [...this.links];
244
+ }
245
+ getLinksByEntity(entity) {
246
+ const results = [];
247
+ const forwardLinks = this.linkIndex.get(entity);
248
+ if (forwardLinks) {
249
+ for (const [attr, targets] of forwardLinks) {
250
+ for (const target of targets) {
251
+ results.push({ e1: entity, a: attr, e2: target });
252
+ }
253
+ }
254
+ }
255
+ const reverseLinks = this.linkReverseIndex.get(entity);
256
+ if (reverseLinks) {
257
+ for (const [attr, sources] of reverseLinks) {
258
+ for (const source of sources) {
259
+ results.push({ e1: source, a: attr, e2: entity });
260
+ }
261
+ }
262
+ }
263
+ return results;
264
+ }
265
+ getLinksByAttribute(attribute) {
266
+ const results = [];
267
+ const links = this.linkAttrIndex.get(attribute);
268
+ if (links) {
269
+ for (const [e1, e2] of links) {
270
+ results.push({ e1, a: attribute, e2 });
271
+ }
272
+ }
273
+ return results;
274
+ }
275
+ getLinksByEntityAndAttribute(entity, attribute) {
276
+ const results = [];
277
+ const attrs = this.linkIndex.get(entity);
278
+ if (attrs) {
279
+ const targets = attrs.get(attribute);
280
+ if (targets) {
281
+ for (const target of targets) {
282
+ results.push({ e1: entity, a: attribute, e2: target });
283
+ }
284
+ }
285
+ }
286
+ return results;
287
+ }
288
+ getStats() {
289
+ return {
290
+ totalFacts: this.facts.length,
291
+ totalLinks: this.links.length,
292
+ uniqueEntities: this.eavIndex.size,
293
+ uniqueAttributes: this.aevIndex.size,
294
+ catalogEntries: this.catalog.size
295
+ };
296
+ }
297
+ snapshot() {
298
+ return {
299
+ facts: this.facts.filter((f) => f !== undefined),
300
+ links: [...this.links],
301
+ catalog: this.getCatalog()
302
+ };
303
+ }
304
+ restore(snapshot) {
305
+ this.facts = [];
306
+ this.links = [];
307
+ this.catalog.clear();
308
+ this.eavIndex.clear();
309
+ this.aevIndex.clear();
310
+ this.aveIndex.clear();
311
+ this.linkIndex.clear();
312
+ this.linkReverseIndex.clear();
313
+ this.linkAttrIndex.clear();
314
+ this.distinct.clear();
315
+ this.addFacts(snapshot.facts);
316
+ this.addLinks(snapshot.links);
317
+ if (snapshot.catalog) {
318
+ for (const entry of snapshot.catalog) {
319
+ this.catalog.set(entry.attribute, entry);
320
+ }
321
+ }
322
+ }
323
+ }
324
+ var init_eav_store = () => {};
325
+
326
+ // src/core/query/types.ts
327
+ function isVariable(t) {
328
+ return t.kind === "variable";
329
+ }
330
+ function isLiteral(t) {
331
+ return t.kind === "literal";
332
+ }
333
+ function variable(name) {
334
+ return { kind: "variable", name };
335
+ }
336
+ function literal(value) {
337
+ return { kind: "literal", value };
338
+ }
339
+
340
+ // src/core/query/engine.ts
341
+ class QueryEngine {
342
+ store;
343
+ rules = new Map;
344
+ maxRuleDepth = 32;
345
+ constructor(store) {
346
+ this.store = store;
347
+ }
348
+ addRule(rule) {
349
+ const existing = this.rules.get(rule.name) ?? [];
350
+ existing.push(rule);
351
+ this.rules.set(rule.name, existing);
352
+ }
353
+ removeRule(name) {
354
+ this.rules.delete(name);
355
+ }
356
+ execute(query) {
357
+ const start = performance.now();
358
+ let results = this._evaluatePatterns(query.where, [new Map]);
359
+ for (const filter of query.filters) {
360
+ results = results.filter((b) => this._evalFilter(filter, b));
361
+ }
362
+ if (query.aggregates.length > 0) {
363
+ results = this._aggregate(results, query.aggregates, query.select);
364
+ }
365
+ if (query.orderBy.length > 0) {
366
+ results = this._order(results, query.orderBy);
367
+ }
368
+ if (query.offset > 0)
369
+ results = results.slice(query.offset);
370
+ if (query.limit > 0)
371
+ results = results.slice(0, query.limit);
372
+ const projected = this._project(results, query.select);
373
+ return {
374
+ bindings: projected,
375
+ executionTime: performance.now() - start,
376
+ count: projected.length
377
+ };
378
+ }
379
+ _evaluatePatterns(patterns, bindings) {
380
+ let current = bindings;
381
+ for (const pattern of patterns) {
382
+ if (current.length === 0)
383
+ break;
384
+ current = this._evaluatePattern(pattern, current);
385
+ }
386
+ return current;
387
+ }
388
+ _evaluatePattern(pattern, bindings) {
389
+ switch (pattern.kind) {
390
+ case "fact":
391
+ return this._evalFactPattern(pattern, bindings);
392
+ case "link":
393
+ return this._evalLinkPattern(pattern, bindings);
394
+ case "not":
395
+ return this._evalNotPattern(pattern, bindings);
396
+ case "or":
397
+ return this._evalOrPattern(pattern, bindings);
398
+ case "rule":
399
+ return this._evalRuleApplication(pattern, bindings);
400
+ }
401
+ }
402
+ _evalFactPattern(p, bindings) {
403
+ const results = [];
404
+ for (const b of bindings) {
405
+ const eResolved = this._resolve(p.entity, b);
406
+ const aResolved = this._resolve(p.attribute, b);
407
+ const vResolved = this._resolve(p.value, b);
408
+ let facts;
409
+ if (eResolved !== undefined && aResolved !== undefined) {
410
+ facts = this.store.getFactsByEntity(String(eResolved)).filter((f) => f.a === aResolved);
411
+ } else if (eResolved !== undefined) {
412
+ facts = this.store.getFactsByEntity(String(eResolved));
413
+ } else if (aResolved !== undefined && vResolved !== undefined) {
414
+ facts = this.store.getFactsByValue(String(aResolved), vResolved);
415
+ } else if (aResolved !== undefined) {
416
+ facts = this.store.getFactsByAttribute(String(aResolved));
417
+ } else {
418
+ facts = this.store.getAllFacts();
419
+ }
420
+ if (vResolved !== undefined) {
421
+ facts = facts.filter((f) => f.v === vResolved);
422
+ }
423
+ for (const fact of facts) {
424
+ const nb = new Map(b);
425
+ if (this._bind(p.entity, fact.e, nb) && this._bind(p.attribute, fact.a, nb) && this._bind(p.value, fact.v, nb)) {
426
+ results.push(nb);
427
+ }
428
+ }
429
+ }
430
+ return results;
431
+ }
432
+ _evalLinkPattern(p, bindings) {
433
+ const results = [];
434
+ for (const b of bindings) {
435
+ const srcResolved = this._resolve(p.source, b);
436
+ const attrResolved = this._resolve(p.attribute, b);
437
+ const tgtResolved = this._resolve(p.target, b);
438
+ let links;
439
+ if (srcResolved !== undefined && attrResolved !== undefined) {
440
+ links = this.store.getLinksByEntityAndAttribute(String(srcResolved), String(attrResolved));
441
+ } else if (srcResolved !== undefined) {
442
+ links = this.store.getLinksByEntity(String(srcResolved));
443
+ } else if (attrResolved !== undefined) {
444
+ links = this.store.getLinksByAttribute(String(attrResolved));
445
+ } else {
446
+ links = this.store.getAllLinks();
447
+ }
448
+ if (tgtResolved !== undefined) {
449
+ links = links.filter((l) => l.e2 === tgtResolved);
450
+ }
451
+ for (const link of links) {
452
+ const nb = new Map(b);
453
+ if (this._bind(p.source, link.e1, nb) && this._bind(p.attribute, link.a, nb) && this._bind(p.target, link.e2, nb)) {
454
+ results.push(nb);
455
+ }
456
+ }
457
+ }
458
+ return results;
459
+ }
460
+ _evalNotPattern(p, bindings) {
461
+ return bindings.filter((b) => {
462
+ const matches = this._evaluatePattern(p.pattern, [b]);
463
+ return matches.length === 0;
464
+ });
465
+ }
466
+ _evalOrPattern(p, bindings) {
467
+ const results = [];
468
+ for (const branch of p.branches) {
469
+ const branchResults = this._evaluatePatterns(branch, bindings);
470
+ results.push(...branchResults);
471
+ }
472
+ return this._dedup(results);
473
+ }
474
+ _evalRuleApplication(p, bindings, depth = 0) {
475
+ if (depth > this.maxRuleDepth)
476
+ return [];
477
+ const ruleDefs = this.rules.get(p.name);
478
+ if (!ruleDefs)
479
+ return [];
480
+ const results = [];
481
+ for (const b of bindings) {
482
+ for (const rule of ruleDefs) {
483
+ const ruleBindings = new Map(b);
484
+ let ok = true;
485
+ for (let i = 0;i < rule.params.length && i < p.args.length; i++) {
486
+ const resolved = this._resolve(p.args[i], b);
487
+ if (resolved !== undefined) {
488
+ ruleBindings.set(rule.params[i], resolved);
489
+ } else if (isVariable(p.args[i])) {}
490
+ }
491
+ if (!ok)
492
+ continue;
493
+ let bodyResults = this._evaluatePatterns(rule.body, [ruleBindings]);
494
+ for (const f of rule.filters) {
495
+ bodyResults = bodyResults.filter((rb) => this._evalFilter(f, rb));
496
+ }
497
+ for (const rb of bodyResults) {
498
+ const nb = new Map(b);
499
+ for (let i = 0;i < rule.params.length && i < p.args.length; i++) {
500
+ if (isVariable(p.args[i])) {
501
+ const val = rb.get(rule.params[i]);
502
+ if (val !== undefined)
503
+ nb.set(p.args[i].name, val);
504
+ }
505
+ }
506
+ results.push(nb);
507
+ }
508
+ }
509
+ }
510
+ return this._dedup(results);
511
+ }
512
+ _evalFilter(filter, b) {
513
+ const left = this._resolve(filter.left, b);
514
+ const right = this._resolve(filter.right, b);
515
+ if (left === undefined || right === undefined)
516
+ return false;
517
+ switch (filter.op) {
518
+ case "=":
519
+ return left === right;
520
+ case "!=":
521
+ return left !== right;
522
+ case "<":
523
+ return left < right;
524
+ case "<=":
525
+ return left <= right;
526
+ case ">":
527
+ return left > right;
528
+ case ">=":
529
+ return left >= right;
530
+ case "contains":
531
+ return String(left).includes(String(right));
532
+ case "startsWith":
533
+ return String(left).startsWith(String(right));
534
+ case "endsWith":
535
+ return String(left).endsWith(String(right));
536
+ case "matches":
537
+ return new RegExp(String(right)).test(String(left));
538
+ default:
539
+ return false;
540
+ }
541
+ }
542
+ _aggregate(bindings, aggregates, groupBy) {
543
+ const aggVarNames = new Set(aggregates.map((a) => a.as));
544
+ const groupVars = groupBy.filter((v) => !aggVarNames.has(v));
545
+ const groups = new Map;
546
+ for (const b of bindings) {
547
+ const key = groupVars.map((v) => String(b.get(v) ?? "")).join("\x00");
548
+ const group = groups.get(key) ?? [];
549
+ group.push(b);
550
+ groups.set(key, group);
551
+ }
552
+ const results = [];
553
+ for (const [, group] of groups) {
554
+ const nb = new Map(group[0]);
555
+ for (const agg of aggregates) {
556
+ const vals = group.map((b) => b.get(agg.variable)).filter((v) => v !== undefined);
557
+ nb.set(agg.as, this._computeAggregate(agg.op, vals));
558
+ }
559
+ results.push(nb);
560
+ }
561
+ return results;
562
+ }
563
+ _computeAggregate(op, vals) {
564
+ switch (op) {
565
+ case "count":
566
+ return vals.length;
567
+ case "sum":
568
+ return vals.reduce((s, v) => s + (Number(v) || 0), 0);
569
+ case "avg":
570
+ return vals.length ? vals.reduce((s, v) => s + (Number(v) || 0), 0) / vals.length : 0;
571
+ case "min":
572
+ return vals.reduce((m, v) => v < m ? v : m, vals[0]);
573
+ case "max":
574
+ return vals.reduce((m, v) => v > m ? v : m, vals[0]);
575
+ case "collect":
576
+ return JSON.stringify(vals);
577
+ default:
578
+ return vals.length;
579
+ }
580
+ }
581
+ _order(bindings, orderBy) {
582
+ return [...bindings].sort((a, b) => {
583
+ for (const o of orderBy) {
584
+ const va = a.get(o.variable);
585
+ const vb = b.get(o.variable);
586
+ if (va === vb)
587
+ continue;
588
+ if (va === undefined)
589
+ return 1;
590
+ if (vb === undefined)
591
+ return -1;
592
+ const cmp = va < vb ? -1 : 1;
593
+ return o.direction === "asc" ? cmp : -cmp;
594
+ }
595
+ return 0;
596
+ });
597
+ }
598
+ _project(bindings, select) {
599
+ return bindings.map((b) => {
600
+ const row = {};
601
+ if (select.length === 0) {
602
+ for (const [k, v] of b)
603
+ row[k] = v;
604
+ } else {
605
+ for (const s of select) {
606
+ const v = b.get(s);
607
+ if (v !== undefined)
608
+ row[s] = v;
609
+ }
610
+ }
611
+ return row;
612
+ });
613
+ }
614
+ _resolve(term, bindings) {
615
+ if (isLiteral(term))
616
+ return term.value;
617
+ return bindings.get(term.name);
618
+ }
619
+ _bind(term, value, bindings) {
620
+ if (isLiteral(term))
621
+ return term.value === value;
622
+ const existing = bindings.get(term.name);
623
+ if (existing !== undefined)
624
+ return existing === value;
625
+ bindings.set(term.name, value);
626
+ return true;
627
+ }
628
+ _dedup(bindings) {
629
+ const seen = new Set;
630
+ return bindings.filter((b) => {
631
+ const key = [...b.entries()].sort(([a], [b2]) => a.localeCompare(b2)).map(([k, v]) => `${k}=${v}`).join("\x00");
632
+ if (seen.has(key))
633
+ return false;
634
+ seen.add(key);
635
+ return true;
636
+ });
637
+ }
638
+ }
639
+
640
+ // src/core/kernel/trellis-kernel.ts
641
+ init_eav_store();
642
+ async function hashOp(kind, timestamp, agentId, previousHash, payload) {
643
+ const data = `${kind}|${timestamp}|${agentId}|${previousHash ?? ""}|${payload}`;
644
+ const buf = new TextEncoder().encode(data);
645
+ const hashBuf = await crypto.subtle.digest("SHA-256", buf);
646
+ const hex = Array.from(new Uint8Array(hashBuf)).map((b) => b.toString(16).padStart(2, "0")).join("");
647
+ return `trellis:op:${hex}`;
648
+ }
649
+
650
+ class TrellisKernel {
651
+ store;
652
+ backend;
653
+ middleware;
654
+ agentId;
655
+ snapshotThreshold;
656
+ opsSinceSnapshot = 0;
657
+ _booted = false;
658
+ constructor(config) {
659
+ this.store = new EAVStore;
660
+ this.backend = config.backend;
661
+ this.agentId = config.agentId;
662
+ this.middleware = config.middleware ?? [];
663
+ this.snapshotThreshold = config.snapshotThreshold ?? 0;
664
+ }
665
+ boot() {
666
+ this.backend.init();
667
+ let opsReplayed = 0;
668
+ let fromSnapshot = false;
669
+ const snapshot = this.backend.loadLatestSnapshot();
670
+ if (snapshot) {
671
+ this.store.restore(snapshot.data);
672
+ fromSnapshot = true;
673
+ const recentOps = this.backend.readAfter(snapshot.lastOpHash);
674
+ for (const op of recentOps) {
675
+ this._replayOp(op);
676
+ opsReplayed++;
677
+ }
678
+ } else {
679
+ const allOps = this.backend.readAll();
680
+ for (const op of allOps) {
681
+ this._replayOp(op);
682
+ opsReplayed++;
683
+ }
684
+ }
685
+ this._booted = true;
686
+ return { opsReplayed, fromSnapshot };
687
+ }
688
+ close() {
689
+ this.backend.close?.();
690
+ this._booted = false;
691
+ }
692
+ isBooted() {
693
+ return this._booted;
694
+ }
695
+ async mutate(kind, payload, ctx) {
696
+ const timestamp = new Date().toISOString();
697
+ const lastOp = this.backend.getLastOp();
698
+ const agentId = ctx?.agentId ?? this.agentId;
699
+ const payloadStr = JSON.stringify(payload);
700
+ const hash = await hashOp(kind, timestamp, agentId, lastOp?.hash, payloadStr);
701
+ const op = {
702
+ hash,
703
+ kind,
704
+ timestamp,
705
+ agentId,
706
+ previousHash: lastOp?.hash,
707
+ facts: [...payload.facts ?? []],
708
+ links: [...payload.links ?? []],
709
+ deleteFacts: payload.deleteFacts?.length ? [...payload.deleteFacts] : undefined,
710
+ deleteLinks: payload.deleteLinks?.length ? [...payload.deleteLinks] : undefined
711
+ };
712
+ const extOp = op;
713
+ if (payload.meta) {
714
+ for (const [k, v] of Object.entries(payload.meta)) {
715
+ extOp[k] = v;
716
+ }
717
+ }
718
+ const mwCtx = { agentId, ...ctx };
719
+ await this._runMiddleware(op, mwCtx);
720
+ let factsAdded = 0;
721
+ let factsDeleted = 0;
722
+ let linksAdded = 0;
723
+ let linksDeleted = 0;
724
+ if (payload.deleteFacts && payload.deleteFacts.length > 0) {
725
+ this.store.deleteFacts(payload.deleteFacts);
726
+ factsDeleted = payload.deleteFacts.length;
727
+ }
728
+ if (payload.deleteLinks && payload.deleteLinks.length > 0) {
729
+ this.store.deleteLinks(payload.deleteLinks);
730
+ linksDeleted = payload.deleteLinks.length;
731
+ }
732
+ if (payload.facts && payload.facts.length > 0) {
733
+ this.store.addFacts(payload.facts);
734
+ factsAdded = payload.facts.length;
735
+ }
736
+ if (payload.links && payload.links.length > 0) {
737
+ this.store.addLinks(payload.links);
738
+ linksAdded = payload.links.length;
739
+ }
740
+ this.backend.append(op);
741
+ this.opsSinceSnapshot++;
742
+ if (this.snapshotThreshold > 0 && this.opsSinceSnapshot >= this.snapshotThreshold) {
743
+ this.checkpoint();
744
+ }
745
+ return {
746
+ op,
747
+ factsDelta: { added: factsAdded, deleted: factsDeleted },
748
+ linksDelta: { added: linksAdded, deleted: linksDeleted }
749
+ };
750
+ }
751
+ checkpoint() {
752
+ const lastOp = this.backend.getLastOp();
753
+ if (!lastOp)
754
+ return;
755
+ this.backend.saveSnapshot(lastOp.hash, this.store.snapshot());
756
+ this.opsSinceSnapshot = 0;
757
+ }
758
+ getStore() {
759
+ return this.store;
760
+ }
761
+ getBackend() {
762
+ return this.backend;
763
+ }
764
+ getAgentId() {
765
+ return this.agentId;
766
+ }
767
+ readAllOps() {
768
+ return this.backend.readAll();
769
+ }
770
+ getLastOp() {
771
+ return this.backend.getLastOp();
772
+ }
773
+ createQueryEngine() {
774
+ return new QueryEngine(this.store);
775
+ }
776
+ async query(q) {
777
+ const engine = new QueryEngine(this.store);
778
+ const ctx = { agentId: this.agentId };
779
+ const chain = this.middleware.filter((m) => m.handleQuery);
780
+ if (chain.length === 0) {
781
+ return engine.execute(q);
782
+ }
783
+ let result;
784
+ let idx = 0;
785
+ const next = (query, context) => {
786
+ if (idx < chain.length) {
787
+ const mw = chain[idx++];
788
+ return mw.handleQuery(query, context, next);
789
+ }
790
+ result = engine.execute(query);
791
+ return result;
792
+ };
793
+ result = next(q, ctx);
794
+ return result;
795
+ }
796
+ timeTravel(opHash) {
797
+ const ops = this.backend.readUntil(opHash);
798
+ const snapshot = new EAVStore;
799
+ for (const op of ops) {
800
+ if (op.deleteFacts && op.deleteFacts.length > 0) {
801
+ snapshot.deleteFacts(op.deleteFacts);
802
+ }
803
+ if (op.deleteLinks && op.deleteLinks.length > 0) {
804
+ snapshot.deleteLinks(op.deleteLinks);
805
+ }
806
+ if (op.facts && op.facts.length > 0) {
807
+ snapshot.addFacts(op.facts);
808
+ }
809
+ if (op.links && op.links.length > 0) {
810
+ snapshot.addLinks(op.links);
811
+ }
812
+ }
813
+ return snapshot;
814
+ }
815
+ async createEntity(entityId, type, attributes = {}, links) {
816
+ const facts = [
817
+ { e: entityId, a: "type", v: type },
818
+ { e: entityId, a: "createdAt", v: new Date().toISOString() }
819
+ ];
820
+ for (const [attr, value] of Object.entries(attributes)) {
821
+ facts.push({ e: entityId, a: attr, v: value });
822
+ }
823
+ const linkRecords = (links ?? []).map((l) => ({
824
+ e1: entityId,
825
+ a: l.attribute,
826
+ e2: l.targetEntityId
827
+ }));
828
+ return this.mutate("addFacts", {
829
+ facts,
830
+ links: linkRecords.length > 0 ? linkRecords : undefined
831
+ });
832
+ }
833
+ getEntity(entityId) {
834
+ const facts = this.store.getFactsByEntity(entityId);
835
+ if (facts.length === 0)
836
+ return null;
837
+ const typeFact = facts.find((f) => f.a === "type");
838
+ return {
839
+ id: entityId,
840
+ type: typeFact?.v ?? "unknown",
841
+ facts,
842
+ links: this.store.getLinksByEntity(entityId)
843
+ };
844
+ }
845
+ async updateEntity(entityId, updates) {
846
+ const existingFacts = this.store.getFactsByEntity(entityId);
847
+ const deleteFacts = [];
848
+ const addFacts = [];
849
+ for (const [attr, newValue] of Object.entries(updates)) {
850
+ const existing = existingFacts.filter((f) => f.a === attr);
851
+ deleteFacts.push(...existing);
852
+ addFacts.push({ e: entityId, a: attr, v: newValue });
853
+ }
854
+ const updatedAtFacts = existingFacts.filter((f) => f.a === "updatedAt");
855
+ deleteFacts.push(...updatedAtFacts);
856
+ addFacts.push({ e: entityId, a: "updatedAt", v: new Date().toISOString() });
857
+ return this.mutate("addFacts", {
858
+ facts: addFacts,
859
+ deleteFacts
860
+ });
861
+ }
862
+ async deleteEntity(entityId) {
863
+ const facts = this.store.getFactsByEntity(entityId);
864
+ const links = this.store.getLinksByEntity(entityId);
865
+ return this.mutate("deleteFacts", {
866
+ deleteFacts: facts,
867
+ deleteLinks: links
868
+ });
869
+ }
870
+ listEntities(type, filters) {
871
+ let entityIds;
872
+ if (type) {
873
+ const typeFacts = this.store.getFactsByValue("type", type);
874
+ entityIds = new Set(typeFacts.map((f) => f.e));
875
+ } else {
876
+ const allTypeFacts = this.store.getFactsByAttribute("type");
877
+ entityIds = new Set(allTypeFacts.map((f) => f.e));
878
+ }
879
+ if (filters) {
880
+ for (const [attr, value] of Object.entries(filters)) {
881
+ const matchingFacts = this.store.getFactsByValue(attr, value);
882
+ const matchingEntities = new Set(matchingFacts.map((f) => f.e));
883
+ for (const id of entityIds) {
884
+ if (!matchingEntities.has(id)) {
885
+ entityIds.delete(id);
886
+ }
887
+ }
888
+ }
889
+ }
890
+ return Array.from(entityIds).map((id) => this.getEntity(id)).filter(Boolean);
891
+ }
892
+ async addLink(sourceId, attribute, targetId) {
893
+ return this.mutate("addLinks", {
894
+ links: [{ e1: sourceId, a: attribute, e2: targetId }]
895
+ });
896
+ }
897
+ async removeLink(sourceId, attribute, targetId) {
898
+ return this.mutate("deleteLinks", {
899
+ deleteLinks: [{ e1: sourceId, a: attribute, e2: targetId }]
900
+ });
901
+ }
902
+ async addFact(entityId, attribute, value) {
903
+ return this.mutate("addFacts", {
904
+ facts: [{ e: entityId, a: attribute, v: value }]
905
+ });
906
+ }
907
+ async removeFact(entityId, attribute, value) {
908
+ return this.mutate("deleteFacts", {
909
+ deleteFacts: [{ e: entityId, a: attribute, v: value }]
910
+ });
911
+ }
912
+ addMiddleware(mw) {
913
+ this.middleware.push(mw);
914
+ }
915
+ removeMiddleware(name) {
916
+ this.middleware = this.middleware.filter((m) => m.name !== name);
917
+ }
918
+ async _runMiddleware(op, ctx) {
919
+ const chain = [...this.middleware];
920
+ let idx = 0;
921
+ const next = async (op2, ctx2) => {
922
+ const mw = chain[idx++];
923
+ if (mw?.handleOp) {
924
+ await mw.handleOp(op2, ctx2, next);
925
+ }
926
+ };
927
+ if (chain.length > 0) {
928
+ await next(op, ctx);
929
+ }
930
+ }
931
+ _replayOp(op) {
932
+ if (op.deleteFacts && op.deleteFacts.length > 0) {
933
+ this.store.deleteFacts(op.deleteFacts);
934
+ }
935
+ if (op.deleteLinks && op.deleteLinks.length > 0) {
936
+ this.store.deleteLinks(op.deleteLinks);
937
+ }
938
+ if (op.facts && op.facts.length > 0) {
939
+ this.store.addFacts(op.facts);
940
+ }
941
+ if (op.links && op.links.length > 0) {
942
+ this.store.addLinks(op.links);
943
+ }
944
+ }
945
+ }
946
+
947
+ // src/core/persist/sqlite-backend.ts
948
+ import { Database } from "bun:sqlite";
949
+ var SCHEMA_SQL = `
950
+ CREATE TABLE IF NOT EXISTS ops (
951
+ hash TEXT PRIMARY KEY,
952
+ kind TEXT NOT NULL,
953
+ timestamp TEXT NOT NULL,
954
+ agent_id TEXT NOT NULL,
955
+ previous_hash TEXT,
956
+ payload TEXT NOT NULL
957
+ );
958
+
959
+ CREATE TABLE IF NOT EXISTS snapshots (
960
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
961
+ last_op_hash TEXT NOT NULL,
962
+ data TEXT NOT NULL,
963
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
964
+ );
965
+
966
+ CREATE TABLE IF NOT EXISTS blobs (
967
+ hash TEXT PRIMARY KEY,
968
+ content BLOB NOT NULL
969
+ );
970
+
971
+ CREATE INDEX IF NOT EXISTS idx_ops_kind ON ops(kind);
972
+ CREATE INDEX IF NOT EXISTS idx_ops_timestamp ON ops(timestamp);
973
+ CREATE INDEX IF NOT EXISTS idx_ops_agent ON ops(agent_id);
974
+ CREATE INDEX IF NOT EXISTS idx_ops_previous ON ops(previous_hash);
975
+ CREATE INDEX IF NOT EXISTS idx_snapshots_op ON snapshots(last_op_hash);
976
+ `;
977
+
978
+ class SqliteKernelBackend {
979
+ dbPath;
980
+ db;
981
+ _stmts = null;
982
+ constructor(dbPath) {
983
+ this.dbPath = dbPath;
984
+ this.db = new Database(dbPath);
985
+ }
986
+ init() {
987
+ this.db.exec("PRAGMA journal_mode=WAL;");
988
+ this.db.exec("PRAGMA foreign_keys=ON;");
989
+ this.db.exec("PRAGMA synchronous=NORMAL;");
990
+ this.db.exec(SCHEMA_SQL);
991
+ this._prepareStatements();
992
+ }
993
+ _prepareStatements() {
994
+ this._stmts = {
995
+ insert: this.db.prepare(`
996
+ INSERT OR IGNORE INTO ops (hash, kind, timestamp, agent_id, previous_hash, payload)
997
+ VALUES ($hash, $kind, $timestamp, $agentId, $previousHash, $payload)
998
+ `),
999
+ readAll: this.db.prepare(`
1000
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
1001
+ FROM ops ORDER BY rowid ASC
1002
+ `),
1003
+ readUntil: this.db.prepare(`
1004
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
1005
+ FROM ops WHERE rowid <= (SELECT rowid FROM ops WHERE hash = $hash)
1006
+ ORDER BY rowid ASC
1007
+ `),
1008
+ readAfter: this.db.prepare(`
1009
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
1010
+ FROM ops WHERE rowid > (SELECT rowid FROM ops WHERE hash = $hash)
1011
+ ORDER BY rowid ASC
1012
+ `),
1013
+ getByHash: this.db.prepare(`
1014
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
1015
+ FROM ops WHERE hash = $hash
1016
+ `),
1017
+ getLast: this.db.prepare(`
1018
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
1019
+ FROM ops ORDER BY rowid DESC LIMIT 1
1020
+ `),
1021
+ count: this.db.prepare("SELECT COUNT(*) as cnt FROM ops"),
1022
+ saveSnapshot: this.db.prepare(`
1023
+ INSERT INTO snapshots (last_op_hash, data)
1024
+ VALUES ($lastOpHash, $data)
1025
+ `),
1026
+ loadSnapshot: this.db.prepare(`
1027
+ SELECT last_op_hash, data FROM snapshots
1028
+ ORDER BY id DESC LIMIT 1
1029
+ `),
1030
+ putBlob: this.db.prepare(`
1031
+ INSERT OR IGNORE INTO blobs (hash, content) VALUES ($hash, $content)
1032
+ `),
1033
+ getBlob: this.db.prepare(`
1034
+ SELECT content FROM blobs WHERE hash = $hash
1035
+ `),
1036
+ hasBlob: this.db.prepare(`
1037
+ SELECT 1 FROM blobs WHERE hash = $hash
1038
+ `)
1039
+ };
1040
+ }
1041
+ append(op) {
1042
+ const payload = JSON.stringify({
1043
+ facts: op.facts,
1044
+ links: op.links,
1045
+ ...op.deleteFacts?.length ? { deleteFacts: op.deleteFacts } : {},
1046
+ ...op.deleteLinks?.length ? { deleteLinks: op.deleteLinks } : {},
1047
+ ...op.vcs ? { vcs: op.vcs } : {},
1048
+ ...op.signature ? { signature: op.signature } : {}
1049
+ });
1050
+ this._stmts.insert.run({
1051
+ $hash: op.hash,
1052
+ $kind: op.kind,
1053
+ $timestamp: op.timestamp,
1054
+ $agentId: op.agentId,
1055
+ $previousHash: op.previousHash ?? null,
1056
+ $payload: payload
1057
+ });
1058
+ }
1059
+ appendBatch(ops) {
1060
+ if (ops.length === 0)
1061
+ return;
1062
+ this.db.transaction(() => {
1063
+ for (const op of ops) {
1064
+ this.append(op);
1065
+ }
1066
+ })();
1067
+ }
1068
+ readAll() {
1069
+ const rows = this._stmts.readAll.all();
1070
+ return rows.map(rowToOp);
1071
+ }
1072
+ readUntil(hash) {
1073
+ const rows = this._stmts.readUntil.all({ $hash: hash });
1074
+ return rows.map(rowToOp);
1075
+ }
1076
+ readAfter(hash) {
1077
+ const rows = this._stmts.readAfter.all({ $hash: hash });
1078
+ return rows.map(rowToOp);
1079
+ }
1080
+ readUntilTimestamp(isoTimestamp) {
1081
+ const rows = this.db.prepare(`SELECT hash, kind, timestamp, agent_id, previous_hash, payload
1082
+ FROM ops WHERE timestamp <= $ts ORDER BY rowid ASC`).all({ $ts: isoTimestamp });
1083
+ return rows.map(rowToOp);
1084
+ }
1085
+ getLastOp() {
1086
+ const row = this._stmts.getLast.get();
1087
+ return row ? rowToOp(row) : undefined;
1088
+ }
1089
+ getOpByHash(hash) {
1090
+ const row = this._stmts.getByHash.get({ $hash: hash });
1091
+ return row ? rowToOp(row) : undefined;
1092
+ }
1093
+ count() {
1094
+ const row = this._stmts.count.get();
1095
+ return row?.cnt ?? 0;
1096
+ }
1097
+ findCommonAncestor(hashA, hashB) {
1098
+ const ancestorsA = new Set;
1099
+ let cursor = hashA;
1100
+ while (cursor) {
1101
+ ancestorsA.add(cursor);
1102
+ const op = this.getOpByHash(cursor);
1103
+ cursor = op?.previousHash;
1104
+ }
1105
+ cursor = hashB;
1106
+ while (cursor) {
1107
+ if (ancestorsA.has(cursor)) {
1108
+ return this.getOpByHash(cursor);
1109
+ }
1110
+ const op = this.getOpByHash(cursor);
1111
+ cursor = op?.previousHash;
1112
+ }
1113
+ return;
1114
+ }
1115
+ saveSnapshot(lastOpHash, data) {
1116
+ this._stmts.saveSnapshot.run({
1117
+ $lastOpHash: lastOpHash,
1118
+ $data: JSON.stringify(data)
1119
+ });
1120
+ }
1121
+ loadLatestSnapshot() {
1122
+ const row = this._stmts.loadSnapshot.get();
1123
+ if (!row)
1124
+ return;
1125
+ return {
1126
+ lastOpHash: row.last_op_hash,
1127
+ data: JSON.parse(row.data)
1128
+ };
1129
+ }
1130
+ putBlob(hash, content) {
1131
+ this._stmts.putBlob.run({
1132
+ $hash: hash,
1133
+ $content: Buffer.from(content)
1134
+ });
1135
+ }
1136
+ getBlob(hash) {
1137
+ const row = this._stmts.getBlob.get({ $hash: hash });
1138
+ if (!row)
1139
+ return;
1140
+ return new Uint8Array(row.content);
1141
+ }
1142
+ hasBlob(hash) {
1143
+ return !!this._stmts.hasBlob.get({ $hash: hash });
1144
+ }
1145
+ close() {
1146
+ this.db.close();
1147
+ }
1148
+ }
1149
+ function rowToOp(row) {
1150
+ const payload = JSON.parse(row.payload);
1151
+ const op = {
1152
+ hash: row.hash,
1153
+ kind: row.kind,
1154
+ timestamp: row.timestamp,
1155
+ agentId: row.agent_id
1156
+ };
1157
+ if (row.previous_hash)
1158
+ op.previousHash = row.previous_hash;
1159
+ if (payload.facts)
1160
+ op.facts = payload.facts;
1161
+ if (payload.links)
1162
+ op.links = payload.links;
1163
+ if (payload.deleteFacts)
1164
+ op.deleteFacts = payload.deleteFacts;
1165
+ if (payload.deleteLinks)
1166
+ op.deleteLinks = payload.deleteLinks;
1167
+ if (payload.vcs)
1168
+ op.vcs = payload.vcs;
1169
+ if (payload.signature)
1170
+ op.signature = payload.signature;
1171
+ return op;
1172
+ }
1173
+
1174
+ export { flatten, jsonEntityFacts, EAVStore, init_eav_store, variable, literal, QueryEngine, TrellisKernel, SqliteKernelBackend };