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.
- package/README.md +279 -116
- package/dist/cli/index.js +655 -4
- package/dist/core/index.js +471 -2
- package/dist/embeddings/index.js +5 -1
- package/dist/{index-s603ev6w.js → index-5b01h414.js} +1 -1
- package/dist/index-5m0g9r0y.js +1100 -0
- package/dist/{index-zf6htvnm.js → index-7gvjxt27.js} +166 -2
- package/dist/index-hybgxe40.js +1174 -0
- package/dist/index.js +7 -2
- package/dist/transformers.node-bx3q9d7k.js +33130 -0
- package/package.json +9 -4
- package/src/cli/index.ts +939 -0
- package/src/core/agents/harness.ts +380 -0
- package/src/core/agents/index.ts +18 -0
- package/src/core/agents/types.ts +90 -0
- package/src/core/index.ts +85 -2
- package/src/core/kernel/trellis-kernel.ts +593 -0
- package/src/core/ontology/builtins.ts +248 -0
- package/src/core/ontology/index.ts +34 -0
- package/src/core/ontology/registry.ts +209 -0
- package/src/core/ontology/types.ts +124 -0
- package/src/core/ontology/validator.ts +382 -0
- package/src/core/persist/backend.ts +10 -0
- package/src/core/persist/sqlite-backend.ts +298 -0
- package/src/core/plugins/index.ts +17 -0
- package/src/core/plugins/registry.ts +322 -0
- package/src/core/plugins/types.ts +126 -0
- package/src/core/query/datalog.ts +188 -0
- package/src/core/query/engine.ts +370 -0
- package/src/core/query/index.ts +34 -0
- package/src/core/query/parser.ts +481 -0
- package/src/core/query/types.ts +200 -0
- package/src/embeddings/auto-embed.ts +248 -0
- package/src/embeddings/index.ts +7 -0
- package/src/embeddings/model.ts +21 -4
- package/src/embeddings/types.ts +8 -1
- package/src/index.ts +9 -0
- package/src/sync/http-transport.ts +144 -0
- package/src/sync/index.ts +11 -0
- package/src/sync/multi-repo.ts +200 -0
- package/src/sync/ws-transport.ts +145 -0
- package/dist/index-5bhe57y9.js +0 -326
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Ontology Definitions
|
|
3
|
+
*
|
|
4
|
+
* Pre-defined ontologies for common domain models:
|
|
5
|
+
* - Project: software project management entities
|
|
6
|
+
* - Team: team/developer organizational entities
|
|
7
|
+
* - Agent: AI agent entities for the agent harness
|
|
8
|
+
*
|
|
9
|
+
* @module trellis/core/ontology
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { OntologySchema } from './types.js';
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Project Ontology
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
export const projectOntology: OntologySchema = {
|
|
19
|
+
id: 'trellis:project',
|
|
20
|
+
name: 'Project Ontology',
|
|
21
|
+
version: '1.0.0',
|
|
22
|
+
description: 'Entity types for software project management.',
|
|
23
|
+
entities: [
|
|
24
|
+
{
|
|
25
|
+
name: 'Project',
|
|
26
|
+
description: 'A software project or repository.',
|
|
27
|
+
attributes: [
|
|
28
|
+
{ name: 'name', type: 'string', required: true, description: 'Project name' },
|
|
29
|
+
{ name: 'description', type: 'string', description: 'Project description' },
|
|
30
|
+
{ name: 'status', type: 'string', enum: ['active', 'archived', 'draft', 'deprecated'], default: 'active' },
|
|
31
|
+
{ name: 'url', type: 'string', description: 'Project URL or repository link' },
|
|
32
|
+
{ name: 'language', type: 'string', description: 'Primary programming language' },
|
|
33
|
+
{ name: 'createdAt', type: 'date', description: 'Creation timestamp' },
|
|
34
|
+
{ name: 'updatedAt', type: 'date', description: 'Last update timestamp' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'Module',
|
|
39
|
+
description: 'A logical module or package within a project.',
|
|
40
|
+
attributes: [
|
|
41
|
+
{ name: 'name', type: 'string', required: true },
|
|
42
|
+
{ name: 'path', type: 'string', description: 'Filesystem path relative to project root' },
|
|
43
|
+
{ name: 'description', type: 'string' },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Feature',
|
|
48
|
+
description: 'A product feature or capability.',
|
|
49
|
+
attributes: [
|
|
50
|
+
{ name: 'name', type: 'string', required: true },
|
|
51
|
+
{ name: 'description', type: 'string' },
|
|
52
|
+
{ name: 'status', type: 'string', enum: ['planned', 'in-progress', 'shipped', 'cut'], default: 'planned' },
|
|
53
|
+
{ name: 'priority', type: 'string', enum: ['critical', 'high', 'medium', 'low'], default: 'medium' },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'Dependency',
|
|
58
|
+
description: 'An external dependency or library.',
|
|
59
|
+
attributes: [
|
|
60
|
+
{ name: 'name', type: 'string', required: true },
|
|
61
|
+
{ name: 'version', type: 'string' },
|
|
62
|
+
{ name: 'registry', type: 'string', description: 'Package registry (npm, pypi, etc.)' },
|
|
63
|
+
{ name: 'scope', type: 'string', enum: ['runtime', 'dev', 'optional'], default: 'runtime' },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'Config',
|
|
68
|
+
description: 'A configuration entry or setting.',
|
|
69
|
+
attributes: [
|
|
70
|
+
{ name: 'key', type: 'string', required: true },
|
|
71
|
+
{ name: 'value', type: 'any', required: true },
|
|
72
|
+
{ name: 'description', type: 'string' },
|
|
73
|
+
{ name: 'scope', type: 'string', enum: ['project', 'user', 'system'], default: 'project' },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'Artifact',
|
|
78
|
+
description: 'A build artifact, release asset, or output file.',
|
|
79
|
+
attributes: [
|
|
80
|
+
{ name: 'name', type: 'string', required: true },
|
|
81
|
+
{ name: 'path', type: 'string' },
|
|
82
|
+
{ name: 'size', type: 'number' },
|
|
83
|
+
{ name: 'hash', type: 'string' },
|
|
84
|
+
{ name: 'format', type: 'string' },
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'Release',
|
|
89
|
+
description: 'A versioned release of a project.',
|
|
90
|
+
attributes: [
|
|
91
|
+
{ name: 'version', type: 'string', required: true },
|
|
92
|
+
{ name: 'tag', type: 'string' },
|
|
93
|
+
{ name: 'date', type: 'date' },
|
|
94
|
+
{ name: 'notes', type: 'string' },
|
|
95
|
+
{ name: 'status', type: 'string', enum: ['draft', 'published', 'yanked'], default: 'draft' },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
relations: [
|
|
100
|
+
{ name: 'contains', sourceTypes: ['Project'], targetTypes: ['Module', 'Feature', 'Config'], cardinality: 'many', description: 'Project contains modules/features/configs' },
|
|
101
|
+
{ name: 'dependsOn', sourceTypes: ['Project', 'Module'], targetTypes: ['Dependency', 'Module', 'Project'], cardinality: 'many', description: 'Depends on another entity' },
|
|
102
|
+
{ name: 'implementedBy', sourceTypes: ['Feature'], targetTypes: ['Module'], cardinality: 'many', description: 'Feature is implemented by modules' },
|
|
103
|
+
{ name: 'produces', sourceTypes: ['Project', 'Release'], targetTypes: ['Artifact'], cardinality: 'many', description: 'Produces artifacts' },
|
|
104
|
+
{ name: 'releases', sourceTypes: ['Project'], targetTypes: ['Release'], cardinality: 'many', description: 'Project has releases' },
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Team / Developer Ontology
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
export const teamOntology: OntologySchema = {
|
|
113
|
+
id: 'trellis:team',
|
|
114
|
+
name: 'Team Ontology',
|
|
115
|
+
version: '1.0.0',
|
|
116
|
+
description: 'Entity types for team and developer organization.',
|
|
117
|
+
entities: [
|
|
118
|
+
{
|
|
119
|
+
name: 'Team',
|
|
120
|
+
description: 'A team or organizational group.',
|
|
121
|
+
attributes: [
|
|
122
|
+
{ name: 'name', type: 'string', required: true },
|
|
123
|
+
{ name: 'description', type: 'string' },
|
|
124
|
+
{ name: 'slug', type: 'string', description: 'URL-safe identifier' },
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'Developer',
|
|
129
|
+
description: 'A developer or contributor.',
|
|
130
|
+
attributes: [
|
|
131
|
+
{ name: 'name', type: 'string', required: true },
|
|
132
|
+
{ name: 'email', type: 'string' },
|
|
133
|
+
{ name: 'handle', type: 'string', description: 'Username or handle' },
|
|
134
|
+
{ name: 'role', type: 'string', enum: ['admin', 'maintainer', 'contributor', 'reviewer'] },
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'Role',
|
|
139
|
+
description: 'A named role with specific permissions.',
|
|
140
|
+
attributes: [
|
|
141
|
+
{ name: 'name', type: 'string', required: true },
|
|
142
|
+
{ name: 'description', type: 'string' },
|
|
143
|
+
{ name: 'permissions', type: 'string', unique: false, description: 'Permission strings (multi-valued)' },
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'Capability',
|
|
148
|
+
description: 'A skill or capability.',
|
|
149
|
+
attributes: [
|
|
150
|
+
{ name: 'name', type: 'string', required: true },
|
|
151
|
+
{ name: 'category', type: 'string' },
|
|
152
|
+
{ name: 'level', type: 'string', enum: ['beginner', 'intermediate', 'advanced', 'expert'] },
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
relations: [
|
|
157
|
+
{ name: 'hasMember', sourceTypes: ['Team'], targetTypes: ['Developer'], cardinality: 'many', inverse: 'memberOf', description: 'Team has member' },
|
|
158
|
+
{ name: 'memberOf', sourceTypes: ['Developer'], targetTypes: ['Team'], cardinality: 'many', inverse: 'hasMember', description: 'Developer is member of team' },
|
|
159
|
+
{ name: 'owns', sourceTypes: ['Developer'], targetTypes: ['Project', 'Module'], cardinality: 'many', description: 'Developer owns/maintains' },
|
|
160
|
+
{ name: 'reviewsFor', sourceTypes: ['Developer'], targetTypes: ['Project', 'Module'], cardinality: 'many', description: 'Developer reviews for' },
|
|
161
|
+
{ name: 'hasCapability', sourceTypes: ['Developer'], targetTypes: ['Capability'], cardinality: 'many', description: 'Developer has capability' },
|
|
162
|
+
{ name: 'hasRole', sourceTypes: ['Developer'], targetTypes: ['Role'], cardinality: 'many', description: 'Developer has role' },
|
|
163
|
+
{ name: 'assignedTo', sourceTypes: ['Developer'], targetTypes: ['Feature'], cardinality: 'many', description: 'Developer is assigned to feature' },
|
|
164
|
+
],
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// Agent Ontology
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
export const agentOntology: OntologySchema = {
|
|
172
|
+
id: 'trellis:agent',
|
|
173
|
+
name: 'Agent Ontology',
|
|
174
|
+
version: '1.0.0',
|
|
175
|
+
description: 'Entity types for AI agents, runs, plans, and tools.',
|
|
176
|
+
entities: [
|
|
177
|
+
{
|
|
178
|
+
name: 'Agent',
|
|
179
|
+
description: 'An AI agent definition.',
|
|
180
|
+
attributes: [
|
|
181
|
+
{ name: 'name', type: 'string', required: true },
|
|
182
|
+
{ name: 'description', type: 'string' },
|
|
183
|
+
{ name: 'model', type: 'string', description: 'LLM model identifier' },
|
|
184
|
+
{ name: 'provider', type: 'string', description: 'LLM provider (openai, anthropic, local, etc.)' },
|
|
185
|
+
{ name: 'systemPrompt', type: 'string' },
|
|
186
|
+
{ name: 'status', type: 'string', enum: ['active', 'inactive', 'deprecated'], default: 'active' },
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'AgentCapability',
|
|
191
|
+
description: 'A capability or skill an agent possesses.',
|
|
192
|
+
attributes: [
|
|
193
|
+
{ name: 'name', type: 'string', required: true },
|
|
194
|
+
{ name: 'description', type: 'string' },
|
|
195
|
+
{ name: 'category', type: 'string' },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'AgentRun',
|
|
200
|
+
description: 'A single execution run of an agent.',
|
|
201
|
+
attributes: [
|
|
202
|
+
{ name: 'startedAt', type: 'date', required: true },
|
|
203
|
+
{ name: 'completedAt', type: 'date' },
|
|
204
|
+
{ name: 'status', type: 'string', enum: ['running', 'completed', 'failed', 'cancelled'], default: 'running' },
|
|
205
|
+
{ name: 'input', type: 'string' },
|
|
206
|
+
{ name: 'output', type: 'string' },
|
|
207
|
+
{ name: 'tokenCount', type: 'number' },
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: 'AgentPlan',
|
|
212
|
+
description: 'A plan or strategy created by an agent.',
|
|
213
|
+
attributes: [
|
|
214
|
+
{ name: 'title', type: 'string', required: true },
|
|
215
|
+
{ name: 'description', type: 'string' },
|
|
216
|
+
{ name: 'status', type: 'string', enum: ['draft', 'active', 'completed', 'abandoned'], default: 'draft' },
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: 'Tool',
|
|
221
|
+
description: 'A tool available to agents.',
|
|
222
|
+
attributes: [
|
|
223
|
+
{ name: 'name', type: 'string', required: true },
|
|
224
|
+
{ name: 'description', type: 'string' },
|
|
225
|
+
{ name: 'schema', type: 'string', description: 'JSON schema for tool parameters' },
|
|
226
|
+
{ name: 'endpoint', type: 'string' },
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
relations: [
|
|
231
|
+
{ name: 'hasCapability', sourceTypes: ['Agent'], targetTypes: ['AgentCapability'], cardinality: 'many' },
|
|
232
|
+
{ name: 'hasTool', sourceTypes: ['Agent'], targetTypes: ['Tool'], cardinality: 'many' },
|
|
233
|
+
{ name: 'executedBy', sourceTypes: ['AgentRun'], targetTypes: ['Agent'], cardinality: 'one' },
|
|
234
|
+
{ name: 'hasPlan', sourceTypes: ['AgentRun'], targetTypes: ['AgentPlan'], cardinality: 'many' },
|
|
235
|
+
{ name: 'usedTool', sourceTypes: ['AgentRun'], targetTypes: ['Tool'], cardinality: 'many' },
|
|
236
|
+
{ name: 'createdBy', sourceTypes: ['AgentPlan'], targetTypes: ['Agent'], cardinality: 'one' },
|
|
237
|
+
],
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// All built-in ontologies
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
export const builtinOntologies: OntologySchema[] = [
|
|
245
|
+
projectOntology,
|
|
246
|
+
teamOntology,
|
|
247
|
+
agentOntology,
|
|
248
|
+
];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ontology Module — Public API Surface
|
|
3
|
+
*
|
|
4
|
+
* @module trellis/core/ontology
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export type {
|
|
9
|
+
AttrType,
|
|
10
|
+
AttributeDef,
|
|
11
|
+
RelationDef,
|
|
12
|
+
EntityDef,
|
|
13
|
+
OntologySchema,
|
|
14
|
+
ValidationError,
|
|
15
|
+
ValidationResult,
|
|
16
|
+
} from './types.js';
|
|
17
|
+
|
|
18
|
+
// Registry
|
|
19
|
+
export { OntologyRegistry } from './registry.js';
|
|
20
|
+
|
|
21
|
+
// Built-in ontologies
|
|
22
|
+
export {
|
|
23
|
+
projectOntology,
|
|
24
|
+
teamOntology,
|
|
25
|
+
agentOntology,
|
|
26
|
+
builtinOntologies,
|
|
27
|
+
} from './builtins.js';
|
|
28
|
+
|
|
29
|
+
// Validation
|
|
30
|
+
export {
|
|
31
|
+
validateEntity,
|
|
32
|
+
validateStore,
|
|
33
|
+
createValidationMiddleware,
|
|
34
|
+
} from './validator.js';
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ontology Registry — Manages loaded ontology schemas.
|
|
3
|
+
*
|
|
4
|
+
* Provides registration, lookup, inheritance resolution, and
|
|
5
|
+
* entity-type-to-schema mapping.
|
|
6
|
+
*
|
|
7
|
+
* @module trellis/core/ontology
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
OntologySchema,
|
|
12
|
+
EntityDef,
|
|
13
|
+
RelationDef,
|
|
14
|
+
AttributeDef,
|
|
15
|
+
} from './types.js';
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Registry
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
export class OntologyRegistry {
|
|
22
|
+
private schemas: Map<string, OntologySchema> = new Map();
|
|
23
|
+
/** Resolved entity defs (with inherited attributes merged). */
|
|
24
|
+
private resolvedEntities: Map<string, { def: EntityDef; ontologyId: string }> = new Map();
|
|
25
|
+
/** Resolved relation defs. */
|
|
26
|
+
private resolvedRelations: Map<string, { def: RelationDef; ontologyId: string }[]> = new Map();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Register an ontology schema.
|
|
30
|
+
* Throws if an ontology with the same ID is already registered at the same version.
|
|
31
|
+
*/
|
|
32
|
+
register(schema: OntologySchema): void {
|
|
33
|
+
const existing = this.schemas.get(schema.id);
|
|
34
|
+
if (existing && existing.version === schema.version) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Ontology "${schema.id}" v${schema.version} is already registered.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
this.schemas.set(schema.id, schema);
|
|
40
|
+
this._resolve(schema);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Unregister an ontology by ID.
|
|
45
|
+
*/
|
|
46
|
+
unregister(id: string): void {
|
|
47
|
+
const schema = this.schemas.get(id);
|
|
48
|
+
if (!schema) return;
|
|
49
|
+
|
|
50
|
+
// Remove entities belonging to this ontology
|
|
51
|
+
for (const [name, entry] of this.resolvedEntities) {
|
|
52
|
+
if (entry.ontologyId === id) {
|
|
53
|
+
this.resolvedEntities.delete(name);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Remove relations belonging to this ontology
|
|
58
|
+
for (const [name, entries] of this.resolvedRelations) {
|
|
59
|
+
const filtered = entries.filter((e) => e.ontologyId !== id);
|
|
60
|
+
if (filtered.length === 0) {
|
|
61
|
+
this.resolvedRelations.delete(name);
|
|
62
|
+
} else {
|
|
63
|
+
this.resolvedRelations.set(name, filtered);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.schemas.delete(id);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get a registered ontology schema by ID.
|
|
72
|
+
*/
|
|
73
|
+
get(id: string): OntologySchema | undefined {
|
|
74
|
+
return this.schemas.get(id);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* List all registered ontology schemas.
|
|
79
|
+
*/
|
|
80
|
+
list(): OntologySchema[] {
|
|
81
|
+
return [...this.schemas.values()];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get the resolved entity definition for an entity type name.
|
|
86
|
+
* Returns the entity def with inherited attributes merged in.
|
|
87
|
+
*/
|
|
88
|
+
getEntityDef(typeName: string): EntityDef | undefined {
|
|
89
|
+
return this.resolvedEntities.get(typeName)?.def;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the ontology ID that defines a given entity type.
|
|
94
|
+
*/
|
|
95
|
+
getEntityOntology(typeName: string): string | undefined {
|
|
96
|
+
return this.resolvedEntities.get(typeName)?.ontologyId;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* List all known entity type names.
|
|
101
|
+
*/
|
|
102
|
+
listEntityTypes(): string[] {
|
|
103
|
+
return [...this.resolvedEntities.keys()];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get all relation definitions involving a given entity type
|
|
108
|
+
* (either as source or target).
|
|
109
|
+
*/
|
|
110
|
+
getRelationsForType(typeName: string): RelationDef[] {
|
|
111
|
+
const results: RelationDef[] = [];
|
|
112
|
+
for (const [, entries] of this.resolvedRelations) {
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
if (
|
|
115
|
+
entry.def.sourceTypes.includes(typeName) ||
|
|
116
|
+
entry.def.targetTypes.includes(typeName)
|
|
117
|
+
) {
|
|
118
|
+
results.push(entry.def);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return results;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get a specific relation definition by name.
|
|
127
|
+
*/
|
|
128
|
+
getRelationDef(name: string): RelationDef | undefined {
|
|
129
|
+
const entries = this.resolvedRelations.get(name);
|
|
130
|
+
return entries?.[0]?.def;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* List all known relation names.
|
|
135
|
+
*/
|
|
136
|
+
listRelationNames(): string[] {
|
|
137
|
+
return [...this.resolvedRelations.keys()];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Check if an entity type is known to any registered ontology.
|
|
142
|
+
*/
|
|
143
|
+
hasEntityType(typeName: string): boolean {
|
|
144
|
+
return this.resolvedEntities.has(typeName);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get the required attributes for an entity type.
|
|
149
|
+
*/
|
|
150
|
+
getRequiredAttributes(typeName: string): AttributeDef[] {
|
|
151
|
+
const def = this.getEntityDef(typeName);
|
|
152
|
+
if (!def) return [];
|
|
153
|
+
return def.attributes.filter((a) => a.required);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// -------------------------------------------------------------------------
|
|
157
|
+
// Resolution (inheritance)
|
|
158
|
+
// -------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
private _resolve(schema: OntologySchema): void {
|
|
161
|
+
// Register entities
|
|
162
|
+
for (const entity of schema.entities) {
|
|
163
|
+
const resolved = this._resolveEntity(entity, schema);
|
|
164
|
+
this.resolvedEntities.set(entity.name, {
|
|
165
|
+
def: resolved,
|
|
166
|
+
ontologyId: schema.id,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Register relations
|
|
171
|
+
for (const relation of schema.relations) {
|
|
172
|
+
const existing = this.resolvedRelations.get(relation.name) ?? [];
|
|
173
|
+
existing.push({ def: relation, ontologyId: schema.id });
|
|
174
|
+
this.resolvedRelations.set(relation.name, existing);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private _resolveEntity(entity: EntityDef, schema: OntologySchema): EntityDef {
|
|
179
|
+
if (!entity.extends) return entity;
|
|
180
|
+
|
|
181
|
+
// Find parent — check current schema first, then all registered
|
|
182
|
+
let parent = schema.entities.find((e) => e.name === entity.extends);
|
|
183
|
+
if (!parent) {
|
|
184
|
+
const resolved = this.resolvedEntities.get(entity.extends!);
|
|
185
|
+
parent = resolved?.def;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (!parent) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
`Entity "${entity.name}" extends "${entity.extends}" which is not defined.`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Resolve parent first (recursive)
|
|
195
|
+
const resolvedParent = this._resolveEntity(parent, schema);
|
|
196
|
+
|
|
197
|
+
// Merge: child attributes override parent attributes with same name
|
|
198
|
+
const childAttrNames = new Set(entity.attributes.map((a) => a.name));
|
|
199
|
+
const mergedAttrs = [
|
|
200
|
+
...resolvedParent.attributes.filter((a) => !childAttrNames.has(a.name)),
|
|
201
|
+
...entity.attributes,
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
...entity,
|
|
206
|
+
attributes: mergedAttrs,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ontology Type System — Declarative schemas for entity types, attributes,
|
|
3
|
+
* constraints, and relationships.
|
|
4
|
+
*
|
|
5
|
+
* Ontologies define the "shape" of entities in the graph. They are used for:
|
|
6
|
+
* - Schema validation (reject mutations that violate constraints)
|
|
7
|
+
* - Documentation (describe what entity types exist and their attributes)
|
|
8
|
+
* - Code generation and tooling (auto-complete, type checking)
|
|
9
|
+
*
|
|
10
|
+
* @module trellis/core/ontology
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Atom } from '../store/eav-store.js';
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Attribute types
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
export type AttrType = 'string' | 'number' | 'boolean' | 'date' | 'ref' | 'any';
|
|
20
|
+
|
|
21
|
+
export interface AttributeDef {
|
|
22
|
+
/** Attribute name (fact key). */
|
|
23
|
+
name: string;
|
|
24
|
+
/** Expected value type. */
|
|
25
|
+
type: AttrType;
|
|
26
|
+
/** Human-readable description. */
|
|
27
|
+
description?: string;
|
|
28
|
+
/** Whether this attribute is required on entity creation. */
|
|
29
|
+
required?: boolean;
|
|
30
|
+
/** Whether only one value is allowed (default: true). */
|
|
31
|
+
unique?: boolean;
|
|
32
|
+
/** Default value if not provided. */
|
|
33
|
+
default?: Atom;
|
|
34
|
+
/** Allowed values (enum constraint). */
|
|
35
|
+
enum?: Atom[];
|
|
36
|
+
/** Regex pattern for string values. */
|
|
37
|
+
pattern?: string;
|
|
38
|
+
/** Minimum value (for numbers) or min length (for strings). */
|
|
39
|
+
min?: number;
|
|
40
|
+
/** Maximum value (for numbers) or max length (for strings). */
|
|
41
|
+
max?: number;
|
|
42
|
+
/** If type is 'ref', the target entity type(s) this can reference. */
|
|
43
|
+
refTypes?: string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Relation types
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
export interface RelationDef {
|
|
51
|
+
/** Relation attribute name (link key). */
|
|
52
|
+
name: string;
|
|
53
|
+
/** Human-readable description. */
|
|
54
|
+
description?: string;
|
|
55
|
+
/** Source entity type(s) that can have this relation. */
|
|
56
|
+
sourceTypes: string[];
|
|
57
|
+
/** Target entity type(s) this relation can point to. */
|
|
58
|
+
targetTypes: string[];
|
|
59
|
+
/** Cardinality: 'one' = at most one target, 'many' = unlimited. */
|
|
60
|
+
cardinality?: 'one' | 'many';
|
|
61
|
+
/** Whether this relation is required. */
|
|
62
|
+
required?: boolean;
|
|
63
|
+
/** Inverse relation name (auto-created on the target). */
|
|
64
|
+
inverse?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Entity type definitions
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
export interface EntityDef {
|
|
72
|
+
/** Entity type name (e.g. "Project", "User", "Agent"). */
|
|
73
|
+
name: string;
|
|
74
|
+
/** Human-readable description. */
|
|
75
|
+
description?: string;
|
|
76
|
+
/** Attribute definitions for this entity type. */
|
|
77
|
+
attributes: AttributeDef[];
|
|
78
|
+
/** Whether this entity type is abstract (cannot be instantiated directly). */
|
|
79
|
+
abstract?: boolean;
|
|
80
|
+
/** Parent entity type (for inheritance). */
|
|
81
|
+
extends?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Ontology Schema
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
export interface OntologySchema {
|
|
89
|
+
/** Unique ontology identifier (e.g. "trellis:project", "trellis:team"). */
|
|
90
|
+
id: string;
|
|
91
|
+
/** Human-readable name. */
|
|
92
|
+
name: string;
|
|
93
|
+
/** Semantic version. */
|
|
94
|
+
version: string;
|
|
95
|
+
/** Human-readable description. */
|
|
96
|
+
description?: string;
|
|
97
|
+
/** Entity type definitions. */
|
|
98
|
+
entities: EntityDef[];
|
|
99
|
+
/** Relation definitions. */
|
|
100
|
+
relations: RelationDef[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Validation result
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
export interface ValidationError {
|
|
108
|
+
/** Entity ID that failed validation. */
|
|
109
|
+
entityId: string;
|
|
110
|
+
/** Entity type. */
|
|
111
|
+
entityType: string;
|
|
112
|
+
/** Which attribute or relation failed. */
|
|
113
|
+
field: string;
|
|
114
|
+
/** Error message. */
|
|
115
|
+
message: string;
|
|
116
|
+
/** Severity: 'error' = hard failure, 'warning' = advisory. */
|
|
117
|
+
severity: 'error' | 'warning';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface ValidationResult {
|
|
121
|
+
valid: boolean;
|
|
122
|
+
errors: ValidationError[];
|
|
123
|
+
warnings: ValidationError[];
|
|
124
|
+
}
|