{"version":3,"sources":["../src/core/topology.ts","../src/core/workspace.ts"],"names":["id"],"mappings":"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","sourcesContent":["import { SPHERES } from \"./constants\";\nimport { createTree } from \"./factory\";\nimport { SystemKey } from \"./systems/registry\";\nimport {\n  id,\n  KaabalahTypes,\n  Node,\n  NodeData,\n  NodeId,\n  NodeType,\n  parseId,\n} from \"./types\";\nimport { TreeOfLife } from \"./tree-of-life\";\n\nexport type TreeTopologySphereName =\n  (typeof TREE_TOPOLOGY_SPHERE_NAMES)[number];\nexport type TreeTopologySphereId = NodeId<KaabalahTypes.SPHERE>;\nexport type TreeTopologyPathId = NodeId<KaabalahTypes.PATH>;\nexport type TreeTopologySphereRole = \"sephirah\" | \"hidden\";\nexport type TreeTopologyRouteKey = \"lightning\" | \"serpent\";\nexport type TreeTopologyRouteDirection = \"descending\" | \"ascending\";\n\nexport const TREE_TOPOLOGY_SPHERE_NAMES = [\n  SPHERES.KETHER,\n  SPHERES.CHOKHMAH,\n  SPHERES.BINAH,\n  SPHERES.DAATH,\n  SPHERES.CHESED,\n  SPHERES.GEBURAH,\n  SPHERES.TIPHARETH,\n  SPHERES.NETZACH,\n  SPHERES.HOD,\n  SPHERES.YESOD,\n  SPHERES.MALKUTH,\n] as const;\n\nexport const TREE_TOPOLOGY_SPHERE_IDS = TREE_TOPOLOGY_SPHERE_NAMES.map(\n  (name) => id(KaabalahTypes.SPHERE, name)\n) as readonly TreeTopologySphereId[];\n\nexport const TREE_TOPOLOGY_PATH_IDS = Array.from(\n  { length: 22 },\n  (_, index) => id(KaabalahTypes.PATH, index + 1)\n) as readonly TreeTopologyPathId[];\n\nconst TREE_TOPOLOGY_SPHERE_NUMBERS = {\n  [SPHERES.KETHER]: 1,\n  [SPHERES.CHOKHMAH]: 2,\n  [SPHERES.BINAH]: 3,\n  [SPHERES.DAATH]: 11,\n  [SPHERES.CHESED]: 4,\n  [SPHERES.GEBURAH]: 5,\n  [SPHERES.TIPHARETH]: 6,\n  [SPHERES.NETZACH]: 7,\n  [SPHERES.HOD]: 8,\n  [SPHERES.YESOD]: 9,\n  [SPHERES.MALKUTH]: 10,\n} as const satisfies Record<TreeTopologySphereName, number>;\n\nexport const TREE_TOPOLOGY_LIGHTNING_SPHERE_NAMES = [\n  SPHERES.KETHER,\n  SPHERES.CHOKHMAH,\n  SPHERES.BINAH,\n  SPHERES.CHESED,\n  SPHERES.GEBURAH,\n  SPHERES.TIPHARETH,\n  SPHERES.NETZACH,\n  SPHERES.HOD,\n  SPHERES.YESOD,\n  SPHERES.MALKUTH,\n] as const satisfies readonly TreeTopologySphereName[];\n\nexport interface TreeTopologySphere {\n  id: TreeTopologySphereId;\n  name: TreeTopologySphereName;\n  number: number;\n  role: TreeTopologySphereRole;\n  data?: NodeData<KaabalahTypes.SPHERE>;\n}\n\nexport interface TreeTopologyPath {\n  id: TreeTopologyPathId;\n  number: number;\n  from: TreeTopologySphere;\n  to: TreeTopologySphere;\n  data: NodeData<KaabalahTypes.PATH>;\n}\n\nexport interface TreeTopologyAdjacentSphere {\n  sphere: TreeTopologySphere;\n  path: TreeTopologyPath;\n  direction: \"forward\" | \"reverse\";\n}\n\nexport interface TreeTopologyRouteSegment {\n  index: number;\n  from: TreeTopologySphere;\n  to: TreeTopologySphere;\n  path?: TreeTopologyPath;\n  isConnected: boolean;\n}\n\nexport interface TreeTopologyRouteTarget {\n  targetId: TreeTopologySphereId | TreeTopologyPathId;\n  targetType: \"sphere\" | \"path\";\n}\n\nexport interface TreeTopologyRoute {\n  key: TreeTopologyRouteKey;\n  name: string;\n  direction: TreeTopologyRouteDirection;\n  spheres: readonly TreeTopologySphere[];\n  segments: readonly TreeTopologyRouteSegment[];\n  isFullyConnected: boolean;\n  missingSegments: readonly TreeTopologyRouteSegment[];\n  targets: readonly TreeTopologyRouteTarget[];\n  targetIds: readonly (TreeTopologySphereId | TreeTopologyPathId)[];\n}\n\nexport type TreeTopologySphereLookup =\n  | TreeTopologySphereName\n  | TreeTopologySphereId\n  | {\n      id?: TreeTopologySphereId;\n      name?: TreeTopologySphereName | string;\n      number?: number;\n    };\n\nexport type TreeTopologyPathLookup =\n  | number\n  | TreeTopologyPathId\n  | {\n      id?: TreeTopologyPathId;\n      number?: number;\n      between?: readonly [TreeTopologySphereLookup, TreeTopologySphereLookup];\n    };\n\nexport interface TreeTopologyOptions {\n  system?: SystemKey;\n  tree?: TreeOfLife;\n}\n\nexport interface GetTreeTopologySpheresOptions {\n  includeDaath?: boolean;\n}\n\nfunction isNodeType<T extends NodeType>(\n  node: Node<NodeType>,\n  type: T\n): node is Node<T> {\n  return node.type === type;\n}\n\nfunction cloneSphereData(data?: NodeData<KaabalahTypes.SPHERE>) {\n  return data ? { ...data } : undefined;\n}\n\nfunction clonePathData(data: NodeData<KaabalahTypes.PATH>) {\n  return { ...data };\n}\n\nfunction parsePathNumber(pathId: TreeTopologyPathId) {\n  const parsed = Number.parseInt(parseId(pathId), 10);\n\n  if (!Number.isInteger(parsed)) {\n    throw new Error(`Invalid tree path id: ${pathId}`);\n  }\n\n  return parsed;\n}\n\nfunction normalizeName(value: string) {\n  return value.trim().toLowerCase();\n}\n\nfunction pairKey(left: TreeTopologySphereId, right: TreeTopologySphereId) {\n  return [String(left), String(right)].sort().join(\"|\");\n}\n\nfunction routeNames() {\n  return [...TREE_TOPOLOGY_LIGHTNING_SPHERE_NAMES];\n}\n\nfunction routeDescriptor(key: TreeTopologyRouteKey) {\n  return key === \"lightning\"\n    ? {\n        name: \"Lightning Path\",\n        direction: \"descending\" as const,\n      }\n    : {\n        name: \"Serpent Path\",\n        direction: \"ascending\" as const,\n      };\n}\n\nfunction routeTargetList(segments: readonly TreeTopologyRouteSegment[]) {\n  if (segments.length === 0) {\n    return [] as TreeTopologyRouteTarget[];\n  }\n\n  const targets: TreeTopologyRouteTarget[] = [\n    { targetId: segments[0].from.id, targetType: \"sphere\" },\n  ];\n\n  for (const segment of segments) {\n    if (segment.path) {\n      targets.push({ targetId: segment.path.id, targetType: \"path\" });\n    }\n\n    targets.push({ targetId: segment.to.id, targetType: \"sphere\" });\n  }\n\n  return targets;\n}\n\nexport class TreeTopology {\n  public readonly system: SystemKey;\n\n  private readonly spheres: readonly TreeTopologySphere[];\n  private readonly paths: readonly TreeTopologyPath[];\n  private readonly spheresById = new Map<\n    TreeTopologySphereId,\n    TreeTopologySphere\n  >();\n  private readonly spheresByName = new Map<string, TreeTopologySphere>();\n  private readonly spheresByNumber = new Map<number, TreeTopologySphere>();\n  private readonly pathsById = new Map<TreeTopologyPathId, TreeTopologyPath>();\n  private readonly pathsByNumber = new Map<number, TreeTopologyPath>();\n  private readonly pathsBySpherePair = new Map<string, TreeTopologyPath>();\n  private readonly routesByKey = new Map<\n    TreeTopologyRouteKey,\n    TreeTopologyRoute\n  >();\n\n  constructor({\n    system,\n    spheres,\n    paths,\n  }: {\n    system: SystemKey;\n    spheres: readonly TreeTopologySphere[];\n    paths: readonly TreeTopologyPath[];\n  }) {\n    this.system = system;\n    this.spheres = spheres.map((sphere) =>\n      Object.freeze({\n        ...sphere,\n        data: cloneSphereData(sphere.data),\n      })\n    );\n\n    for (const sphere of this.spheres) {\n      this.spheresById.set(sphere.id, sphere);\n      this.spheresByName.set(normalizeName(sphere.name), sphere);\n      this.spheresByNumber.set(sphere.number, sphere);\n    }\n\n    this.paths = paths.map((path) => {\n      const from = this.spheresById.get(path.from.id);\n      const to = this.spheresById.get(path.to.id);\n\n      if (!from || !to) {\n        throw new Error(\n          `Tree topology path ${path.id} references unknown spheres.`\n        );\n      }\n\n      return Object.freeze({\n        ...path,\n        from,\n        to,\n        data: clonePathData(path.data),\n      });\n    });\n\n    for (const path of this.paths) {\n      this.pathsById.set(path.id, path);\n      this.pathsByNumber.set(path.number, path);\n      this.pathsBySpherePair.set(pairKey(path.from.id, path.to.id), path);\n    }\n\n    for (const key of [\"lightning\", \"serpent\"] as const) {\n      this.routesByKey.set(key, this.buildRoute(key));\n    }\n  }\n\n  getSpheres(options: GetTreeTopologySpheresOptions = {}) {\n    const includeDaath = options.includeDaath ?? true;\n\n    return includeDaath\n      ? [...this.spheres]\n      : this.spheres.filter((sphere) => sphere.name !== SPHERES.DAATH);\n  }\n\n  getPrimarySpheres() {\n    return this.getSpheres({ includeDaath: false });\n  }\n\n  getSphere(lookup: TreeTopologySphereLookup) {\n    if (typeof lookup === \"string\") {\n      if (lookup.startsWith(`${KaabalahTypes.SPHERE}:`)) {\n        return this.spheresById.get(lookup as TreeTopologySphereId);\n      }\n\n      return this.spheresByName.get(normalizeName(lookup));\n    }\n\n    if (lookup.id) {\n      return this.spheresById.get(lookup.id);\n    }\n\n    if (lookup.number) {\n      return this.spheresByNumber.get(lookup.number);\n    }\n\n    if (lookup.name) {\n      return this.spheresByName.get(normalizeName(lookup.name));\n    }\n\n    return undefined;\n  }\n\n  getPaths() {\n    return [...this.paths];\n  }\n\n  getPath(lookup: TreeTopologyPathLookup) {\n    if (typeof lookup === \"number\") {\n      return this.pathsByNumber.get(lookup);\n    }\n\n    if (typeof lookup === \"string\") {\n      return this.pathsById.get(lookup as TreeTopologyPathId);\n    }\n\n    if (lookup.id) {\n      return this.pathsById.get(lookup.id);\n    }\n\n    if (lookup.number) {\n      return this.pathsByNumber.get(lookup.number);\n    }\n\n    if (lookup.between) {\n      return this.getPathBetween(lookup.between[0], lookup.between[1]);\n    }\n\n    return undefined;\n  }\n\n  getPathBetween(\n    first: TreeTopologySphereLookup,\n    second: TreeTopologySphereLookup\n  ) {\n    const firstSphere = this.getSphere(first);\n    const secondSphere = this.getSphere(second);\n\n    if (!firstSphere || !secondSphere) {\n      return undefined;\n    }\n\n    return this.pathsBySpherePair.get(pairKey(firstSphere.id, secondSphere.id));\n  }\n\n  getAdjacentSpheres(\n    sphereLookup: TreeTopologySphereLookup\n  ): TreeTopologyAdjacentSphere[] {\n    const sphere = this.getSphere(sphereLookup);\n\n    if (!sphere) {\n      return [];\n    }\n\n    return this.paths\n      .filter((path) => path.from.id === sphere.id || path.to.id === sphere.id)\n      .map((path) => {\n        const isForward = path.from.id === sphere.id;\n\n        return {\n          sphere: isForward ? path.to : path.from,\n          path,\n          direction: isForward ? \"forward\" : \"reverse\",\n        };\n      });\n  }\n\n  getRoutes() {\n    return [...this.routesByKey.values()];\n  }\n\n  getRoute(key: TreeTopologyRouteKey) {\n    return this.routesByKey.get(key);\n  }\n\n  nextInRoute(\n    routeKey: TreeTopologyRouteKey,\n    sphereLookup: TreeTopologySphereLookup\n  ) {\n    const route = this.getRoute(routeKey);\n    const sphere = this.getSphere(sphereLookup);\n\n    if (!route || !sphere) {\n      return undefined;\n    }\n\n    const index = route.spheres.findIndex(\n      (routeSphere) => routeSphere.id === sphere.id\n    );\n\n    return index >= 0 ? route.spheres[index + 1] : undefined;\n  }\n\n  previousInRoute(\n    routeKey: TreeTopologyRouteKey,\n    sphereLookup: TreeTopologySphereLookup\n  ) {\n    const route = this.getRoute(routeKey);\n    const sphere = this.getSphere(sphereLookup);\n\n    if (!route || !sphere) {\n      return undefined;\n    }\n\n    const index = route.spheres.findIndex(\n      (routeSphere) => routeSphere.id === sphere.id\n    );\n\n    return index > 0 ? route.spheres[index - 1] : undefined;\n  }\n\n  private buildRoute(key: TreeTopologyRouteKey): TreeTopologyRoute {\n    const descriptor = routeDescriptor(key);\n    const names = routeNames();\n    const orderedNames = key === \"serpent\" ? names.reverse() : names;\n    const spheres = orderedNames.map((name) => {\n      const sphere = this.getSphere(name);\n\n      if (!sphere) {\n        throw new Error(\n          `Tree topology route \"${key}\" references missing sphere \"${name}\" in ${this.system}.`\n        );\n      }\n\n      return sphere;\n    });\n    const segments: TreeTopologyRouteSegment[] = [];\n\n    for (let index = 0; index < spheres.length - 1; index++) {\n      const from = spheres[index];\n      const to = spheres[index + 1];\n      const path = this.getPathBetween(from.name, to.name);\n\n      segments.push({\n        index,\n        from,\n        to,\n        path,\n        isConnected: Boolean(path),\n      });\n    }\n\n    const targets = routeTargetList(segments);\n    const missingSegments = segments.filter((segment) => !segment.isConnected);\n\n    return Object.freeze({\n      key,\n      name: descriptor.name,\n      direction: descriptor.direction,\n      spheres: Object.freeze([...spheres]),\n      segments: Object.freeze(segments),\n      isFullyConnected: missingSegments.length === 0,\n      missingSegments: Object.freeze(missingSegments),\n      targets: Object.freeze(targets),\n      targetIds: Object.freeze(targets.map((target) => target.targetId)),\n    });\n  }\n}\n\nexport function getTreeTopology(options: TreeTopologyOptions = {}) {\n  const system = options.system ?? options.tree?.activeSystem ?? \"kaabalah\";\n  const tree = options.tree ?? createTree({ system });\n  const spheres: TreeTopologySphere[] = [];\n\n  for (const sphereId of TREE_TOPOLOGY_SPHERE_IDS) {\n    const sphereNode = tree.getNode(sphereId);\n\n    if (!sphereNode) {\n      continue;\n    }\n\n    const name = parseId(sphereId) as TreeTopologySphereName;\n\n    spheres.push({\n      id: sphereId,\n      name,\n      number: TREE_TOPOLOGY_SPHERE_NUMBERS[name],\n      role: name === SPHERES.DAATH ? \"hidden\" : \"sephirah\",\n      data: cloneSphereData(sphereNode.data),\n    });\n  }\n\n  const spheresById = new Map(spheres.map((sphere) => [sphere.id, sphere]));\n  const paths = tree\n    .getNodes()\n    .filter((node): node is Node<KaabalahTypes.PATH> =>\n      isNodeType(node, KaabalahTypes.PATH)\n    )\n    .map((pathNode) => {\n      if (!pathNode.data?.from || !pathNode.data?.to) {\n        throw new Error(`Tree topology path ${pathNode.id} is missing endpoints.`);\n      }\n\n      const from = spheresById.get(pathNode.data.from);\n      const to = spheresById.get(pathNode.data.to);\n\n      if (!from || !to) {\n        throw new Error(\n          `Tree topology path ${pathNode.id} references unknown spheres.`\n        );\n      }\n\n      return {\n        id: pathNode.id,\n        number: parsePathNumber(pathNode.id),\n        from,\n        to,\n        data: clonePathData(pathNode.data),\n      } satisfies TreeTopologyPath;\n    })\n    .sort((left, right) => left.number - right.number);\n\n  return new TreeTopology({\n    system,\n    spheres,\n    paths,\n  });\n}\n","import {\n  CorrespondenceEdge,\n  CorrespondenceMap,\n  CorrespondenceMatch,\n  CorrespondenceMetadata,\n  CorrespondenceSource,\n  CorrespondenceStep,\n  TreeNote,\n  TreeNoteTarget,\n  TreeOverlay,\n  TreeWorkspaceDescriptor,\n  makeCorrespondenceId,\n} from \"./correspondence-model\";\nimport { createTree, TreeOptions } from \"./factory\";\nimport { TreeOfLife } from \"./tree-of-life\";\nimport { Node, NodeId, NodeType } from \"./types\";\n\nexport interface TreeCorrespondenceQueryOptions<T extends NodeType = NodeType> {\n  type?: T | readonly T[];\n  depth?: number;\n  includeSelf?: boolean;\n  limit?: number;\n}\n\nexport interface TreeFindNodesOptions<T extends NodeType = NodeType> {\n  type?: T | readonly T[];\n  ids?: readonly NodeId<T>[];\n  search?: string;\n  predicate?: (node: Node<T>) => boolean;\n}\n\nexport interface TreeVisualRequest {\n  nodeId: NodeId<NodeType>;\n  kind?: string;\n  [key: string]: unknown;\n}\n\nexport interface TreeVisualResult {\n  kind: string;\n  nodeId: NodeId<NodeType>;\n  [key: string]: unknown;\n}\n\nexport type TreeVisualResolver = (input: {\n  request: TreeVisualRequest;\n  workspace: TreeWorkspace;\n}) => TreeVisualResult | undefined;\n\nexport interface CreateTreeWorkspaceOptions {\n  base?: TreeWorkspace | TreeOfLife;\n  overlays?: TreeOverlay[];\n  descriptor?: TreeWorkspaceDescriptor;\n  visualResolvers?: TreeVisualResolver[];\n}\n\ntype TreeGraphData = {\n  descriptor: TreeWorkspaceDescriptor;\n  nodesById: Map<NodeId<NodeType>, Node<NodeType>>;\n  nodeIdsByType: Map<NodeType, NodeId<NodeType>[]>;\n  edgesById: Map<string, CorrespondenceEdge>;\n  edgeIdsByNodeId: Map<NodeId<NodeType>, string[]>;\n  notesById: Map<string, TreeNote>;\n  noteIdsByNodeId: Map<NodeId<NodeType>, string[]>;\n  noteIdsByCorrespondenceId: Map<string, string[]>;\n};\n\nfunction cloneNode<T extends NodeType>(node: Node<T>): Node<T> {\n  return Object.freeze({\n    id: node.id,\n    type: node.type,\n    name: node.name,\n    data:\n      node.data && typeof node.data === \"object\"\n        ? ({ ...node.data } as Node<T>[\"data\"])\n        : node.data,\n  });\n}\n\nfunction cloneMetadata(metadata?: CorrespondenceMetadata) {\n  if (!metadata) {\n    return undefined;\n  }\n\n  return {\n    ...metadata,\n    tags: metadata.tags ? [...metadata.tags] : undefined,\n    attributes: metadata.attributes ? { ...metadata.attributes } : undefined,\n  };\n}\n\nfunction cloneSource(source: CorrespondenceSource): CorrespondenceSource {\n  if (source.kind === \"bridge\") {\n    return {\n      ...source,\n      parts: [...source.parts],\n    };\n  }\n\n  return { ...source };\n}\n\nfunction cloneEdge(edge: CorrespondenceEdge): CorrespondenceEdge {\n  return Object.freeze({\n    ...edge,\n    metadata: cloneMetadata(edge.metadata),\n    sources: edge.sources.map(cloneSource),\n  });\n}\n\nfunction cloneNote(note: TreeNote): TreeNote {\n  return Object.freeze({\n    ...note,\n    target: { ...note.target },\n    metadata: note.metadata ? { ...note.metadata } : undefined,\n  });\n}\n\nfunction mergeMetadata(\n  current?: CorrespondenceMetadata,\n  next?: CorrespondenceMetadata\n) {\n  if (!current) {\n    return cloneMetadata(next);\n  }\n\n  if (!next) {\n    return cloneMetadata(current);\n  }\n\n  return {\n    ...current,\n    ...next,\n    tags: [...new Set([...(current.tags ?? []), ...(next.tags ?? [])])],\n    attributes: {\n      ...(current.attributes ?? {}),\n      ...(next.attributes ?? {}),\n    },\n  };\n}\n\nfunction mergeSources(\n  current: readonly CorrespondenceSource[],\n  next: CorrespondenceSource\n) {\n  const seen = new Set<string>();\n  const merged: CorrespondenceSource[] = [];\n\n  for (const source of [...current, next]) {\n    const key = JSON.stringify(source);\n\n    if (seen.has(key)) {\n      continue;\n    }\n\n    seen.add(key);\n    merged.push(cloneSource(source));\n  }\n\n  return merged;\n}\n\nfunction normalizeTypes<T extends NodeType>(\n  type?: T | readonly T[]\n): Set<NodeType> | undefined {\n  if (!type) {\n    return undefined;\n  }\n\n  return new Set(Array.isArray(type) ? type : [type]);\n}\n\nfunction sortNodes<T extends NodeType>(nodes: Node<T>[]) {\n  return [...nodes].sort((left, right) => {\n    if (left.type !== right.type) {\n      return left.type.localeCompare(right.type);\n    }\n\n    const leftLabel = String(left.name ?? left.id);\n    const rightLabel = String(right.name ?? right.id);\n\n    return leftLabel.localeCompare(rightLabel);\n  });\n}\n\nfunction sortMatches<T extends NodeType>(matches: CorrespondenceMatch<T>[]) {\n  return [...matches].sort((left, right) => {\n    if (left.distance !== right.distance) {\n      return left.distance - right.distance;\n    }\n\n    if (left.node.type !== right.node.type) {\n      return left.node.type.localeCompare(right.node.type);\n    }\n\n    const leftLabel = String(left.node.name ?? left.node.id);\n    const rightLabel = String(right.node.name ?? right.node.id);\n\n    return leftLabel.localeCompare(rightLabel);\n  });\n}\n\nfunction createGraphData(\n  descriptor: TreeWorkspaceDescriptor,\n  nodes: Iterable<Node<NodeType>>,\n  edges: Iterable<CorrespondenceEdge>,\n  notes: Iterable<TreeNote>\n): TreeGraphData {\n  const nodesById = new Map<NodeId<NodeType>, Node<NodeType>>();\n  const nodeIdsByType = new Map<NodeType, NodeId<NodeType>[]>();\n  const edgesById = new Map<string, CorrespondenceEdge>();\n  const edgeIdsByNodeId = new Map<NodeId<NodeType>, string[]>();\n  const notesById = new Map<string, TreeNote>();\n  const noteIdsByNodeId = new Map<NodeId<NodeType>, string[]>();\n  const noteIdsByCorrespondenceId = new Map<string, string[]>();\n\n  for (const node of nodes) {\n    const clonedNode = cloneNode(node);\n\n    nodesById.set(clonedNode.id, clonedNode);\n\n    const typedIds = nodeIdsByType.get(clonedNode.type) ?? [];\n    typedIds.push(clonedNode.id as NodeId<NodeType>);\n    nodeIdsByType.set(clonedNode.type, typedIds);\n  }\n\n  for (const edge of edges) {\n    const clonedEdge = cloneEdge(edge);\n\n    edgesById.set(clonedEdge.id, clonedEdge);\n\n    const leftEdges = edgeIdsByNodeId.get(clonedEdge.left) ?? [];\n    leftEdges.push(clonedEdge.id);\n    edgeIdsByNodeId.set(clonedEdge.left, leftEdges);\n\n    const rightEdges = edgeIdsByNodeId.get(clonedEdge.right) ?? [];\n    rightEdges.push(clonedEdge.id);\n    edgeIdsByNodeId.set(clonedEdge.right, rightEdges);\n  }\n\n  for (const note of notes) {\n    const clonedNote = cloneNote(note);\n    notesById.set(clonedNote.id, clonedNote);\n\n    if (clonedNote.target.kind === \"node\") {\n      const nodeNoteIds = noteIdsByNodeId.get(clonedNote.target.nodeId) ?? [];\n      nodeNoteIds.push(clonedNote.id);\n      noteIdsByNodeId.set(clonedNote.target.nodeId, nodeNoteIds);\n      continue;\n    }\n\n    const edgeId = makeCorrespondenceId(\n      clonedNote.target.left,\n      clonedNote.target.right\n    );\n    const correspondenceNoteIds =\n      noteIdsByCorrespondenceId.get(edgeId) ?? [];\n    correspondenceNoteIds.push(clonedNote.id);\n    noteIdsByCorrespondenceId.set(edgeId, correspondenceNoteIds);\n  }\n\n  for (const ids of nodeIdsByType.values()) {\n    ids.sort((left, right) => String(left).localeCompare(String(right)));\n  }\n\n  for (const ids of edgeIdsByNodeId.values()) {\n    ids.sort((left, right) => left.localeCompare(right));\n  }\n\n  for (const ids of noteIdsByNodeId.values()) {\n    ids.sort((left, right) => left.localeCompare(right));\n  }\n\n  for (const ids of noteIdsByCorrespondenceId.values()) {\n    ids.sort((left, right) => left.localeCompare(right));\n  }\n\n  return {\n    descriptor: Object.freeze({ ...descriptor }),\n    nodesById,\n    nodeIdsByType,\n    edgesById,\n    edgeIdsByNodeId,\n    notesById,\n    noteIdsByNodeId,\n    noteIdsByCorrespondenceId,\n  };\n}\n\nfunction normalizeBase(base?: TreeWorkspace | TreeOfLife) {\n  if (!base) {\n    return {\n      descriptor: {},\n      nodes: [] as Node<NodeType>[],\n      edges: [] as CorrespondenceEdge[],\n      notes: [] as TreeNote[],\n    };\n  }\n\n  if (base instanceof TreeWorkspace) {\n    return {\n      descriptor: base.descriptor,\n      nodes: base.getNodes(),\n      edges: base.getEdges(),\n      notes: base.getNotes(),\n    };\n  }\n\n  return {\n    descriptor: {\n      system: base.activeSystem ?? undefined,\n      parts: base.loadedParts.filter((part) => part !== \"base\"),\n    },\n    nodes: base.getNodes(),\n    edges: base.getEdges(),\n    notes: [] as TreeNote[],\n  };\n}\n\nfunction applyOverlays(\n  base: ReturnType<typeof normalizeBase>,\n  overlays: TreeOverlay[]\n) {\n  const nodesById = new Map<NodeId<NodeType>, Node<NodeType>>();\n  const edgesById = new Map<string, CorrespondenceEdge>();\n  const notes: TreeNote[] = [];\n\n  for (const node of base.nodes) {\n    nodesById.set(node.id as NodeId<NodeType>, cloneNode(node));\n  }\n\n  for (const edge of base.edges) {\n    edgesById.set(edge.id, cloneEdge(edge));\n  }\n\n  for (const note of base.notes) {\n    notes.push(cloneNote(note));\n  }\n\n  for (const overlay of overlays) {\n    for (const node of overlay.nodes ?? []) {\n      const existing = nodesById.get(node.id as NodeId<NodeType>);\n\n      if (existing && existing.type !== node.type) {\n        throw new Error(\n          `Overlay ${overlay.id} tried to upsert ${node.id} with a different type`\n        );\n      }\n\n      nodesById.set(\n        node.id as NodeId<NodeType>,\n        cloneNode(\n          existing\n            ? {\n                ...existing,\n                ...node,\n                data: {\n                  ...(existing.data ?? {}),\n                  ...(node.data ?? {}),\n                } as Node<NodeType>[\"data\"],\n              }\n            : node\n        )\n      );\n    }\n\n    for (const correspondence of overlay.correspondences ?? []) {\n      if (\n        !nodesById.has(correspondence.left) ||\n        !nodesById.has(correspondence.right)\n      ) {\n        throw new Error(\n          `Overlay ${overlay.id} references unknown nodes in ${correspondence.left} <-> ${correspondence.right}`\n        );\n      }\n\n      const edgeId = makeCorrespondenceId(\n        correspondence.left,\n        correspondence.right\n      );\n\n      if (correspondence.op === \"remove\") {\n        edgesById.delete(edgeId);\n        continue;\n      }\n\n      const existingEdge = edgesById.get(edgeId);\n      const overlaySource: CorrespondenceSource = {\n        kind: \"overlay\",\n        overlayId: overlay.id,\n        label: overlay.name,\n      };\n\n      if (!existingEdge) {\n        if (correspondence.op !== \"add\") {\n          throw new Error(\n            `Overlay ${overlay.id} cannot annotate missing correspondence ${edgeId}`\n          );\n        }\n\n        edgesById.set(\n          edgeId,\n          cloneEdge({\n            id: edgeId,\n            left: correspondence.left,\n            right: correspondence.right,\n            metadata: cloneMetadata(correspondence.metadata),\n            sources: [overlaySource],\n          })\n        );\n        continue;\n      }\n\n      edgesById.set(\n        edgeId,\n        cloneEdge({\n          ...existingEdge,\n          metadata: mergeMetadata(existingEdge.metadata, correspondence.metadata),\n          sources: mergeSources(existingEdge.sources, overlaySource),\n        })\n      );\n    }\n\n    for (const note of overlay.notes ?? []) {\n      notes.push(\n        cloneNote({\n          ...note,\n          metadata: note.metadata ? { ...note.metadata } : undefined,\n        })\n      );\n    }\n  }\n\n  const filteredNotes = notes.filter((note) => {\n    if (note.target.kind === \"node\") {\n      return nodesById.has(note.target.nodeId);\n    }\n\n    return edgesById.has(\n      makeCorrespondenceId(note.target.left, note.target.right)\n    );\n  });\n\n  return {\n    nodes: [...nodesById.values()],\n    edges: [...edgesById.values()],\n    notes: filteredNotes,\n  };\n}\n\nfunction reconstructPath(\n  startId: NodeId<NodeType>,\n  targetId: NodeId<NodeType>,\n  previous: Map<NodeId<NodeType>, { from: NodeId<NodeType>; edgeId: string }>,\n  edgesById: Map<string, CorrespondenceEdge>\n) {\n  const steps: CorrespondenceStep[] = [];\n  let current = targetId;\n\n  while (current !== startId) {\n    const link = previous.get(current);\n\n    if (!link) {\n      break;\n    }\n\n    const edge = edgesById.get(link.edgeId);\n\n    if (!edge) {\n      break;\n    }\n\n    steps.push({\n      from: link.from,\n      to: current,\n      edge,\n    });\n    current = link.from;\n  }\n\n  return steps.reverse();\n}\n\nfunction buildCanonicalDescriptor(opts: TreeOptions, cacheKey: string) {\n  return {\n    id: `canonical:${cacheKey}`,\n    name: \"Canonical Tree\",\n    system: opts.system,\n    parts: [...(opts.parts ?? [])],\n    cacheKey,\n  } satisfies TreeWorkspaceDescriptor;\n}\n\nconst canonicalTreeCache = new Map<string, TreeWorkspace>();\n\nexport class TreeWorkspace {\n  public readonly descriptor: TreeWorkspaceDescriptor;\n\n  constructor(\n    private readonly graph: TreeGraphData,\n    private readonly visualResolvers: readonly TreeVisualResolver[] = []\n  ) {\n    this.descriptor = graph.descriptor;\n  }\n\n  getNode<T extends NodeType>(id: NodeId<T>) {\n    return this.graph.nodesById.get(id as NodeId<NodeType>) as\n      | Node<T>\n      | undefined;\n  }\n\n  hasNode(id: NodeId<NodeType>) {\n    return this.graph.nodesById.has(id);\n  }\n\n  getNodes<T extends NodeType>(type?: T): Node<T>[] {\n    if (!type) {\n      return sortNodes(\n        [...this.graph.nodesById.values()] as Node<T>[]\n      );\n    }\n\n    const ids = this.graph.nodeIdsByType.get(type) ?? [];\n\n    return ids\n      .map((id) => this.graph.nodesById.get(id) as Node<T> | undefined)\n      .filter((node): node is Node<T> => Boolean(node));\n  }\n\n  findNodes<T extends NodeType = NodeType>(\n    options: TreeFindNodesOptions<T> = {}\n  ): Node<T>[] {\n    const typeFilter = normalizeTypes(options.type);\n    const search = options.search?.trim().toLowerCase();\n\n    const candidates = options.ids\n      ? options.ids\n          .map((id) => this.graph.nodesById.get(id as NodeId<NodeType>))\n          .filter((node): node is Node<NodeType> => Boolean(node))\n      : typeFilter\n        ? [...typeFilter].flatMap((type) => this.getNodes(type))\n        : this.getNodes();\n\n    return sortNodes(\n      candidates.filter((node): node is Node<T> => {\n        if (typeFilter && !typeFilter.has(node.type)) {\n          return false;\n        }\n\n        if (search) {\n          const haystacks = [\n            String(node.id).toLowerCase(),\n            String(node.name ?? \"\").toLowerCase(),\n          ];\n\n          if (!haystacks.some((value) => value.includes(search))) {\n            return false;\n          }\n        }\n\n        return options.predicate ? options.predicate(node as Node<T>) : true;\n      })\n    );\n  }\n\n  getEdge(left: NodeId<NodeType>, right: NodeId<NodeType>) {\n    return this.graph.edgesById.get(makeCorrespondenceId(left, right));\n  }\n\n  getEdges(nodeId?: NodeId<NodeType>) {\n    if (!nodeId) {\n      return [...this.graph.edgesById.values()];\n    }\n\n    return (this.graph.edgeIdsByNodeId.get(nodeId) ?? [])\n      .map((edgeId) => this.graph.edgesById.get(edgeId))\n      .filter((edge): edge is CorrespondenceEdge => Boolean(edge));\n  }\n\n  getNotes(target?: TreeNoteTarget) {\n    if (!target) {\n      return [...this.graph.notesById.values()];\n    }\n\n    if (target.kind === \"node\") {\n      return (this.graph.noteIdsByNodeId.get(target.nodeId) ?? [])\n        .map((noteId) => this.graph.notesById.get(noteId))\n        .filter((note): note is TreeNote => Boolean(note));\n    }\n\n    const edgeId = makeCorrespondenceId(target.left, target.right);\n\n    return (this.graph.noteIdsByCorrespondenceId.get(edgeId) ?? [])\n      .map((noteId) => this.graph.notesById.get(noteId))\n      .filter((note): note is TreeNote => Boolean(note));\n  }\n\n  getCorrespondences<T extends NodeType, U extends NodeType = NodeType>(\n    nodeId: NodeId<T>,\n    options: TreeCorrespondenceQueryOptions<U> = {}\n  ): CorrespondenceMatch<U>[] {\n    if (!this.graph.nodesById.has(nodeId as NodeId<NodeType>)) {\n      return [];\n    }\n\n    const typeFilter = normalizeTypes(options.type);\n    const includeSelf = options.includeSelf ?? false;\n    const depth = Math.max(1, options.depth ?? 1);\n    const limit = options.limit ?? Infinity;\n\n    const previous = new Map<\n      NodeId<NodeType>,\n      { from: NodeId<NodeType>; edgeId: string }\n    >();\n    const visited = new Set<NodeId<NodeType>>([nodeId as NodeId<NodeType>]);\n    const queue: Array<{ nodeId: NodeId<NodeType>; distance: number }> = [\n      {\n        nodeId: nodeId as NodeId<NodeType>,\n        distance: 0,\n      },\n    ];\n    const matches: CorrespondenceMatch<NodeType>[] = [];\n\n    while (queue.length > 0 && matches.length < limit) {\n      const current = queue.shift()!;\n\n      if (current.distance >= depth) {\n        continue;\n      }\n\n      for (const edgeId of this.graph.edgeIdsByNodeId.get(current.nodeId) ?? []) {\n        const edge = this.graph.edgesById.get(edgeId);\n\n        if (!edge) {\n          continue;\n        }\n\n        const nextNodeId =\n          edge.left === current.nodeId ? edge.right : edge.left;\n\n        if (visited.has(nextNodeId)) {\n          continue;\n        }\n\n        visited.add(nextNodeId);\n        previous.set(nextNodeId, {\n          from: current.nodeId,\n          edgeId,\n        });\n\n        const distance = current.distance + 1;\n        const nextNode = this.graph.nodesById.get(nextNodeId);\n\n        if (!nextNode) {\n          continue;\n        }\n\n        if ((!typeFilter || typeFilter.has(nextNode.type)) && distance > 0) {\n          matches.push({\n            node: nextNode,\n            distance,\n            path: reconstructPath(\n              nodeId as NodeId<NodeType>,\n              nextNodeId,\n              previous,\n              this.graph.edgesById\n            ),\n          });\n        }\n\n        queue.push({\n          nodeId: nextNodeId,\n          distance,\n        });\n      }\n    }\n\n    if (includeSelf) {\n      const sourceNode = this.graph.nodesById.get(nodeId as NodeId<NodeType>);\n\n      if (\n        sourceNode &&\n        (!typeFilter || typeFilter.has(sourceNode.type)) &&\n        matches.length < limit\n      ) {\n        matches.unshift({\n          node: sourceNode as Node<U>,\n          distance: 0,\n          path: [],\n        });\n      }\n    }\n\n    return sortMatches(matches as CorrespondenceMatch<U>[]).slice(0, limit);\n  }\n\n  getCorrespondenceMap<T extends NodeType>(\n    nodeId: NodeId<T>,\n    options: Omit<TreeCorrespondenceQueryOptions, \"type\"> = {}\n  ): CorrespondenceMap {\n    const grouped: Record<string, CorrespondenceMatch[]> = {};\n\n    for (const match of this.getCorrespondences(nodeId, options)) {\n      const typeKey = match.node.type;\n      const typeMatches = grouped[typeKey] ?? [];\n      typeMatches.push(match as CorrespondenceMatch);\n      grouped[typeKey] = typeMatches;\n    }\n\n    return grouped as CorrespondenceMap;\n  }\n\n  resolveVisual(request: TreeVisualRequest) {\n    for (const resolver of this.visualResolvers) {\n      const resolved = resolver({\n        request,\n        workspace: this,\n      });\n\n      if (resolved) {\n        return resolved;\n      }\n    }\n\n    return undefined;\n  }\n}\n\nexport function createTreeWorkspace(\n  options: CreateTreeWorkspaceOptions = {}\n) {\n  const base = normalizeBase(options.base);\n  const overlays = options.overlays ?? [];\n  const applied = applyOverlays(base, overlays);\n  const descriptor = {\n    ...base.descriptor,\n    ...options.descriptor,\n  };\n\n  return new TreeWorkspace(\n    createGraphData(descriptor, applied.nodes, applied.edges, applied.notes),\n    options.visualResolvers ?? []\n  );\n}\n\nexport function getCanonicalTree(\n  opts: TreeOptions = {\n    system: \"kaabalah\",\n    parts: [],\n  }\n) {\n  const parts = [...(opts.parts ?? [])];\n  const cacheKey = `${opts.system}:${parts.join(\",\")}`;\n  const cachedTree = canonicalTreeCache.get(cacheKey);\n\n  if (cachedTree) {\n    return cachedTree;\n  }\n\n  const tree = createTree({\n    system: opts.system,\n    parts,\n  });\n\n  const canonicalTree = createTreeWorkspace({\n    base: tree,\n    descriptor: buildCanonicalDescriptor(opts, cacheKey),\n  });\n\n  canonicalTreeCache.set(cacheKey, canonicalTree);\n\n  return canonicalTree;\n}\n"]}