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,370 @@
1
+ /**
2
+ * EQL-S Query Engine — Pattern-matching evaluator over the EAV store.
3
+ *
4
+ * Evaluates queries by matching fact/link patterns against the store,
5
+ * binding variables, applying filters, and computing aggregates.
6
+ *
7
+ * @module trellis/core/query
8
+ */
9
+
10
+ import type { EAVStore, Fact, Link, Atom } from '../store/eav-store.js';
11
+ import type {
12
+ Query, Pattern, FactPattern, LinkPattern, NotPattern, OrPattern,
13
+ RuleApplication, Filter, FilterOp, Aggregate, OrderBy,
14
+ Term, Bindings, DatalogRule,
15
+ } from './types.js';
16
+ import { isVariable, isLiteral } from './types.js';
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Result type
20
+ // ---------------------------------------------------------------------------
21
+
22
+ export interface QueryResult {
23
+ bindings: Record<string, Atom>[];
24
+ executionTime: number;
25
+ count: number;
26
+ }
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Engine
30
+ // ---------------------------------------------------------------------------
31
+
32
+ export class QueryEngine {
33
+ private rules: Map<string, DatalogRule[]> = new Map();
34
+ private maxRuleDepth = 32;
35
+
36
+ constructor(private store: EAVStore) {}
37
+
38
+ /** Register a Datalog rule. Multiple rules with the same name = union. */
39
+ addRule(rule: DatalogRule): void {
40
+ const existing = this.rules.get(rule.name) ?? [];
41
+ existing.push(rule);
42
+ this.rules.set(rule.name, existing);
43
+ }
44
+
45
+ removeRule(name: string): void {
46
+ this.rules.delete(name);
47
+ }
48
+
49
+ /** Execute a query against the store. */
50
+ execute(query: Query): QueryResult {
51
+ const start = performance.now();
52
+
53
+ // Evaluate patterns
54
+ let results = this._evaluatePatterns(query.where, [new Map()]);
55
+
56
+ // Apply filters
57
+ for (const filter of query.filters) {
58
+ results = results.filter((b) => this._evalFilter(filter, b));
59
+ }
60
+
61
+ // Apply aggregates
62
+ if (query.aggregates.length > 0) {
63
+ results = this._aggregate(results, query.aggregates, query.select);
64
+ }
65
+
66
+ // Apply ordering
67
+ if (query.orderBy.length > 0) {
68
+ results = this._order(results, query.orderBy);
69
+ }
70
+
71
+ // Apply offset/limit
72
+ if (query.offset > 0) results = results.slice(query.offset);
73
+ if (query.limit > 0) results = results.slice(0, query.limit);
74
+
75
+ // Project selected variables
76
+ const projected = this._project(results, query.select);
77
+
78
+ return {
79
+ bindings: projected,
80
+ executionTime: performance.now() - start,
81
+ count: projected.length,
82
+ };
83
+ }
84
+
85
+ // -------------------------------------------------------------------------
86
+ // Pattern evaluation
87
+ // -------------------------------------------------------------------------
88
+
89
+ private _evaluatePatterns(patterns: Pattern[], bindings: Bindings[]): Bindings[] {
90
+ let current = bindings;
91
+ for (const pattern of patterns) {
92
+ if (current.length === 0) break;
93
+ current = this._evaluatePattern(pattern, current);
94
+ }
95
+ return current;
96
+ }
97
+
98
+ private _evaluatePattern(pattern: Pattern, bindings: Bindings[]): Bindings[] {
99
+ switch (pattern.kind) {
100
+ case 'fact': return this._evalFactPattern(pattern, bindings);
101
+ case 'link': return this._evalLinkPattern(pattern, bindings);
102
+ case 'not': return this._evalNotPattern(pattern, bindings);
103
+ case 'or': return this._evalOrPattern(pattern, bindings);
104
+ case 'rule': return this._evalRuleApplication(pattern, bindings);
105
+ }
106
+ }
107
+
108
+ private _evalFactPattern(p: FactPattern, bindings: Bindings[]): Bindings[] {
109
+ const results: Bindings[] = [];
110
+ for (const b of bindings) {
111
+ const eResolved = this._resolve(p.entity, b);
112
+ const aResolved = this._resolve(p.attribute, b);
113
+ const vResolved = this._resolve(p.value, b);
114
+
115
+ let facts: Fact[];
116
+ if (eResolved !== undefined && aResolved !== undefined) {
117
+ facts = this.store.getFactsByEntity(String(eResolved))
118
+ .filter((f) => f.a === aResolved);
119
+ } else if (eResolved !== undefined) {
120
+ facts = this.store.getFactsByEntity(String(eResolved));
121
+ } else if (aResolved !== undefined && vResolved !== undefined) {
122
+ facts = this.store.getFactsByValue(String(aResolved), vResolved);
123
+ } else if (aResolved !== undefined) {
124
+ facts = this.store.getFactsByAttribute(String(aResolved));
125
+ } else {
126
+ facts = this.store.getAllFacts();
127
+ }
128
+
129
+ if (vResolved !== undefined) {
130
+ facts = facts.filter((f) => f.v === vResolved);
131
+ }
132
+
133
+ for (const fact of facts) {
134
+ const nb = new Map(b);
135
+ if (this._bind(p.entity, fact.e, nb) &&
136
+ this._bind(p.attribute, fact.a, nb) &&
137
+ this._bind(p.value, fact.v, nb)) {
138
+ results.push(nb);
139
+ }
140
+ }
141
+ }
142
+ return results;
143
+ }
144
+
145
+ private _evalLinkPattern(p: LinkPattern, bindings: Bindings[]): Bindings[] {
146
+ const results: Bindings[] = [];
147
+ for (const b of bindings) {
148
+ const srcResolved = this._resolve(p.source, b);
149
+ const attrResolved = this._resolve(p.attribute, b);
150
+ const tgtResolved = this._resolve(p.target, b);
151
+
152
+ let links: Link[];
153
+ if (srcResolved !== undefined && attrResolved !== undefined) {
154
+ links = this.store.getLinksByEntityAndAttribute(String(srcResolved), String(attrResolved));
155
+ } else if (srcResolved !== undefined) {
156
+ links = this.store.getLinksByEntity(String(srcResolved));
157
+ } else if (attrResolved !== undefined) {
158
+ links = this.store.getLinksByAttribute(String(attrResolved));
159
+ } else {
160
+ links = this.store.getAllLinks();
161
+ }
162
+
163
+ if (tgtResolved !== undefined) {
164
+ links = links.filter((l) => l.e2 === tgtResolved);
165
+ }
166
+
167
+ for (const link of links) {
168
+ const nb = new Map(b);
169
+ if (this._bind(p.source, link.e1, nb) &&
170
+ this._bind(p.attribute, link.a, nb) &&
171
+ this._bind(p.target, link.e2, nb)) {
172
+ results.push(nb);
173
+ }
174
+ }
175
+ }
176
+ return results;
177
+ }
178
+
179
+ private _evalNotPattern(p: NotPattern, bindings: Bindings[]): Bindings[] {
180
+ return bindings.filter((b) => {
181
+ const matches = this._evaluatePattern(p.pattern, [b]);
182
+ return matches.length === 0;
183
+ });
184
+ }
185
+
186
+ private _evalOrPattern(p: OrPattern, bindings: Bindings[]): Bindings[] {
187
+ const results: Bindings[] = [];
188
+ for (const branch of p.branches) {
189
+ const branchResults = this._evaluatePatterns(branch, bindings);
190
+ results.push(...branchResults);
191
+ }
192
+ return this._dedup(results);
193
+ }
194
+
195
+ private _evalRuleApplication(p: RuleApplication, bindings: Bindings[], depth = 0): Bindings[] {
196
+ if (depth > this.maxRuleDepth) return [];
197
+ const ruleDefs = this.rules.get(p.name);
198
+ if (!ruleDefs) return [];
199
+
200
+ const results: Bindings[] = [];
201
+ for (const b of bindings) {
202
+ for (const rule of ruleDefs) {
203
+ // Bind rule params from application args
204
+ const ruleBindings = new Map(b);
205
+ let ok = true;
206
+ for (let i = 0; i < rule.params.length && i < p.args.length; i++) {
207
+ const resolved = this._resolve(p.args[i], b);
208
+ if (resolved !== undefined) {
209
+ ruleBindings.set(rule.params[i], resolved);
210
+ } else if (isVariable(p.args[i])) {
211
+ // Leave unbound — will be bound by body
212
+ }
213
+ }
214
+ if (!ok) continue;
215
+
216
+ // Evaluate body
217
+ let bodyResults = this._evaluatePatterns(rule.body, [ruleBindings]);
218
+
219
+ // Apply rule filters
220
+ for (const f of rule.filters) {
221
+ bodyResults = bodyResults.filter((rb) => this._evalFilter(f, rb));
222
+ }
223
+
224
+ // Map back rule param bindings to the application arg variables
225
+ for (const rb of bodyResults) {
226
+ const nb = new Map(b);
227
+ for (let i = 0; i < rule.params.length && i < p.args.length; i++) {
228
+ if (isVariable(p.args[i])) {
229
+ const val = rb.get(rule.params[i]);
230
+ if (val !== undefined) nb.set(p.args[i].name, val);
231
+ }
232
+ }
233
+ results.push(nb);
234
+ }
235
+ }
236
+ }
237
+ return this._dedup(results);
238
+ }
239
+
240
+ // -------------------------------------------------------------------------
241
+ // Filtering
242
+ // -------------------------------------------------------------------------
243
+
244
+ private _evalFilter(filter: Filter, b: Bindings): boolean {
245
+ const left = this._resolve(filter.left, b);
246
+ const right = this._resolve(filter.right, b);
247
+ if (left === undefined || right === undefined) return false;
248
+
249
+ switch (filter.op) {
250
+ case '=': return left === right;
251
+ case '!=': return left !== right;
252
+ case '<': return (left as any) < (right as any);
253
+ case '<=': return (left as any) <= (right as any);
254
+ case '>': return (left as any) > (right as any);
255
+ case '>=': return (left as any) >= (right as any);
256
+ case 'contains': return String(left).includes(String(right));
257
+ case 'startsWith': return String(left).startsWith(String(right));
258
+ case 'endsWith': return String(left).endsWith(String(right));
259
+ case 'matches': return new RegExp(String(right)).test(String(left));
260
+ default: return false;
261
+ }
262
+ }
263
+
264
+ // -------------------------------------------------------------------------
265
+ // Aggregation
266
+ // -------------------------------------------------------------------------
267
+
268
+ private _aggregate(bindings: Bindings[], aggregates: Aggregate[], groupBy: string[]): Bindings[] {
269
+ // Group by non-aggregated select variables
270
+ const aggVarNames = new Set(aggregates.map((a) => a.as));
271
+ const groupVars = groupBy.filter((v) => !aggVarNames.has(v));
272
+
273
+ const groups = new Map<string, Bindings[]>();
274
+ for (const b of bindings) {
275
+ const key = groupVars.map((v) => String(b.get(v) ?? '')).join('\0');
276
+ const group = groups.get(key) ?? [];
277
+ group.push(b);
278
+ groups.set(key, group);
279
+ }
280
+
281
+ const results: Bindings[] = [];
282
+ for (const [, group] of groups) {
283
+ const nb = new Map(group[0]);
284
+ for (const agg of aggregates) {
285
+ const vals = group.map((b) => b.get(agg.variable)).filter((v) => v !== undefined);
286
+ nb.set(agg.as, this._computeAggregate(agg.op, vals as Atom[]));
287
+ }
288
+ results.push(nb);
289
+ }
290
+ return results;
291
+ }
292
+
293
+ private _computeAggregate(op: string, vals: Atom[]): Atom {
294
+ switch (op) {
295
+ case 'count': return vals.length;
296
+ case 'sum': return vals.reduce((s, v) => (s as number) + (Number(v) || 0), 0 as any) as number;
297
+ case 'avg': return vals.length ? (vals.reduce((s, v) => (s as number) + (Number(v) || 0), 0 as any) as number) / vals.length : 0;
298
+ case 'min': return vals.reduce((m, v) => (v as any) < (m as any) ? v : m, vals[0]);
299
+ case 'max': return vals.reduce((m, v) => (v as any) > (m as any) ? v : m, vals[0]);
300
+ case 'collect': return JSON.stringify(vals);
301
+ default: return vals.length;
302
+ }
303
+ }
304
+
305
+ // -------------------------------------------------------------------------
306
+ // Ordering
307
+ // -------------------------------------------------------------------------
308
+
309
+ private _order(bindings: Bindings[], orderBy: OrderBy[]): Bindings[] {
310
+ return [...bindings].sort((a, b) => {
311
+ for (const o of orderBy) {
312
+ const va = a.get(o.variable);
313
+ const vb = b.get(o.variable);
314
+ if (va === vb) continue;
315
+ if (va === undefined) return 1;
316
+ if (vb === undefined) return -1;
317
+ const cmp = (va as any) < (vb as any) ? -1 : 1;
318
+ return o.direction === 'asc' ? cmp : -cmp;
319
+ }
320
+ return 0;
321
+ });
322
+ }
323
+
324
+ // -------------------------------------------------------------------------
325
+ // Projection
326
+ // -------------------------------------------------------------------------
327
+
328
+ private _project(bindings: Bindings[], select: string[]): Record<string, Atom>[] {
329
+ return bindings.map((b) => {
330
+ const row: Record<string, Atom> = {};
331
+ if (select.length === 0) {
332
+ for (const [k, v] of b) row[k] = v;
333
+ } else {
334
+ for (const s of select) {
335
+ const v = b.get(s);
336
+ if (v !== undefined) row[s] = v;
337
+ }
338
+ }
339
+ return row;
340
+ });
341
+ }
342
+
343
+ // -------------------------------------------------------------------------
344
+ // Helpers
345
+ // -------------------------------------------------------------------------
346
+
347
+ private _resolve(term: Term, bindings: Bindings): Atom | undefined {
348
+ if (isLiteral(term)) return term.value;
349
+ return bindings.get(term.name);
350
+ }
351
+
352
+ private _bind(term: Term, value: Atom, bindings: Bindings): boolean {
353
+ if (isLiteral(term)) return term.value === value;
354
+ const existing = bindings.get(term.name);
355
+ if (existing !== undefined) return existing === value;
356
+ bindings.set(term.name, value);
357
+ return true;
358
+ }
359
+
360
+ private _dedup(bindings: Bindings[]): Bindings[] {
361
+ const seen = new Set<string>();
362
+ return bindings.filter((b) => {
363
+ const key = [...b.entries()].sort(([a], [b]) => a.localeCompare(b))
364
+ .map(([k, v]) => `${k}=${v}`).join('\0');
365
+ if (seen.has(key)) return false;
366
+ seen.add(key);
367
+ return true;
368
+ });
369
+ }
370
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * EQL-S Query Module — Public API Surface
3
+ *
4
+ * @module trellis/core/query
5
+ */
6
+
7
+ // Types
8
+ export type {
9
+ Variable, Literal, Term,
10
+ FactPattern, LinkPattern, NotPattern, OrPattern, RuleApplication, Pattern,
11
+ FilterOp, Filter,
12
+ AggregateOp, Aggregate,
13
+ OrderBy,
14
+ Query,
15
+ Bindings,
16
+ DatalogRule,
17
+ } from './types.js';
18
+
19
+ export { isVariable, isLiteral, variable, literal } from './types.js';
20
+
21
+ // Engine
22
+ export { QueryEngine } from './engine.js';
23
+ export type { QueryResult } from './engine.js';
24
+
25
+ // Parser
26
+ export { parseQuery, parseRule, parseSimple } from './parser.js';
27
+
28
+ // Datalog
29
+ export {
30
+ DatalogRuntime,
31
+ transitiveClosureRules,
32
+ reverseReachabilityRules,
33
+ siblingRules,
34
+ } from './datalog.js';