import { createHash } from "crypto"; import { embed } from "./embeddings.js"; import { getClient, COLLECTION } from "./qdrant.js"; // --- Relationship types --- export interface HostRelationship { host: string; role: string; description?: string; } export interface SoftwareRelationship { name: string; role: string; version?: string; description?: string; } export interface GitRepoRelationship { repo: string; path?: string; role: string; description?: string; } export interface LocalDirRelationship { path: string; role: string; description?: string; } export interface ProjectRelationships { hosts: HostRelationship[]; software: SoftwareRelationship[]; git_repos: GitRepoRelationship[]; local_dirs: LocalDirRelationship[]; } // --- Project payload (stored as Qdrant point payload) --- export interface ProjectPayload { slug: string; name: string; status: string; summary: string; tags: string[]; current_state: string; blockers: string[]; decisions_pending: string[]; relationships: ProjectRelationships; key_facts: string[]; history: string[]; updated: string; type: "project"; } // --- Helpers --- export function projectPointId(slug: string): string { const hash = createHash("sha256").update(`project\0${slug}`).digest("hex"); return [ hash.slice(0, 8), hash.slice(8, 12), hash.slice(12, 16), hash.slice(16, 20), hash.slice(20, 32), ].join("-"); } export function buildEmbeddingText(payload: ProjectPayload): string { const parts = [payload.summary, payload.current_state, ...payload.key_facts, ...payload.tags]; return parts.filter(Boolean).join(" "); } export function emptyRelationships(): ProjectRelationships { return { hosts: [], software: [], git_repos: [], local_dirs: [] }; } // --- Data access --- export async function getProjectPoint(slug: string): Promise { const client = getClient(); const id = projectPointId(slug); try { const points = await client.retrieve(COLLECTION, { ids: [id], with_payload: true, with_vector: false }); if (points.length === 0) return null; return points[0].payload as unknown as ProjectPayload; } catch { return null; } } export async function upsertProjectPoint(payload: ProjectPayload): Promise { const client = getClient(); const id = projectPointId(payload.slug); const vector = await embed(buildEmbeddingText(payload)); await client.upsert(COLLECTION, { points: [{ id, vector, payload: payload as unknown as Record }], }); return id; }