@phi-code-admin/phi-code 0.63.2 → 0.63.3

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.
@@ -211,6 +211,134 @@ export default function memoryExtension(pi: ExtensionAPI) {
211
211
  },
212
212
  });
213
213
 
214
+ /**
215
+ * Ontology tool - Add entities and relations to the knowledge graph
216
+ */
217
+ pi.registerTool({
218
+ name: "ontology_add",
219
+ label: "Ontology Add",
220
+ description: "Add an entity or relation to the project knowledge graph. Entities represent things (projects, files, services, people). Relations connect them.",
221
+ promptGuidelines: [
222
+ "When discovering project architecture (services, databases, APIs), add entities and relations to the ontology.",
223
+ "When learning about how components connect, add relations (e.g. 'api-server' → 'uses' → 'postgres-db').",
224
+ ],
225
+ parameters: Type.Object({
226
+ type: Type.Union([Type.Literal("entity"), Type.Literal("relation")], { description: "What to add: 'entity' or 'relation'" }),
227
+ // Entity fields
228
+ entityType: Type.Optional(Type.String({ description: "Entity type (e.g. Project, Service, Database, File, Person, Tool)" })),
229
+ name: Type.Optional(Type.String({ description: "Entity name (e.g. 'my-api', 'postgres-db')" })),
230
+ properties: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "Key-value properties (e.g. {language: 'TypeScript', port: '3000'})" })),
231
+ // Relation fields
232
+ from: Type.Optional(Type.String({ description: "Source entity ID" })),
233
+ to: Type.Optional(Type.String({ description: "Target entity ID" })),
234
+ relationType: Type.Optional(Type.String({ description: "Relation type (e.g. 'uses', 'depends-on', 'deployed-on', 'created-by')" })),
235
+ }),
236
+
237
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
238
+ const p = params as any;
239
+ try {
240
+ if (p.type === "entity") {
241
+ if (!p.entityType || !p.name) {
242
+ return { content: [{ type: "text", text: "Entity requires 'entityType' and 'name'" }], isError: true };
243
+ }
244
+ const id = sigmaMemory.ontology.addEntity({
245
+ type: p.entityType,
246
+ name: p.name,
247
+ properties: p.properties || {},
248
+ });
249
+ return {
250
+ content: [{ type: "text", text: `Entity added: **${p.name}** (${p.entityType}) — ID: \`${id}\`` }],
251
+ details: { id, type: p.entityType, name: p.name },
252
+ };
253
+ } else if (p.type === "relation") {
254
+ if (!p.from || !p.to || !p.relationType) {
255
+ return { content: [{ type: "text", text: "Relation requires 'from', 'to', and 'relationType'" }], isError: true };
256
+ }
257
+ const id = sigmaMemory.ontology.addRelation({
258
+ from: p.from,
259
+ to: p.to,
260
+ type: p.relationType,
261
+ properties: p.properties || {},
262
+ });
263
+ return {
264
+ content: [{ type: "text", text: `Relation added: \`${p.from}\` → **${p.relationType}** → \`${p.to}\` — ID: \`${id}\`` }],
265
+ details: { id, from: p.from, to: p.to, type: p.relationType },
266
+ };
267
+ }
268
+ return { content: [{ type: "text", text: "Type must be 'entity' or 'relation'" }], isError: true };
269
+ } catch (error) {
270
+ return { content: [{ type: "text", text: `Ontology error: ${error}` }], isError: true };
271
+ }
272
+ },
273
+ });
274
+
275
+ /**
276
+ * Ontology query tool - Query the knowledge graph
277
+ */
278
+ pi.registerTool({
279
+ name: "ontology_query",
280
+ label: "Ontology Query",
281
+ description: "Query the project knowledge graph. Find entities by type/name, get relations, find paths between entities, or get stats.",
282
+ parameters: Type.Object({
283
+ action: Type.Union([
284
+ Type.Literal("find"),
285
+ Type.Literal("relations"),
286
+ Type.Literal("path"),
287
+ Type.Literal("stats"),
288
+ Type.Literal("graph"),
289
+ ], { description: "Query action: find (entities), relations (of entity), path (between entities), stats, graph (full export)" }),
290
+ entityType: Type.Optional(Type.String({ description: "Filter by entity type (for 'find' action)" })),
291
+ name: Type.Optional(Type.String({ description: "Filter by name (partial match, for 'find' action)" })),
292
+ entityId: Type.Optional(Type.String({ description: "Entity ID (for 'relations' action)" })),
293
+ fromId: Type.Optional(Type.String({ description: "Source entity ID (for 'path' action)" })),
294
+ toId: Type.Optional(Type.String({ description: "Target entity ID (for 'path' action)" })),
295
+ }),
296
+
297
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
298
+ const p = params as any;
299
+ try {
300
+ switch (p.action) {
301
+ case "find": {
302
+ const results = sigmaMemory.ontology.findEntity({ type: p.entityType, name: p.name });
303
+ if (results.length === 0) return { content: [{ type: "text", text: "No entities found." }] };
304
+ const text = results.map(e => `- **${e.name}** (${e.type}) ID:\`${e.id}\` ${JSON.stringify(e.properties)}`).join("\n");
305
+ return { content: [{ type: "text", text: `Found ${results.length} entities:\n${text}` }] };
306
+ }
307
+ case "relations": {
308
+ if (!p.entityId) return { content: [{ type: "text", text: "'entityId' required" }], isError: true };
309
+ const rels = sigmaMemory.ontology.findRelations(p.entityId);
310
+ if (rels.length === 0) return { content: [{ type: "text", text: "No relations found." }] };
311
+ const text = rels.map(r => `- \`${r.from}\` → **${r.type}** → \`${r.to}\``).join("\n");
312
+ return { content: [{ type: "text", text: `Found ${rels.length} relations:\n${text}` }] };
313
+ }
314
+ case "path": {
315
+ if (!p.fromId || !p.toId) return { content: [{ type: "text", text: "'fromId' and 'toId' required" }], isError: true };
316
+ const path = sigmaMemory.ontology.queryPath(p.fromId, p.toId);
317
+ if (!path) return { content: [{ type: "text", text: "No path found between these entities." }] };
318
+ const text = path.map(s => `${s.entity.name}${s.relation ? ` → [${s.relation.type}]` : ""}`).join(" → ");
319
+ return { content: [{ type: "text", text: `Path: ${text}` }] };
320
+ }
321
+ case "stats": {
322
+ const stats = sigmaMemory.ontology.stats();
323
+ const graph = sigmaMemory.ontology.getGraph();
324
+ let text = `**Ontology Stats:**\n- Entities: ${graph.entities.length}\n- Relations: ${graph.relations.length}\n`;
325
+ text += `\nBy type:\n`;
326
+ for (const [type, count] of Object.entries(stats.entitiesByType)) text += ` - ${type}: ${count}\n`;
327
+ return { content: [{ type: "text", text }] };
328
+ }
329
+ case "graph": {
330
+ const graph = sigmaMemory.ontology.export();
331
+ return { content: [{ type: "text", text: JSON.stringify(graph, null, 2) }] };
332
+ }
333
+ default:
334
+ return { content: [{ type: "text", text: "Action must be: find, relations, path, stats, graph" }], isError: true };
335
+ }
336
+ } catch (error) {
337
+ return { content: [{ type: "text", text: `Ontology query error: ${error}` }], isError: true };
338
+ }
339
+ },
340
+ });
341
+
214
342
  /**
215
343
  * Memory status tool - Get status of all memory subsystems
216
344
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phi-code-admin/phi-code",
3
- "version": "0.63.2",
3
+ "version": "0.63.3",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {