(rootDir: string, threshold?: number)
| 249 | } |
| 250 | |
| 251 | export async function pruneStaleLinks(rootDir: string, threshold?: number): Promise<{ removed: number; remaining: number }> { |
| 252 | const graph = await loadGraph(rootDir); |
| 253 | const cutoff = threshold ?? STALE_THRESHOLD; |
| 254 | const toRemove: string[] = []; |
| 255 | |
| 256 | for (const [edgeId, edge] of Object.entries(graph.edges)) { |
| 257 | if (decayWeight(edge) < cutoff) toRemove.push(edgeId); |
| 258 | } |
| 259 | |
| 260 | for (const id of toRemove) delete graph.edges[id]; |
| 261 | |
| 262 | const orphanNodeIds = Object.keys(graph.nodes).filter(nodeId => |
| 263 | getEdgesForNode(graph, nodeId).length === 0 |
| 264 | && graph.nodes[nodeId].accessCount <= 1 |
| 265 | && (Date.now() - graph.nodes[nodeId].lastAccessed) > 7 * 86_400_000 |
| 266 | ); |
| 267 | for (const id of orphanNodeIds) delete graph.nodes[id]; |
| 268 | |
| 269 | scheduleSave(rootDir); |
| 270 | return { removed: toRemove.length + orphanNodeIds.length, remaining: Object.keys(graph.edges).length }; |
| 271 | } |
| 272 | |
| 273 | export async function addInterlinkedContext(rootDir: string, items: Array<{ type: NodeType; label: string; content: string; metadata?: Record<string, string> }>, autoLink: boolean = true): Promise<{ nodes: MemoryNode[]; edges: MemoryEdge[] }> { |
| 274 | const createdNodes: MemoryNode[] = []; |
no test coverage detected