UNPKG

aiwg

Version:

Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo

160 lines 5.51 kB
/** * Graphology Graph Backend * * Optional implementation of GraphBackend using the graphology library. * Provides typed/attributed edges, BFS/DFS traversal, community detection, * and shortest-path algorithms. * * Install: npm install graphology graphology-types graphology-operators graphology-traversal * * @implements #728 * @source @src/artifacts/graph-backend.ts * @tests @test/unit/artifacts/graphology-backend.test.ts */ import { normalizeEdges } from '../types.js'; /** * Graphology-backed graph with rich traversal and operator ecosystem. * * Uses dynamic import so the graphology package is only loaded when this * backend is explicitly selected. Projects that don't install graphology * pay zero cost. */ export class GraphologyBackend { // eslint-disable-next-line @typescript-eslint/no-explicit-any graph; constructor(graphInstance) { this.graph = graphInstance; } /** * Factory: creates a GraphologyBackend with a fresh directed multigraph. * Throws a clear error if graphology is not installed. */ static async create() { try { const graphology = await import('graphology'); const Graph = graphology.default ?? graphology; const graph = new Graph({ type: 'directed', multi: true }); return new GraphologyBackend(graph); } catch { throw new Error('graphology backend requires: npm install graphology graphology-types graphology-operators graphology-traversal'); } } // --- Mutation --- addNode(id, attrs) { if (!this.graph.hasNode(id)) { this.graph.addNode(id, attrs ?? {}); } else if (attrs) { this.graph.mergeNodeAttributes(id, attrs); } } addEdge(source, target, type = 'depends-on', attrs) { if (!this.graph.hasNode(source)) this.graph.addNode(source, {}); if (!this.graph.hasNode(target)) this.graph.addNode(target, {}); this.graph.addEdge(source, target, { type, ...attrs }); } // --- Query --- hasNode(id) { return this.graph.hasNode(id); } hasEdge(source, target, edgeType) { if (!edgeType) return this.graph.hasEdge(source, target); const edges = this.graph.edges(source, target); return edges.some((e) => this.graph.getEdgeAttribute(e, 'type') === edgeType); } getNodeAttrs(id) { if (!this.graph.hasNode(id)) return undefined; return this.graph.getNodeAttributes(id); } nodes() { return this.graph.nodes(); } // --- Traversal --- neighbors(nodeId, direction, edgeType) { if (!this.graph.hasNode(nodeId)) return []; let edgeIterator; if (direction === 'in') { edgeIterator = this.graph.inEdges(nodeId); } else if (direction === 'out') { edgeIterator = this.graph.outEdges(nodeId); } else { edgeIterator = this.graph.edges(nodeId); } const results = new Set(); for (const edgeKey of edgeIterator) { if (edgeType && this.graph.getEdgeAttribute(edgeKey, 'type') !== edgeType) continue; const src = this.graph.source(edgeKey); const tgt = this.graph.target(edgeKey); // Add the "other" node results.add(src === nodeId ? tgt : src); } return [...results]; } // --- Set operations --- intersection(setA, setB) { const b = new Set(setB); return setA.filter(x => b.has(x)); } difference(setA, setB) { const b = new Set(setB); return setA.filter(x => !b.has(x)); } union(setA, setB) { return [...new Set([...setA, ...setB])]; } // --- Persistence --- serialize() { const result = {}; this.graph.forEachNode((id) => { const upstream = []; const downstream = []; for (const edgeKey of this.graph.inEdges(id)) { upstream.push({ path: this.graph.source(edgeKey), type: this.graph.getEdgeAttribute(edgeKey, 'type') ?? 'depends-on', }); } for (const edgeKey of this.graph.outEdges(id)) { downstream.push({ path: this.graph.target(edgeKey), type: this.graph.getEdgeAttribute(edgeKey, 'type') ?? 'depends-on', }); } result[id] = { upstream, downstream }; }); return result; } deserialize(data) { this.graph.clear(); // First pass: add all declared nodes for (const id of Object.keys(data)) { if (!this.graph.hasNode(id)) this.graph.addNode(id, {}); } // Second pass: add edges (upstream edges define the directed relationships) for (const [id, node] of Object.entries(data)) { const upEdges = normalizeEdges(node.upstream); for (const edge of upEdges) { if (!this.graph.hasNode(edge.path)) this.graph.addNode(edge.path, {}); this.graph.addEdge(edge.path, id, { type: edge.type }); } } } nodeCount() { return this.graph.order; } edgeCount() { return this.graph.size; } } //# sourceMappingURL=graphology-backend.js.map