@usewhisper/mcp-server 0.1.0 → 0.3.0

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.
Files changed (70) hide show
  1. package/README.md +26 -24
  2. package/dist/autosubscribe-6EDKPBE2.js +4068 -0
  3. package/dist/autosubscribe-GHO6YR5A.js +4068 -0
  4. package/dist/autosubscribe-ISDETQIB.js +436 -0
  5. package/dist/autosubscribe-ISDETQIB.js.map +1 -0
  6. package/dist/chunk-3WGYBAYR.js +8387 -0
  7. package/dist/chunk-52VJYCZ7.js +455 -0
  8. package/dist/chunk-5KBZQHDL.js +189 -0
  9. package/dist/chunk-5KIJNY6Z.js +370 -0
  10. package/dist/chunk-7SN3CKDK.js +1076 -0
  11. package/dist/chunk-B3VWOHUA.js +271 -0
  12. package/dist/chunk-C57DHKTL.js +459 -0
  13. package/dist/chunk-EI5CE3EY.js +616 -0
  14. package/dist/chunk-FTWUJBAH.js +387 -0
  15. package/dist/chunk-FTWUJBAH.js.map +1 -0
  16. package/dist/chunk-H3HSKH2P.js +4841 -0
  17. package/dist/chunk-JO3ORBZD.js +616 -0
  18. package/dist/chunk-L6DXSM2U.js +457 -0
  19. package/dist/chunk-L6DXSM2U.js.map +1 -0
  20. package/dist/chunk-LMEYV4JD.js +368 -0
  21. package/dist/chunk-MEFLJ4PV.js +8385 -0
  22. package/dist/chunk-OBLI4FE4.js +276 -0
  23. package/dist/chunk-OBLI4FE4.js.map +1 -0
  24. package/dist/chunk-PPGYJJED.js +271 -0
  25. package/dist/chunk-QGM4M3NI.js +37 -0
  26. package/dist/chunk-T7KMSTWP.js +399 -0
  27. package/dist/chunk-TWEIYHI6.js +399 -0
  28. package/dist/chunk-UYWE7HSU.js +369 -0
  29. package/dist/chunk-UYWE7HSU.js.map +1 -0
  30. package/dist/chunk-X2DL2GWT.js +33 -0
  31. package/dist/chunk-X2DL2GWT.js.map +1 -0
  32. package/dist/chunk-X7HNNNJJ.js +1079 -0
  33. package/dist/consolidation-2GCKI4RE.js +220 -0
  34. package/dist/consolidation-4JOPW6BG.js +220 -0
  35. package/dist/consolidation-FOVQTWNQ.js +222 -0
  36. package/dist/consolidation-IFQ52E44.js +210 -0
  37. package/dist/consolidation-IFQ52E44.js.map +1 -0
  38. package/dist/context-sharing-4ITCNKG4.js +307 -0
  39. package/dist/context-sharing-6CCFIAKL.js +276 -0
  40. package/dist/context-sharing-6CCFIAKL.js.map +1 -0
  41. package/dist/context-sharing-GYKLXHZA.js +307 -0
  42. package/dist/context-sharing-PH64JTXS.js +308 -0
  43. package/dist/context-sharing-Y6LTZZOF.js +307 -0
  44. package/dist/cost-optimization-6OIKRSBV.js +196 -0
  45. package/dist/cost-optimization-6OIKRSBV.js.map +1 -0
  46. package/dist/cost-optimization-7DVSTL6R.js +307 -0
  47. package/dist/cost-optimization-BH5NAX33.js +287 -0
  48. package/dist/cost-optimization-BH5NAX33.js.map +1 -0
  49. package/dist/cost-optimization-F3L5BS5F.js +303 -0
  50. package/dist/ingest-2LPTWUUM.js +16 -0
  51. package/dist/ingest-7T5FAZNC.js +15 -0
  52. package/dist/ingest-EBNIE7XB.js +15 -0
  53. package/dist/ingest-FSHT5BCS.js +15 -0
  54. package/dist/ingest-QE2BTV72.js +15 -0
  55. package/dist/ingest-QE2BTV72.js.map +1 -0
  56. package/dist/oracle-3RLQF3DP.js +259 -0
  57. package/dist/oracle-FKRTQUUG.js +282 -0
  58. package/dist/oracle-J47QCSEW.js +263 -0
  59. package/dist/oracle-MDP5MZRC.js +257 -0
  60. package/dist/oracle-MDP5MZRC.js.map +1 -0
  61. package/dist/search-BLVHWLWC.js +14 -0
  62. package/dist/search-CZ5NYL5B.js +13 -0
  63. package/dist/search-CZ5NYL5B.js.map +1 -0
  64. package/dist/search-EG6TYWWW.js +13 -0
  65. package/dist/search-I22QQA7T.js +13 -0
  66. package/dist/search-T7H5G6DW.js +13 -0
  67. package/dist/server.d.ts +2 -0
  68. package/dist/server.js +914 -1503
  69. package/dist/server.js.map +1 -1
  70. package/package.json +6 -7
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mcp/server.ts","../../src/db/index.ts","../../src/db/schema.ts","../../src/engine/retriever.ts","../../src/engine/embeddings.ts","../../src/engine/compressor.ts","../../src/engine/ingest.ts","../../src/engine/chunker.ts","../../src/engine/extractor.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { db, projects, sources, memories, conversations, messages } from \"../db/index.js\";\nimport { eq, and, sql, desc } from \"drizzle-orm\";\nimport { retrieve } from \"../engine/retriever.js\";\nimport { ingestDocument } from \"../engine/ingest.js\";\nimport { embedSingle } from \"../engine/embeddings.js\";\n\nconst ORG_ID = process.env.WHISPER_ORG_ID || \"\";\n\nconst server = new McpServer({\n name: \"whisper-context\",\n version: \"0.1.0\",\n});\n\nasync function resolveProject(name: string) {\n const [proj] = await db\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.orgId, ORG_ID),\n sql`(${projects.name} = ${name} OR ${projects.slug} = ${name})`\n )\n )\n .limit(1);\n return proj;\n}\n\n// ─── query_context ──────────────────────────────────────────\n\nserver.tool(\n \"query_context\",\n \"Search your knowledge base for relevant context. Returns packed context ready for LLM consumption. Supports hybrid vector+keyword search, memory inclusion, and knowledge graph traversal.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"What are you looking for?\"),\n top_k: z.number().optional().default(10).describe(\"Number of results\"),\n chunk_types: z.array(z.string()).optional().describe(\"Filter: code, function, class, documentation, api_spec, schema, config, text\"),\n include_memories: z.boolean().optional().default(false).describe(\"Include relevant memories\"),\n include_graph: z.boolean().optional().default(false).describe(\"Include knowledge graph traversal\"),\n user_id: z.string().optional().describe(\"User ID for memory scoping\"),\n session_id: z.string().optional().describe(\"Session ID for memory scoping\"),\n max_tokens: z.number().optional().describe(\"Max tokens for packed context\"),\n },\n async ({ project, query, top_k, chunk_types, include_memories, include_graph, user_id, session_id, max_tokens }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const response = await retrieve({\n projectId: proj.id,\n query,\n topK: top_k,\n chunkTypes: chunk_types,\n includeMemories: include_memories,\n includeGraph: include_graph,\n userId: user_id,\n sessionId: session_id,\n maxTokens: max_tokens,\n });\n\n if (response.results.length === 0) {\n return { content: [{ type: \"text\" as const, text: \"No relevant context found.\" }] };\n }\n\n const header = `Found ${response.meta.totalResults} results (${response.meta.latencyMs}ms${response.meta.cacheHit ? \", cached\" : \"\"}):\\n\\n`;\n return { content: [{ type: \"text\" as const, text: header + response.context }] };\n }\n);\n\n// ─── add_memory ─────────────────────────────────────────────\n\nserver.tool(\n \"add_memory\",\n \"Store a memory (fact, preference, decision) that persists across conversations. Memories can be scoped to a user, session, or agent.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n content: z.string().describe(\"The memory content to store\"),\n memory_type: z.enum([\"factual\", \"episodic\", \"semantic\", \"procedural\"]).optional().default(\"factual\"),\n user_id: z.string().optional().describe(\"User this memory belongs to\"),\n session_id: z.string().optional().describe(\"Session scope\"),\n agent_id: z.string().optional().describe(\"Agent scope\"),\n importance: z.number().optional().default(0.5).describe(\"Importance 0-1\"),\n },\n async ({ project, content, memory_type, user_id, session_id, agent_id, importance }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const embedding = await embedSingle(content);\n const [memory] = await db\n .insert(memories)\n .values({\n projectId: proj.id,\n content,\n memoryType: memory_type,\n userId: user_id,\n sessionId: session_id,\n agentId: agent_id,\n importance,\n embedding,\n })\n .returning();\n\n return { content: [{ type: \"text\" as const, text: `Memory stored (id: ${memory.id}, type: ${memory_type}).` }] };\n }\n);\n\n// ─── search_memories ────────────────────────────────────────\n\nserver.tool(\n \"search_memories\",\n \"Search stored memories by semantic similarity. Recall facts, preferences, past decisions from previous interactions.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"What to search for\"),\n user_id: z.string().optional().describe(\"Filter by user\"),\n session_id: z.string().optional().describe(\"Filter by session\"),\n top_k: z.number().optional().default(10).describe(\"Number of results\"),\n },\n async ({ project, query, user_id, session_id, top_k }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const queryEmbedding = await embedSingle(query);\n const conditions: any[] = [\n eq(memories.projectId, proj.id),\n eq(memories.isActive, true),\n sql`(${memories.expiresAt} IS NULL OR ${memories.expiresAt} > NOW())`,\n ];\n if (user_id) conditions.push(eq(memories.userId, user_id));\n if (session_id) conditions.push(eq(memories.sessionId, session_id));\n\n const results = await db\n .select({\n id: memories.id,\n content: memories.content,\n memoryType: memories.memoryType,\n importance: memories.importance,\n similarity: sql<number>`1 - (${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(memories)\n .where(and(...conditions))\n .orderBy(sql`${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(top_k);\n\n if (results.length === 0) return { content: [{ type: \"text\" as const, text: \"No memories found.\" }] };\n\n const text = results\n .map((r, i) => `${i + 1}. [${r.memoryType}, importance: ${r.importance}, score: ${(r.similarity as number).toFixed(3)}]\\n${r.content}`)\n .join(\"\\n\\n\");\n\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── list_projects ──────────────────────────────────────────\n\nserver.tool(\n \"list_projects\",\n \"List all available context projects.\",\n {},\n async () => {\n const projs = await db.select().from(projects).where(eq(projects.orgId, ORG_ID));\n const text = projs.length === 0\n ? \"No projects found.\"\n : projs.map((p) => `- ${p.name} (${p.slug})${p.description ? `: ${p.description}` : \"\"}`).join(\"\\n\");\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── list_sources ───────────────────────────────────────────\n\nserver.tool(\n \"list_sources\",\n \"List all data sources connected to a project.\",\n { project: z.string().describe(\"Project name or slug\") },\n async ({ project }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const srcs = await db.select().from(sources).where(eq(sources.projectId, proj.id));\n const text = srcs.length === 0\n ? \"No sources connected.\"\n : srcs.map((s) => `- ${s.name} (${s.connectorType}) — ${s.status} | ${s.documentCount} docs, ${s.chunkCount} chunks`).join(\"\\n\");\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── add_context ────────────────────────────────────────────\n\nserver.tool(\n \"add_context\",\n \"Add text content to a project's knowledge base.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n title: z.string().describe(\"Title for this content\"),\n content: z.string().describe(\"The text content to index\"),\n },\n async ({ project, title, content }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n let [directSource] = await db\n .select().from(sources)\n .where(and(eq(sources.projectId, proj.id), eq(sources.connectorType, \"custom\"), eq(sources.name, \"mcp-ingest\")))\n .limit(1);\n\n if (!directSource) {\n [directSource] = await db\n .insert(sources)\n .values({ projectId: proj.id, name: \"mcp-ingest\", connectorType: \"custom\", config: {}, status: \"ready\" })\n .returning();\n }\n\n await ingestDocument({ sourceId: directSource.id, projectId: proj.id, externalId: `mcp-${title}`, title, content });\n return { content: [{ type: \"text\" as const, text: `Indexed \"${title}\" (${content.length} chars) into '${project}'.` }] };\n }\n);\n\n// ─── track_conversation ─────────────────────────────────────\n\nserver.tool(\n \"track_conversation\",\n \"Add a message to a conversation. Creates the conversation if it doesn't exist.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Unique session identifier\"),\n role: z.enum([\"user\", \"assistant\", \"system\", \"tool\"]),\n content: z.string().describe(\"Message content\"),\n user_id: z.string().optional().describe(\"User identifier\"),\n },\n async ({ project, session_id, role, content, user_id }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n let [conv] = await db\n .select().from(conversations)\n .where(and(eq(conversations.projectId, proj.id), eq(conversations.sessionId, session_id)))\n .limit(1);\n\n if (!conv) {\n [conv] = await db\n .insert(conversations)\n .values({ projectId: proj.id, sessionId: session_id, userId: user_id })\n .returning();\n }\n\n await db.insert(messages).values({ conversationId: conv.id, role, content });\n await db.update(conversations)\n .set({ messageCount: sql`${conversations.messageCount} + 1`, updatedAt: new Date() })\n .where(eq(conversations.id, conv.id));\n\n return { content: [{ type: \"text\" as const, text: `Message added (session: ${session_id}).` }] };\n }\n);\n\n// ─── get_conversation ───────────────────────────────────────\n\nserver.tool(\n \"get_conversation\",\n \"Retrieve conversation history for a session.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Session identifier\"),\n limit: z.number().optional().default(50),\n },\n async ({ project, session_id, limit }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const [conv] = await db\n .select().from(conversations)\n .where(and(eq(conversations.projectId, proj.id), eq(conversations.sessionId, session_id)))\n .limit(1);\n\n if (!conv) return { content: [{ type: \"text\" as const, text: \"No conversation found for this session.\" }] };\n\n const msgs = await db.select().from(messages)\n .where(eq(messages.conversationId, conv.id))\n .orderBy(messages.createdAt)\n .limit(limit);\n\n const text = msgs.map((m) => `[${m.role}]: ${m.content}`).join(\"\\n\\n\");\n return { content: [{ type: \"text\" as const, text: text || \"No messages yet.\" }] };\n }\n);\n\n// ─── Start ──────────────────────────────────────────────────\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"Whisper Context MCP server running on stdio\");\n}\n\nmain().catch(console.error);\n","import { drizzle } from \"drizzle-orm/postgres-js\";\nimport postgres from \"postgres\";\nimport * as schema from \"./schema.js\";\n\nconst connectionString = process.env.DATABASE_URL!;\n\nconst client = postgres(connectionString, { max: 10 });\n\nexport const db = drizzle(client, { schema });\n\nexport * from \"./schema.js\";\n","import {\n pgTable,\n uuid,\n text,\n timestamp,\n integer,\n boolean,\n jsonb,\n vector,\n index,\n uniqueIndex,\n pgEnum,\n real,\n serial,\n} from \"drizzle-orm/pg-core\";\n\n// ─── Enums ───────────────────────────────────────────────────\n\nexport const connectorTypeEnum = pgEnum(\"connector_type\", [\n \"github\",\n \"gitlab\",\n \"url\",\n \"sitemap\",\n \"text\",\n \"pdf\",\n \"api_spec\",\n \"database\",\n \"confluence\",\n \"notion\",\n \"slack\",\n \"discord\",\n \"arxiv\",\n \"huggingface\",\n \"npm_package\",\n \"pypi_package\",\n \"custom\",\n]);\n\nexport const sourceStatusEnum = pgEnum(\"source_status\", [\n \"pending\",\n \"indexing\",\n \"ready\",\n \"failed\",\n \"stale\",\n \"syncing\",\n]);\n\nexport const chunkTypeEnum = pgEnum(\"chunk_type\", [\n \"code\",\n \"function\",\n \"class\",\n \"documentation\",\n \"api_spec\",\n \"schema\",\n \"config\",\n \"text\",\n \"comment\",\n \"readme\",\n \"research\",\n \"conversation\",\n \"dataset\",\n]);\n\nexport const memoryTypeEnum = pgEnum(\"memory_type\", [\n \"factual\", // structured facts: \"user prefers TypeScript\"\n \"episodic\", // past interaction summaries\n \"semantic\", // general knowledge\n \"procedural\", // how-to knowledge\n]);\n\nexport const relationTypeEnum = pgEnum(\"relation_type\", [\n \"imports\",\n \"exports\",\n \"calls\",\n \"implements\",\n \"extends\",\n \"references\",\n \"depends_on\",\n \"related_to\",\n \"part_of\",\n \"contradicts\",\n \"supersedes\",\n]);\n\n// ─── Organizations & Auth ────────────────────────────────────\n\nexport const organizations = pgTable(\n \"organizations\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n whisperOrgId: text(\"whisper_org_id\").unique(), // link to main Whisper org\n name: text(\"name\").notNull(),\n plan: text(\"plan\").default(\"free\").notNull(), // free, pro, enterprise\n settings: jsonb(\"settings\").$type<{\n defaultEmbeddingModel?: string;\n defaultChunkSize?: number;\n maxSources?: number;\n maxDocuments?: number;\n maxQueriesPerDay?: number;\n }>().default({}),\n usageLimits: jsonb(\"usage_limits\").$type<{\n queriesPerDay: number;\n documentsTotal: number;\n sourcesTotal: number;\n storageBytes: number;\n }>().default({\n queriesPerDay: 1000,\n documentsTotal: 10000,\n sourcesTotal: 50,\n storageBytes: 1073741824, // 1GB\n }),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"orgs_whisper_org_idx\").on(t.whisperOrgId),\n ]\n);\n\nexport const apiKeys = pgTable(\n \"api_keys\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n name: text(\"name\").notNull(),\n keyHash: text(\"key_hash\").notNull(),\n keyPrefix: text(\"key_prefix\").notNull(), // \"wctx_xxxx\" for identification\n scopes: jsonb(\"scopes\").$type<string[]>().default([\"read\", \"write\"]),\n rateLimit: integer(\"rate_limit\").default(100), // requests per minute\n lastUsedAt: timestamp(\"last_used_at\"),\n expiresAt: timestamp(\"expires_at\"),\n isActive: boolean(\"is_active\").default(true).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"api_keys_hash_idx\").on(t.keyHash),\n index(\"api_keys_org_idx\").on(t.orgId),\n index(\"api_keys_prefix_idx\").on(t.keyPrefix),\n ]\n);\n\n// ─── Projects (Knowledge Bases) ──────────────────────────────\n\nexport const projects = pgTable(\n \"projects\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n name: text(\"name\").notNull(),\n slug: text(\"slug\").notNull(),\n description: text(\"description\"),\n settings: jsonb(\"settings\").$type<{\n embeddingModel?: string;\n embeddingDimensions?: number;\n chunkSize?: number;\n chunkOverlap?: number;\n rerankModel?: string;\n defaultTopK?: number;\n defaultThreshold?: number;\n }>().default({\n embeddingModel: \"text-embedding-3-small\",\n embeddingDimensions: 1536,\n chunkSize: 1000,\n chunkOverlap: 200,\n defaultTopK: 10,\n defaultThreshold: 0.3,\n }),\n isPublic: boolean(\"is_public\").default(false).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"projects_org_slug_idx\").on(t.orgId, t.slug),\n index(\"projects_org_idx\").on(t.orgId),\n index(\"projects_public_idx\").on(t.isPublic),\n ]\n);\n\n// ─── Data Sources ────────────────────────────────────────────\n\nexport const sources = pgTable(\n \"sources\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n connectorType: connectorTypeEnum(\"connector_type\").notNull(),\n name: text(\"name\").notNull(),\n config: jsonb(\"config\").$type<Record<string, any>>().default({}),\n status: sourceStatusEnum(\"status\").default(\"pending\").notNull(),\n syncSchedule: text(\"sync_schedule\"), // cron expression for auto-sync\n lastSyncAt: timestamp(\"last_sync_at\"),\n lastSyncDurationMs: integer(\"last_sync_duration_ms\"),\n syncError: text(\"sync_error\"),\n documentCount: integer(\"document_count\").default(0),\n chunkCount: integer(\"chunk_count\").default(0),\n contentHash: text(\"content_hash\"), // for change detection\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"sources_project_idx\").on(t.projectId),\n index(\"sources_status_idx\").on(t.status),\n index(\"sources_type_idx\").on(t.connectorType),\n ]\n);\n\n// ─── Documents ───────────────────────────────────────────────\n\nexport const documents = pgTable(\n \"documents\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n sourceId: uuid(\"source_id\")\n .notNull()\n .references(() => sources.id, { onDelete: \"cascade\" }),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n externalId: text(\"external_id\"),\n title: text(\"title\"),\n content: text(\"content\"),\n contentHash: text(\"content_hash\"),\n url: text(\"url\"),\n language: text(\"language\"), // programming language or natural language\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n tokenCount: integer(\"token_count\").default(0),\n isActive: boolean(\"is_active\").default(true).notNull(),\n lastIndexedAt: timestamp(\"last_indexed_at\"),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"documents_source_idx\").on(t.sourceId),\n index(\"documents_project_idx\").on(t.projectId),\n uniqueIndex(\"documents_source_external_idx\").on(t.sourceId, t.externalId),\n index(\"documents_hash_idx\").on(t.contentHash),\n index(\"documents_active_idx\").on(t.projectId, t.isActive),\n ]\n);\n\n// ─── Chunks (with vector embeddings) ─────────────────────────\n\nexport const chunks = pgTable(\n \"chunks\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n documentId: uuid(\"document_id\")\n .notNull()\n .references(() => documents.id, { onDelete: \"cascade\" }),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n content: text(\"content\").notNull(),\n chunkType: chunkTypeEnum(\"chunk_type\").default(\"text\").notNull(),\n chunkIndex: integer(\"chunk_index\").default(0),\n // Search\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n // Full-text search column (populated via trigger or app)\n searchContent: text(\"search_content\"), // stripped/normalized for BM25\n // Metadata\n metadata: jsonb(\"metadata\").$type<{\n filePath?: string;\n language?: string;\n startLine?: number;\n endLine?: number;\n functionName?: string;\n className?: string;\n url?: string;\n title?: string;\n section?: string;\n parentChunkId?: string;\n [key: string]: any;\n }>().default({}),\n tokenCount: integer(\"token_count\").default(0),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"chunks_document_idx\").on(t.documentId),\n index(\"chunks_project_idx\").on(t.projectId),\n index(\"chunks_type_idx\").on(t.chunkType),\n index(\"chunks_project_type_idx\").on(t.projectId, t.chunkType),\n ]\n);\n\n// ─── Graph: Entity Relationships ─────────────────────────────\n\nexport const entities = pgTable(\n \"entities\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n name: text(\"name\").notNull(),\n entityType: text(\"entity_type\").notNull(), // function, class, module, concept, api_endpoint, etc.\n description: text(\"description\"),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n sourceChunkId: uuid(\"source_chunk_id\").references(() => chunks.id, { onDelete: \"set null\" }),\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"entities_project_idx\").on(t.projectId),\n index(\"entities_type_idx\").on(t.projectId, t.entityType),\n uniqueIndex(\"entities_project_name_type_idx\").on(t.projectId, t.name, t.entityType),\n ]\n);\n\nexport const relations = pgTable(\n \"relations\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n fromEntityId: uuid(\"from_entity_id\")\n .notNull()\n .references(() => entities.id, { onDelete: \"cascade\" }),\n toEntityId: uuid(\"to_entity_id\")\n .notNull()\n .references(() => entities.id, { onDelete: \"cascade\" }),\n relationType: relationTypeEnum(\"relation_type\").notNull(),\n weight: real(\"weight\").default(1.0),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"relations_project_idx\").on(t.projectId),\n index(\"relations_from_idx\").on(t.fromEntityId),\n index(\"relations_to_idx\").on(t.toEntityId),\n uniqueIndex(\"relations_unique_idx\").on(t.fromEntityId, t.toEntityId, t.relationType),\n ]\n);\n\n// ─── Memories (user/session/agent scoped) ────────────────────\n\nexport const memories = pgTable(\n \"memories\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n // Scoping\n userId: text(\"user_id\"), // user-scoped memory\n sessionId: text(\"session_id\"), // session-scoped memory\n agentId: text(\"agent_id\"), // agent-scoped memory\n // Memory content\n memoryType: memoryTypeEnum(\"memory_type\").default(\"factual\").notNull(),\n content: text(\"content\").notNull(),\n summary: text(\"summary\"), // LLM-generated summary\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n // Management\n importance: real(\"importance\").default(0.5), // 0-1 how important is this\n accessCount: integer(\"access_count\").default(0),\n lastAccessedAt: timestamp(\"last_accessed_at\"),\n expiresAt: timestamp(\"expires_at\"), // optional TTL\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n isActive: boolean(\"is_active\").default(true).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"memories_project_idx\").on(t.projectId),\n index(\"memories_user_idx\").on(t.projectId, t.userId),\n index(\"memories_session_idx\").on(t.projectId, t.sessionId),\n index(\"memories_agent_idx\").on(t.projectId, t.agentId),\n index(\"memories_type_idx\").on(t.projectId, t.memoryType),\n index(\"memories_active_idx\").on(t.projectId, t.isActive),\n index(\"memories_expires_idx\").on(t.expiresAt),\n ]\n);\n\n// ─── Conversations (context sharing) ─────────────────────────\n\nexport const conversations = pgTable(\n \"conversations\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n sessionId: text(\"session_id\"),\n userId: text(\"user_id\"),\n agentId: text(\"agent_id\"),\n title: text(\"title\"),\n summary: text(\"summary\"),\n embedding: vector(\"embedding\", { dimensions: 1536 }),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n messageCount: integer(\"message_count\").default(0),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"conversations_project_idx\").on(t.projectId),\n index(\"conversations_session_idx\").on(t.sessionId),\n index(\"conversations_user_idx\").on(t.userId),\n ]\n);\n\nexport const messages = pgTable(\n \"messages\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n conversationId: uuid(\"conversation_id\")\n .notNull()\n .references(() => conversations.id, { onDelete: \"cascade\" }),\n role: text(\"role\").notNull(), // user, assistant, system, tool\n content: text(\"content\").notNull(),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"messages_conversation_idx\").on(t.conversationId),\n index(\"messages_created_idx\").on(t.conversationId, t.createdAt),\n ]\n);\n\n// ─── Webhooks ────────────────────────────────────────────────\n\nexport const webhooks = pgTable(\n \"webhooks\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n url: text(\"url\").notNull(),\n secret: text(\"secret\").notNull(),\n events: jsonb(\"events\").$type<string[]>().default([\n \"source.synced\",\n \"document.indexed\",\n \"memory.created\",\n ]),\n isActive: boolean(\"is_active\").default(true).notNull(),\n lastDeliveredAt: timestamp(\"last_delivered_at\"),\n failureCount: integer(\"failure_count\").default(0),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"webhooks_org_idx\").on(t.orgId),\n ]\n);\n\n// ─── Usage Tracking ──────────────────────────────────────────\n\nexport const usageEvents = pgTable(\n \"usage_events\",\n {\n id: serial(\"id\").primaryKey(),\n orgId: uuid(\"org_id\")\n .notNull()\n .references(() => organizations.id, { onDelete: \"cascade\" }),\n projectId: uuid(\"project_id\"),\n eventType: text(\"event_type\").notNull(), // query, ingest, sync, memory_add, memory_search\n source: text(\"source\").default(\"api\"), // api, mcp, sdk, webhook\n tokensUsed: integer(\"tokens_used\").default(0),\n embeddingTokens: integer(\"embedding_tokens\").default(0),\n latencyMs: integer(\"latency_ms\"),\n metadata: jsonb(\"metadata\").$type<Record<string, any>>().default({}),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n index(\"usage_org_idx\").on(t.orgId),\n index(\"usage_project_idx\").on(t.projectId),\n index(\"usage_type_idx\").on(t.eventType),\n index(\"usage_created_idx\").on(t.createdAt),\n index(\"usage_org_created_idx\").on(t.orgId, t.createdAt),\n ]\n);\n\n// ─── Query Cache ─────────────────────────────────────────────\n\nexport const queryCache = pgTable(\n \"query_cache\",\n {\n id: uuid(\"id\").primaryKey().defaultRandom(),\n projectId: uuid(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n queryHash: text(\"query_hash\").notNull(),\n query: text(\"query\").notNull(),\n results: jsonb(\"results\").$type<any[]>().default([]),\n hitCount: integer(\"hit_count\").default(0),\n expiresAt: timestamp(\"expires_at\").notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (t) => [\n uniqueIndex(\"cache_project_query_idx\").on(t.projectId, t.queryHash),\n index(\"cache_expires_idx\").on(t.expiresAt),\n ]\n);\n","import { db, chunks, documents, sources, memories, entities, relations, queryCache } from \"../db/index.js\";\nimport { eq, sql, and, inArray, or, desc, asc, isNull, gt } from \"drizzle-orm\";\nimport { embedSingle } from \"./embeddings.js\";\nimport { compressContext, type CompressionOptions } from \"./compressor.js\";\nimport { createHash } from \"crypto\";\nimport OpenAI from \"openai\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport interface RetrievalResult {\n id: string;\n content: string;\n score: number;\n metadata: Record<string, any>;\n documentTitle?: string;\n sourceName?: string;\n chunkType: string;\n source: \"vector\" | \"bm25\" | \"hybrid\" | \"memory\" | \"graph\";\n}\n\nexport interface QueryOptions {\n projectId: string;\n query: string;\n topK?: number;\n threshold?: number;\n chunkTypes?: string[];\n sourceIds?: string[];\n // Hybrid search\n hybridSearch?: boolean;\n vectorWeight?: number; // 0-1, default 0.7\n bm25Weight?: number; // 0-1, default 0.3\n // Reranking\n rerank?: boolean;\n rerankTopK?: number;\n // Memory inclusion\n includeMemories?: boolean;\n userId?: string;\n sessionId?: string;\n agentId?: string;\n // Graph\n includeGraph?: boolean;\n graphDepth?: number;\n // Context packing\n maxTokens?: number;\n // Compression\n compress?: boolean;\n compressionStrategy?: \"summarize\" | \"extract\" | \"delta\" | \"adaptive\";\n previousContextHash?: string;\n // Caching\n useCache?: boolean;\n cacheTtlSeconds?: number;\n}\n\nexport interface ContextResponse {\n results: RetrievalResult[];\n context: string; // packed context string ready for LLM\n meta: {\n totalResults: number;\n latencyMs: number;\n cacheHit: boolean;\n tokensUsed: number;\n contextHash?: string;\n compression?: {\n originalTokens: number;\n compressedTokens: number;\n reductionPercent: number;\n strategy: string;\n };\n };\n}\n\n// ─── Main Query Function ─────────────────────────────────────\n\nexport async function retrieve(opts: QueryOptions): Promise<ContextResponse> {\n const {\n projectId,\n query,\n topK = 10,\n threshold = 0.3,\n chunkTypes,\n hybridSearch = true,\n vectorWeight = 0.7,\n bm25Weight = 0.3,\n rerank = true,\n rerankTopK,\n includeMemories = false,\n userId,\n sessionId,\n agentId,\n includeGraph = false,\n graphDepth = 1,\n maxTokens,\n compress = false,\n compressionStrategy = \"adaptive\",\n previousContextHash,\n useCache = true,\n cacheTtlSeconds = 300,\n } = opts;\n\n const startTime = Date.now();\n\n // ─── Check Cache ─────────────────────────────────────────\n if (useCache) {\n const cached = await checkCache(projectId, query);\n if (cached) {\n return {\n results: cached as RetrievalResult[],\n context: packContext(cached as RetrievalResult[], maxTokens),\n meta: {\n totalResults: cached.length,\n latencyMs: Date.now() - startTime,\n cacheHit: true,\n tokensUsed: 0,\n },\n };\n }\n }\n\n // ─── Embed Query ─────────────────────────────────────────\n const queryEmbedding = await embedSingle(query);\n\n let allResults: RetrievalResult[] = [];\n\n // ─── Vector Search ───────────────────────────────────────\n const vectorResults = await vectorSearch(projectId, queryEmbedding, topK * 2, chunkTypes);\n allResults.push(...vectorResults);\n\n // ─── BM25 Full-Text Search ───────────────────────────────\n if (hybridSearch) {\n const bm25Results = await fullTextSearch(projectId, query, topK * 2, chunkTypes);\n allResults.push(...bm25Results);\n }\n\n // ─── Memory Search ───────────────────────────────────────\n if (includeMemories) {\n const memoryResults = await memorySearch(projectId, queryEmbedding, {\n userId,\n sessionId,\n agentId,\n topK: Math.ceil(topK / 3),\n });\n allResults.push(...memoryResults);\n }\n\n // ─── Graph Traversal ─────────────────────────────────────\n if (includeGraph) {\n const graphResults = await graphSearch(projectId, queryEmbedding, {\n depth: graphDepth,\n topK: Math.ceil(topK / 3),\n });\n allResults.push(...graphResults);\n }\n\n // ─── Deduplicate ─────────────────────────────────────────\n allResults = deduplicateResults(allResults);\n\n // ─── Reciprocal Rank Fusion (for hybrid) ─────────────────\n if (hybridSearch) {\n allResults = reciprocalRankFusion(allResults, vectorWeight, bm25Weight);\n }\n\n // ─── Filter by threshold ─────────────────────────────────\n allResults = allResults.filter((r) => r.score >= threshold);\n\n // ─── Rerank with LLM ────────────────────────────────────\n if (rerank && allResults.length > 0) {\n const reranked = await rerankResults(query, allResults, rerankTopK || topK);\n allResults = reranked;\n }\n\n // ─── Limit to topK ──────────────────────────────────────\n allResults = allResults.slice(0, topK);\n\n // ─── Enrich with document/source metadata ────────────────\n allResults = await enrichResults(allResults);\n\n // ─── Context packing ─────────────────────────────────────\n let context = packContext(allResults, maxTokens);\n const contextHash = createHash(\"sha256\").update(context).digest(\"hex\").slice(0, 16);\n\n // ─── Compression ──────────────────────────────────────────\n let compressionMeta: ContextResponse[\"meta\"][\"compression\"];\n if (compress && context.length > 0) {\n const compressed = await compressContext(context, {\n maxTokens: maxTokens || 4000,\n strategy: compressionStrategy,\n previousContextHash,\n });\n context = compressed.context;\n compressionMeta = {\n originalTokens: compressed.originalTokens,\n compressedTokens: compressed.compressedTokens,\n reductionPercent: compressed.reductionPercent,\n strategy: compressed.strategy,\n };\n }\n\n // ─── Cache results ───────────────────────────────────────\n if (useCache && allResults.length > 0) {\n await setCache(projectId, query, allResults, cacheTtlSeconds);\n }\n\n const latencyMs = Date.now() - startTime;\n\n return {\n results: allResults,\n context,\n meta: {\n totalResults: allResults.length,\n latencyMs,\n cacheHit: false,\n tokensUsed: estimateTokens(context),\n contextHash,\n compression: compressionMeta,\n },\n };\n}\n\n// ─── Vector Search ───────────────────────────────────────────\n\nasync function vectorSearch(\n projectId: string,\n queryEmbedding: number[],\n limit: number,\n chunkTypes?: string[]\n): Promise<RetrievalResult[]> {\n const conditions = [eq(chunks.projectId, projectId)];\n if (chunkTypes && chunkTypes.length > 0) {\n conditions.push(inArray(chunks.chunkType, chunkTypes as any));\n }\n\n const results = await db\n .select({\n id: chunks.id,\n content: chunks.content,\n chunkType: chunks.chunkType,\n metadata: chunks.metadata,\n documentId: chunks.documentId,\n similarity: sql<number>`1 - (${chunks.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(chunks)\n .where(and(...conditions))\n .orderBy(sql`${chunks.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(limit);\n\n return results.map((r) => ({\n id: r.id,\n content: r.content,\n score: r.similarity,\n metadata: (r.metadata as Record<string, any>) || {},\n chunkType: r.chunkType,\n source: \"vector\" as const,\n }));\n}\n\n// ─── Full-Text Search (BM25-style via pg tsvector) ───────────\n\nasync function fullTextSearch(\n projectId: string,\n query: string,\n limit: number,\n chunkTypes?: string[]\n): Promise<RetrievalResult[]> {\n // Sanitize query for tsquery\n const tsQuery = query\n .replace(/[^\\w\\s]/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter((w) => w.length > 1)\n .join(\" & \");\n\n if (!tsQuery) return [];\n\n const conditions = [eq(chunks.projectId, projectId)];\n if (chunkTypes && chunkTypes.length > 0) {\n conditions.push(inArray(chunks.chunkType, chunkTypes as any));\n }\n\n const results = await db\n .select({\n id: chunks.id,\n content: chunks.content,\n chunkType: chunks.chunkType,\n metadata: chunks.metadata,\n documentId: chunks.documentId,\n rank: sql<number>`ts_rank(to_tsvector('english', coalesce(${chunks.searchContent}, ${chunks.content})), to_tsquery('english', ${tsQuery}))`,\n })\n .from(chunks)\n .where(\n and(\n ...conditions,\n sql`to_tsvector('english', coalesce(${chunks.searchContent}, ${chunks.content})) @@ to_tsquery('english', ${tsQuery})`\n )\n )\n .orderBy(sql`ts_rank(to_tsvector('english', coalesce(${chunks.searchContent}, ${chunks.content})), to_tsquery('english', ${tsQuery})) DESC`)\n .limit(limit);\n\n // Normalize ranks to 0-1\n const maxRank = results.length > 0 ? Math.max(...results.map((r) => r.rank)) : 1;\n\n return results.map((r) => ({\n id: r.id,\n content: r.content,\n score: maxRank > 0 ? r.rank / maxRank : 0,\n metadata: (r.metadata as Record<string, any>) || {},\n chunkType: r.chunkType,\n source: \"bm25\" as const,\n }));\n}\n\n// ─── Memory Search ───────────────────────────────────────────\n\nasync function memorySearch(\n projectId: string,\n queryEmbedding: number[],\n opts: { userId?: string; sessionId?: string; agentId?: string; topK: number }\n): Promise<RetrievalResult[]> {\n const conditions = [\n eq(memories.projectId, projectId),\n eq(memories.isActive, true),\n or(isNull(memories.expiresAt), gt(memories.expiresAt, new Date())),\n ];\n\n if (opts.userId) conditions.push(eq(memories.userId, opts.userId));\n if (opts.sessionId) conditions.push(eq(memories.sessionId, opts.sessionId));\n if (opts.agentId) conditions.push(eq(memories.agentId, opts.agentId));\n\n const results = await db\n .select({\n id: memories.id,\n content: memories.content,\n memoryType: memories.memoryType,\n metadata: memories.metadata,\n importance: memories.importance,\n similarity: sql<number>`1 - (${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(memories)\n .where(and(...conditions))\n .orderBy(sql`${memories.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(opts.topK);\n\n // Update access counts\n if (results.length > 0) {\n const ids = results.map((r) => r.id);\n await db\n .update(memories)\n .set({\n accessCount: sql`${memories.accessCount} + 1`,\n lastAccessedAt: new Date(),\n })\n .where(inArray(memories.id, ids));\n }\n\n return results.map((r) => ({\n id: r.id,\n content: r.content,\n score: r.similarity * (r.importance || 0.5),\n metadata: { ...(r.metadata as Record<string, any>), memoryType: r.memoryType },\n chunkType: \"memory\" as any,\n source: \"memory\" as const,\n }));\n}\n\n// ─── Graph Search ────────────────────────────────────────────\n\nasync function graphSearch(\n projectId: string,\n queryEmbedding: number[],\n opts: { depth: number; topK: number }\n): Promise<RetrievalResult[]> {\n // Find most relevant entities\n const relevantEntities = await db\n .select({\n id: entities.id,\n name: entities.name,\n entityType: entities.entityType,\n description: entities.description,\n metadata: entities.metadata,\n sourceChunkId: entities.sourceChunkId,\n similarity: sql<number>`1 - (${entities.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector)`,\n })\n .from(entities)\n .where(eq(entities.projectId, projectId))\n .orderBy(sql`${entities.embedding} <=> ${JSON.stringify(queryEmbedding)}::vector`)\n .limit(5);\n\n if (relevantEntities.length === 0) return [];\n\n // Traverse relationships\n const entityIds = relevantEntities.map((e) => e.id);\n\n const relatedEntities = await db\n .select({\n id: entities.id,\n name: entities.name,\n entityType: entities.entityType,\n description: entities.description,\n metadata: entities.metadata,\n sourceChunkId: entities.sourceChunkId,\n relationType: relations.relationType,\n weight: relations.weight,\n })\n .from(relations)\n .innerJoin(entities, eq(relations.toEntityId, entities.id))\n .where(\n and(\n eq(relations.projectId, projectId),\n inArray(relations.fromEntityId, entityIds)\n )\n )\n .limit(opts.topK);\n\n // Get chunks for related entities\n const chunkIds = [\n ...relevantEntities.map((e) => e.sourceChunkId).filter(Boolean),\n ...relatedEntities.map((e) => e.sourceChunkId).filter(Boolean),\n ] as string[];\n\n if (chunkIds.length === 0) return [];\n\n const relatedChunks = await db\n .select()\n .from(chunks)\n .where(inArray(chunks.id, chunkIds));\n\n return relatedChunks.map((c) => {\n const entity = relevantEntities.find((e) => e.sourceChunkId === c.id);\n return {\n id: c.id,\n content: c.content,\n score: entity ? entity.similarity * 0.8 : 0.5,\n metadata: {\n ...(c.metadata as Record<string, any>),\n entityName: entity?.name,\n entityType: entity?.entityType,\n },\n chunkType: c.chunkType,\n source: \"graph\" as const,\n };\n });\n}\n\n// ─── Reciprocal Rank Fusion ──────────────────────────────────\n\nfunction reciprocalRankFusion(\n results: RetrievalResult[],\n vectorWeight: number,\n bm25Weight: number,\n k = 60\n): RetrievalResult[] {\n const scoreMap = new Map<string, { result: RetrievalResult; score: number }>();\n\n // Group by source type and rank\n const vectorResults = results.filter((r) => r.source === \"vector\");\n const bm25Results = results.filter((r) => r.source === \"bm25\");\n const otherResults = results.filter((r) => r.source !== \"vector\" && r.source !== \"bm25\");\n\n // RRF scoring for vector results\n vectorResults.forEach((r, rank) => {\n const existing = scoreMap.get(r.id);\n const rrfScore = vectorWeight / (k + rank + 1);\n if (existing) {\n existing.score += rrfScore;\n } else {\n scoreMap.set(r.id, { result: r, score: rrfScore });\n }\n });\n\n // RRF scoring for BM25 results\n bm25Results.forEach((r, rank) => {\n const existing = scoreMap.get(r.id);\n const rrfScore = bm25Weight / (k + rank + 1);\n if (existing) {\n existing.score += rrfScore;\n existing.result.source = \"hybrid\";\n } else {\n scoreMap.set(r.id, { result: { ...r, source: \"hybrid\" }, score: rrfScore });\n }\n });\n\n // Add other results with their original scores\n otherResults.forEach((r) => {\n if (!scoreMap.has(r.id)) {\n scoreMap.set(r.id, { result: r, score: r.score * 0.5 });\n }\n });\n\n return Array.from(scoreMap.values())\n .sort((a, b) => b.score - a.score)\n .map((entry) => ({ ...entry.result, score: entry.score }));\n}\n\n// ─── LLM Reranking ───────────────────────────────────────────\n\nasync function rerankResults(\n query: string,\n results: RetrievalResult[],\n topK: number\n): Promise<RetrievalResult[]> {\n if (results.length <= 3) return results; // not worth reranking\n\n // Take top candidates for reranking (limit to save tokens)\n const candidates = results.slice(0, Math.min(results.length, topK * 3));\n\n const prompt = `Given the query: \"${query}\"\n\nRank these ${candidates.length} text passages by relevance (most relevant first). Return ONLY a JSON array of indices (0-based), e.g. [2, 0, 4, 1, 3].\n\n${candidates.map((r, i) => `[${i}] ${r.content.slice(0, 300)}`).join(\"\\n\\n\")}`;\n\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [{ role: \"user\", content: prompt }],\n temperature: 0,\n max_tokens: 200,\n });\n\n const text = res.choices[0]?.message?.content?.trim() || \"\";\n const match = text.match(/\\[[\\d,\\s]+\\]/);\n if (!match) return results;\n\n const indices: number[] = JSON.parse(match[0]);\n const reranked: RetrievalResult[] = [];\n\n for (const idx of indices) {\n if (idx >= 0 && idx < candidates.length) {\n reranked.push({\n ...candidates[idx],\n score: 1 - reranked.length * (1 / indices.length), // normalize\n });\n }\n }\n\n // Add any results that weren't reranked\n for (const r of results) {\n if (!reranked.find((rr) => rr.id === r.id)) {\n reranked.push(r);\n }\n }\n\n return reranked.slice(0, topK);\n } catch {\n // Fallback to original ordering if reranking fails\n return results.slice(0, topK);\n }\n}\n\n// ─── Deduplication ───────────────────────────────────────────\n\nfunction deduplicateResults(results: RetrievalResult[]): RetrievalResult[] {\n const seen = new Map<string, RetrievalResult>();\n\n for (const r of results) {\n const existing = seen.get(r.id);\n if (!existing || r.score > existing.score) {\n seen.set(r.id, r);\n }\n }\n\n return Array.from(seen.values());\n}\n\n// ─── Context Packing ─────────────────────────────────────────\n\nfunction packContext(results: RetrievalResult[], maxTokens?: number): string {\n if (results.length === 0) return \"\";\n\n const limit = maxTokens || 8000;\n let totalTokens = 0;\n const packed: string[] = [];\n\n for (const r of results) {\n const header = buildChunkHeader(r);\n const block = `${header}\\n${r.content}\\n`;\n const tokens = estimateTokens(block);\n\n if (totalTokens + tokens > limit) break;\n\n packed.push(block);\n totalTokens += tokens;\n }\n\n return packed.join(\"\\n---\\n\\n\");\n}\n\nfunction buildChunkHeader(r: RetrievalResult): string {\n const parts: string[] = [];\n\n if (r.sourceName) parts.push(`Source: ${r.sourceName}`);\n if (r.documentTitle) parts.push(`Document: ${r.documentTitle}`);\n if (r.metadata?.filePath) parts.push(`File: ${r.metadata.filePath}`);\n if (r.metadata?.startLine) parts.push(`Lines: ${r.metadata.startLine}-${r.metadata.endLine || \"?\"}`);\n if (r.chunkType && r.chunkType !== \"text\") parts.push(`Type: ${r.chunkType}`);\n\n return parts.length > 0 ? `[${parts.join(\" | \")}]` : \"\";\n}\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n// ─── Enrich Results ──────────────────────────────────────────\n\nasync function enrichResults(results: RetrievalResult[]): Promise<RetrievalResult[]> {\n // Get unique document IDs from chunk results\n const chunkResults = results.filter((r) => r.source !== \"memory\");\n if (chunkResults.length === 0) return results;\n\n // We need document IDs — stored in metadata or we need to query\n const chunkIds = chunkResults.map((r) => r.id);\n\n const chunkDocs = await db\n .select({\n chunkId: chunks.id,\n docTitle: documents.title,\n sourceName: sources.name,\n docId: documents.id,\n sourceId: sources.id,\n })\n .from(chunks)\n .innerJoin(documents, eq(chunks.documentId, documents.id))\n .innerJoin(sources, eq(documents.sourceId, sources.id))\n .where(inArray(chunks.id, chunkIds));\n\n const enrichMap = new Map(chunkDocs.map((d) => [d.chunkId, d]));\n\n return results.map((r) => {\n const enrichment = enrichMap.get(r.id);\n if (enrichment) {\n return {\n ...r,\n documentTitle: enrichment.docTitle || undefined,\n sourceName: enrichment.sourceName || undefined,\n };\n }\n return r;\n });\n}\n\n// ─── Cache ───────────────────────────────────────────────────\n\nfunction hashQuery(query: string): string {\n return createHash(\"sha256\").update(query.toLowerCase().trim()).digest(\"hex\");\n}\n\nasync function checkCache(projectId: string, query: string) {\n const hash = hashQuery(query);\n\n const [cached] = await db\n .select()\n .from(queryCache)\n .where(\n and(\n eq(queryCache.projectId, projectId),\n eq(queryCache.queryHash, hash),\n gt(queryCache.expiresAt, new Date())\n )\n )\n .limit(1);\n\n if (cached) {\n await db\n .update(queryCache)\n .set({ hitCount: sql`${queryCache.hitCount} + 1` })\n .where(eq(queryCache.id, cached.id));\n\n return cached.results;\n }\n\n return null;\n}\n\nasync function setCache(\n projectId: string,\n query: string,\n results: RetrievalResult[],\n ttlSeconds: number\n) {\n const hash = hashQuery(query);\n const expiresAt = new Date(Date.now() + ttlSeconds * 1000);\n\n await db\n .insert(queryCache)\n .values({\n projectId,\n queryHash: hash,\n query,\n results: results as any,\n expiresAt,\n })\n .onConflictDoUpdate({\n target: [queryCache.projectId, queryCache.queryHash],\n set: { results: results as any, expiresAt, hitCount: 0 },\n });\n}\n","import OpenAI from \"openai\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\nexport async function embed(texts: string[]): Promise<number[][]> {\n const res = await openai.embeddings.create({\n model: \"text-embedding-3-small\",\n input: texts,\n dimensions: 1536,\n });\n\n return res.data.map((d) => d.embedding);\n}\n\nexport async function embedSingle(text: string): Promise<number[]> {\n const [embedding] = await embed([text]);\n return embedding;\n}\n","import OpenAI from \"openai\";\nimport { db, chunks, memories } from \"../db/index.js\";\nimport { eq, sql } from \"drizzle-orm\";\nimport { createHash } from \"crypto\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport interface CompressedContext {\n context: string;\n originalTokens: number;\n compressedTokens: number;\n reductionPercent: number;\n strategy: string;\n}\n\nexport interface CompressionOptions {\n maxTokens?: number;\n strategy?: \"summarize\" | \"extract\" | \"delta\" | \"adaptive\";\n previousContextHash?: string; // for delta mode\n previousContext?: string; // for delta mode\n targetReduction?: number; // 0-1, e.g. 0.6 = reduce by 60%\n}\n\n// ─── In-memory delta cache ──────────────────────────────────\n\nconst deltaCache = new Map<string, { context: string; hash: string; timestamp: number }>();\nconst DELTA_CACHE_TTL = 600_000; // 10 min\n\nfunction hashContext(text: string): string {\n return createHash(\"sha256\").update(text).digest(\"hex\").slice(0, 16);\n}\n\n// ─── Main Compression Function ──────────────────────────────\n\nexport async function compressContext(\n rawContext: string,\n opts: CompressionOptions = {}\n): Promise<CompressedContext> {\n const {\n maxTokens = 4000,\n strategy = \"adaptive\",\n previousContextHash,\n previousContext,\n targetReduction = 0.5,\n } = opts;\n\n const originalTokens = estimateTokens(rawContext);\n\n // If already under budget, return as-is\n if (originalTokens <= maxTokens) {\n return {\n context: rawContext,\n originalTokens,\n compressedTokens: originalTokens,\n reductionPercent: 0,\n strategy: \"none\",\n };\n }\n\n switch (strategy) {\n case \"delta\":\n return deltaCompress(rawContext, originalTokens, maxTokens, previousContextHash, previousContext);\n case \"summarize\":\n return summarizeCompress(rawContext, originalTokens, maxTokens);\n case \"extract\":\n return extractCompress(rawContext, originalTokens, maxTokens);\n case \"adaptive\":\n default:\n return adaptiveCompress(rawContext, originalTokens, maxTokens, previousContextHash, previousContext);\n }\n}\n\n// ─── Adaptive Strategy ──────────────────────────────────────\n// Picks the best strategy based on context characteristics\n\nasync function adaptiveCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number,\n previousHash?: string,\n previousCtx?: string\n): Promise<CompressedContext> {\n const ratio = originalTokens / maxTokens;\n\n // If we have previous context and it's similar, use delta\n if (previousHash || previousCtx) {\n const delta = await deltaCompress(rawContext, originalTokens, maxTokens, previousHash, previousCtx);\n if (delta.compressedTokens <= maxTokens) return delta;\n }\n\n // Light compression (under 2x budget): extract key info\n if (ratio < 2) {\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Heavy compression (over 2x budget): summarize\n return summarizeCompress(rawContext, originalTokens, maxTokens);\n}\n\n// ─── Delta Compression ──────────────────────────────────────\n// Only sends what changed since the last context\n\nasync function deltaCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number,\n previousHash?: string,\n previousCtx?: string\n): Promise<CompressedContext> {\n const currentHash = hashContext(rawContext);\n\n // Check if identical\n if (previousHash && previousHash === currentHash) {\n return {\n context: \"[No changes since last context]\",\n originalTokens,\n compressedTokens: 8,\n reductionPercent: 99,\n strategy: \"delta-identical\",\n };\n }\n\n // Get previous context from cache or parameter\n let prevCtx = previousCtx;\n if (!prevCtx && previousHash) {\n const cached = deltaCache.get(previousHash);\n if (cached && Date.now() - cached.timestamp < DELTA_CACHE_TTL) {\n prevCtx = cached.context;\n }\n }\n\n if (!prevCtx) {\n // No previous context to diff against, fall back to extract\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Split into blocks and find differences\n const prevBlocks = new Set(prevCtx.split(\"\\n---\\n\").map((b) => b.trim()));\n const currentBlocks = rawContext.split(\"\\n---\\n\").map((b) => b.trim());\n\n const newBlocks: string[] = [];\n const unchangedCount = { count: 0 };\n\n for (const block of currentBlocks) {\n if (prevBlocks.has(block)) {\n unchangedCount.count++;\n } else {\n newBlocks.push(block);\n }\n }\n\n let deltaContext: string;\n if (newBlocks.length === 0) {\n deltaContext = \"[No new information since last query]\";\n } else {\n const header = `[${unchangedCount.count} unchanged results omitted, ${newBlocks.length} new/updated]\\n\\n`;\n deltaContext = header + newBlocks.join(\"\\n---\\n\");\n }\n\n // Trim if still over budget\n const deltaTokens = estimateTokens(deltaContext);\n if (deltaTokens > maxTokens) {\n const truncated = truncateToTokens(deltaContext, maxTokens);\n deltaCache.set(currentHash, { context: rawContext, hash: currentHash, timestamp: Date.now() });\n\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"delta-truncated\",\n };\n }\n\n // Cache current context for next delta\n deltaCache.set(currentHash, { context: rawContext, hash: currentHash, timestamp: Date.now() });\n\n return {\n context: deltaContext,\n originalTokens,\n compressedTokens: estimateTokens(deltaContext),\n reductionPercent: Math.round((1 - estimateTokens(deltaContext) / originalTokens) * 100),\n strategy: \"delta\",\n };\n}\n\n// ─── Extract Compression ────────────────────────────────────\n// LLM extracts only the most relevant parts\n\nasync function extractCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number\n): Promise<CompressedContext> {\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n {\n role: \"system\",\n content: `You are a context compressor. Extract and preserve ONLY the most important information from the provided context. Remove redundancy, boilerplate, and low-value content. Keep code snippets, key facts, API signatures, and important relationships. Output should be ${maxTokens} tokens or less. Do NOT add commentary — just output the compressed context.`,\n },\n { role: \"user\", content: rawContext },\n ],\n max_tokens: maxTokens,\n temperature: 0,\n });\n\n const compressed = res.choices[0]?.message?.content?.trim() || rawContext;\n const compressedTokens = estimateTokens(compressed);\n\n return {\n context: compressed,\n originalTokens,\n compressedTokens,\n reductionPercent: Math.round((1 - compressedTokens / originalTokens) * 100),\n strategy: \"extract\",\n };\n } catch {\n // Fallback to truncation\n const truncated = truncateToTokens(rawContext, maxTokens);\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"truncate-fallback\",\n };\n }\n}\n\n// ─── Summarize Compression ──────────────────────────────────\n// For heavy compression — summarizes each block then combines\n\nasync function summarizeCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number\n): Promise<CompressedContext> {\n const blocks = rawContext.split(\"\\n---\\n\").filter((b) => b.trim());\n\n // If few blocks, summarize the whole thing\n if (blocks.length <= 3) {\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Summarize each block individually, then combine\n const budgetPerBlock = Math.floor(maxTokens / blocks.length);\n\n try {\n const summaries = await Promise.all(\n blocks.map(async (block) => {\n if (estimateTokens(block) <= budgetPerBlock) return block;\n\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n {\n role: \"system\",\n content: `Summarize this context block in ${budgetPerBlock} tokens or less. Preserve code signatures, key facts, and important details. Output only the summary.`,\n },\n { role: \"user\", content: block },\n ],\n max_tokens: budgetPerBlock,\n temperature: 0,\n });\n\n return res.choices[0]?.message?.content?.trim() || block.slice(0, budgetPerBlock * 4);\n })\n );\n\n const compressed = summaries.join(\"\\n\\n---\\n\\n\");\n let compressedTokens = estimateTokens(compressed);\n\n // Final trim if still over\n let finalContext = compressed;\n if (compressedTokens > maxTokens) {\n finalContext = truncateToTokens(compressed, maxTokens);\n compressedTokens = estimateTokens(finalContext);\n }\n\n return {\n context: finalContext,\n originalTokens,\n compressedTokens,\n reductionPercent: Math.round((1 - compressedTokens / originalTokens) * 100),\n strategy: \"summarize\",\n };\n } catch {\n const truncated = truncateToTokens(rawContext, maxTokens);\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"truncate-fallback\",\n };\n }\n}\n\n// ─── Pre-computed Chunk Summaries ────────────────────────────\n// Summarize chunks at ingest time so retrieval is cheaper\n\nexport async function summarizeChunk(content: string, chunkType: string): Promise<string> {\n // Only summarize large chunks\n if (estimateTokens(content) < 200) return content;\n\n try {\n const prompt = chunkType === \"code\"\n ? \"Summarize this code in 2-3 sentences. Include: function/class names, what it does, parameters, return type.\"\n : \"Summarize this text in 2-3 sentences. Preserve key facts, names, and important details.\";\n\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n { role: \"system\", content: prompt },\n { role: \"user\", content: content.slice(0, 3000) },\n ],\n max_tokens: 150,\n temperature: 0,\n });\n\n return res.choices[0]?.message?.content?.trim() || content;\n } catch {\n return content;\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction truncateToTokens(text: string, maxTokens: number): string {\n const maxChars = maxTokens * 4;\n if (text.length <= maxChars) return text;\n return text.slice(0, maxChars) + \"\\n\\n[...truncated]\";\n}\n\n// Cleanup stale delta cache entries periodically\nsetInterval(() => {\n const now = Date.now();\n for (const [key, val] of deltaCache) {\n if (now - val.timestamp > DELTA_CACHE_TTL) deltaCache.delete(key);\n }\n}, 60_000);\n","import { db, documents, chunks, sources } from \"../db/index.js\";\nimport { eq } from \"drizzle-orm\";\nimport { chunkText } from \"./chunker.js\";\nimport { embed } from \"./embeddings.js\";\nimport { extractEntities } from \"./extractor.js\";\nimport { createHash } from \"crypto\";\nimport PQueue from \"p-queue\";\n\nconst queue = new PQueue({ concurrency: 3 });\n\n// Entity extraction is async and non-blocking — failures don't break ingestion\nconst ENABLE_AUTO_EXTRACTION = process.env.DISABLE_AUTO_EXTRACTION !== \"true\";\n\nexport interface IngestDocumentInput {\n sourceId: string;\n projectId: string;\n externalId: string;\n title: string;\n content: string;\n metadata?: Record<string, any>;\n filePath?: string;\n skipEntityExtraction?: boolean;\n}\n\nexport async function ingestDocument(input: IngestDocumentInput) {\n const { sourceId, projectId, externalId, title, content, metadata = {}, filePath } = input;\n\n const contentHash = createHash(\"sha256\").update(content).digest(\"hex\");\n\n // Upsert document\n const [doc] = await db\n .insert(documents)\n .values({\n sourceId,\n projectId,\n externalId,\n title,\n content,\n metadata,\n contentHash,\n })\n .onConflictDoUpdate({\n target: [documents.sourceId, documents.externalId],\n set: { title, content, metadata, contentHash, updatedAt: new Date() },\n })\n .returning();\n\n // Delete old chunks for this document\n await db.delete(chunks).where(eq(chunks.documentId, doc.id));\n\n // Chunk the content\n const textChunks = chunkText(content, {\n filePath: filePath || externalId,\n metadata: { ...metadata, title },\n });\n\n if (textChunks.length === 0) return doc;\n\n // Embed in batches of 50\n const batchSize = 50;\n const insertedChunkIds: string[] = [];\n\n for (let i = 0; i < textChunks.length; i += batchSize) {\n const batch = textChunks.slice(i, i + batchSize);\n const embeddings = await embed(batch.map((c) => c.content));\n\n const inserted = await db.insert(chunks).values(\n batch.map((chunk, j) => ({\n documentId: doc.id,\n projectId,\n content: chunk.content,\n chunkType: chunk.chunkType,\n chunkIndex: chunk.chunkIndex,\n metadata: chunk.metadata,\n embedding: embeddings[j],\n tokenCount: Math.ceil(chunk.content.length / 4),\n }))\n ).returning({ id: chunks.id });\n\n insertedChunkIds.push(...inserted.map((c) => c.id));\n }\n\n // Auto entity extraction (fire-and-forget, non-blocking)\n if (ENABLE_AUTO_EXTRACTION && !input.skipEntityExtraction) {\n // Only extract from the first few significant chunks to save tokens\n const chunksToExtract = textChunks\n .filter((c) => c.content.length > 200)\n .slice(0, 5);\n\n for (let i = 0; i < chunksToExtract.length; i++) {\n const chunk = chunksToExtract[i];\n const chunkId = insertedChunkIds[textChunks.indexOf(chunk)];\n\n // Don't await — let it run in background\n extractEntities(projectId, chunk.content, chunk.chunkType, metadata, chunkId).catch(() => {\n // Silently ignore extraction failures\n });\n }\n }\n\n // Update source counts\n const docCount = await db\n .select({ count: db.$count(documents, eq(documents.sourceId, sourceId)) })\n .from(documents);\n\n const chunkCount = await db\n .select({ count: db.$count(chunks, eq(chunks.documentId, doc.id)) })\n .from(chunks);\n\n await db\n .update(sources)\n .set({\n documentCount: Number(docCount[0]?.count || 0),\n chunkCount: Number(chunkCount[0]?.count || 0),\n lastSyncAt: new Date(),\n status: \"ready\",\n updatedAt: new Date(),\n })\n .where(eq(sources.id, sourceId));\n\n return doc;\n}\n\nexport async function ingestDocuments(inputs: IngestDocumentInput[]) {\n const results = await Promise.all(\n inputs.map((input) => queue.add(() => ingestDocument(input)))\n );\n return results;\n}\n","export interface Chunk {\n content: string;\n metadata: Record<string, any>;\n chunkType: \"code\" | \"documentation\" | \"api_spec\" | \"schema\" | \"config\" | \"text\" | \"comment\";\n chunkIndex: number;\n}\n\nconst CODE_EXTENSIONS = new Set([\n \".ts\", \".tsx\", \".js\", \".jsx\", \".py\", \".java\", \".go\", \".rb\",\n \".php\", \".cs\", \".rs\", \".swift\", \".kt\", \".scala\", \".c\", \".cpp\",\n \".h\", \".hpp\", \".sol\", \".vy\",\n]);\n\nconst CONFIG_EXTENSIONS = new Set([\n \".json\", \".yaml\", \".yml\", \".toml\", \".ini\", \".env\", \".xml\",\n]);\n\nexport function detectChunkType(filePath?: string, content?: string): Chunk[\"chunkType\"] {\n if (!filePath) return \"text\";\n\n const ext = \".\" + filePath.split(\".\").pop()?.toLowerCase();\n\n if (CODE_EXTENSIONS.has(ext)) return \"code\";\n if (CONFIG_EXTENSIONS.has(ext)) return \"config\";\n if (filePath.includes(\"schema\") || filePath.includes(\"migration\")) return \"schema\";\n if (filePath.endsWith(\".md\") || filePath.endsWith(\".mdx\") || filePath.endsWith(\".rst\")) return \"documentation\";\n if (filePath.includes(\"openapi\") || filePath.includes(\"swagger\")) return \"api_spec\";\n\n return \"text\";\n}\n\nexport function chunkText(\n content: string,\n opts: {\n chunkSize?: number;\n chunkOverlap?: number;\n filePath?: string;\n metadata?: Record<string, any>;\n } = {}\n): Chunk[] {\n const { chunkSize = 1000, chunkOverlap = 200, filePath, metadata = {} } = opts;\n const chunkType = detectChunkType(filePath, content);\n\n // For code, try to split on function/class boundaries first\n if (chunkType === \"code\") {\n return chunkCode(content, { chunkSize, filePath, metadata });\n }\n\n // For everything else, split by paragraphs/sections then by size\n return chunkBySize(content, { chunkSize, chunkOverlap, chunkType, metadata });\n}\n\nfunction chunkCode(\n content: string,\n opts: { chunkSize: number; filePath?: string; metadata?: Record<string, any> }\n): Chunk[] {\n const { chunkSize, filePath, metadata = {} } = opts;\n const lines = content.split(\"\\n\");\n const chunks: Chunk[] = [];\n\n // Split on common code boundaries\n const boundaries = [\n /^(export\\s+)?(async\\s+)?function\\s+/,\n /^(export\\s+)?(default\\s+)?class\\s+/,\n /^(export\\s+)?const\\s+\\w+\\s*=\\s*(async\\s+)?\\(/,\n /^(export\\s+)?const\\s+\\w+\\s*=\\s*\\{/,\n /^(export\\s+)?interface\\s+/,\n /^(export\\s+)?type\\s+/,\n /^(export\\s+)?enum\\s+/,\n /^def\\s+/, // Python\n /^class\\s+/, // Python/Java\n /^func\\s+/, // Go\n /^pub\\s+(fn|struct|enum|impl)/, // Rust\n ];\n\n let currentChunk: string[] = [];\n let currentStart = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i].trimStart();\n const isBoundary = boundaries.some((b) => b.test(trimmed));\n\n if (isBoundary && currentChunk.length > 0) {\n const chunkContent = currentChunk.join(\"\\n\").trim();\n if (chunkContent.length > 0) {\n chunks.push({\n content: chunkContent,\n chunkType: \"code\",\n chunkIndex: chunks.length,\n metadata: {\n ...metadata,\n filePath,\n startLine: currentStart + 1,\n endLine: i,\n },\n });\n }\n currentChunk = [lines[i]];\n currentStart = i;\n } else {\n currentChunk.push(lines[i]);\n }\n\n // If chunk is too big, flush it\n if (currentChunk.join(\"\\n\").length > chunkSize * 1.5) {\n const chunkContent = currentChunk.join(\"\\n\").trim();\n if (chunkContent.length > 0) {\n chunks.push({\n content: chunkContent,\n chunkType: \"code\",\n chunkIndex: chunks.length,\n metadata: {\n ...metadata,\n filePath,\n startLine: currentStart + 1,\n endLine: i + 1,\n },\n });\n }\n currentChunk = [];\n currentStart = i + 1;\n }\n }\n\n // Flush remaining\n if (currentChunk.length > 0) {\n const chunkContent = currentChunk.join(\"\\n\").trim();\n if (chunkContent.length > 0) {\n chunks.push({\n content: chunkContent,\n chunkType: \"code\",\n chunkIndex: chunks.length,\n metadata: {\n ...metadata,\n filePath,\n startLine: currentStart + 1,\n endLine: lines.length,\n },\n });\n }\n }\n\n return chunks;\n}\n\nfunction chunkBySize(\n content: string,\n opts: {\n chunkSize: number;\n chunkOverlap: number;\n chunkType: Chunk[\"chunkType\"];\n metadata?: Record<string, any>;\n }\n): Chunk[] {\n const { chunkSize, chunkOverlap, chunkType, metadata = {} } = opts;\n const chunks: Chunk[] = [];\n\n // Split on double newlines (paragraphs) first\n const paragraphs = content.split(/\\n\\n+/);\n let current = \"\";\n\n for (const para of paragraphs) {\n if ((current + \"\\n\\n\" + para).length > chunkSize && current.length > 0) {\n chunks.push({\n content: current.trim(),\n chunkType,\n chunkIndex: chunks.length,\n metadata,\n });\n // Keep overlap\n const words = current.split(/\\s+/);\n const overlapWords = words.slice(-Math.floor(chunkOverlap / 5));\n current = overlapWords.join(\" \") + \"\\n\\n\" + para;\n } else {\n current = current ? current + \"\\n\\n\" + para : para;\n }\n }\n\n if (current.trim().length > 0) {\n chunks.push({\n content: current.trim(),\n chunkType,\n chunkIndex: chunks.length,\n metadata,\n });\n }\n\n return chunks;\n}\n","import OpenAI from \"openai\";\nimport { db, entities, relations, memories } from \"../db/index.js\";\nimport { eq, and } from \"drizzle-orm\";\nimport { embedSingle } from \"./embeddings.js\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ═══════════════════════════════════════════════════════════════\n// ENTITY EXTRACTION (runs during ingestion)\n// ═══════════════════════════════════════════════════════════════\n\ninterface ExtractedEntity {\n name: string;\n type: string; // function, class, module, concept, api_endpoint, config, service, etc.\n description: string;\n}\n\ninterface ExtractedRelation {\n from: string;\n fromType: string;\n to: string;\n toType: string;\n relation: string; // imports, calls, extends, depends_on, etc.\n}\n\nexport async function extractEntities(\n projectId: string,\n content: string,\n chunkType: string,\n metadata: Record<string, any> = {},\n chunkId?: string\n): Promise<{ entities: number; relations: number }> {\n // Skip small chunks\n if (content.length < 100) return { entities: 0, relations: 0 };\n\n const isCode = [\"code\", \"function\", \"class\"].includes(chunkType);\n\n const prompt = isCode\n ? `Analyze this code and extract entities and relationships.\n\nEntities: functions, classes, interfaces, types, modules, variables, constants, API endpoints, services.\nRelations: imports, exports, calls, implements, extends, depends_on, references, part_of.\n\nCode:\n\\`\\`\\`\n${content.slice(0, 3000)}\n\\`\\`\\`\n\nRespond with JSON only:\n{\n \"entities\": [{\"name\": \"...\", \"type\": \"function|class|interface|module|constant|api_endpoint|service\", \"description\": \"one line\"}],\n \"relations\": [{\"from\": \"name\", \"fromType\": \"type\", \"to\": \"name\", \"toType\": \"type\", \"relation\": \"imports|calls|extends|implements|depends_on|references|part_of\"}]\n}`\n : `Analyze this text and extract key entities (concepts, people, tools, services, APIs, technologies) and their relationships.\n\nText:\n${content.slice(0, 3000)}\n\nRespond with JSON only:\n{\n \"entities\": [{\"name\": \"...\", \"type\": \"concept|tool|service|api|technology|person|organization\", \"description\": \"one line\"}],\n \"relations\": [{\"from\": \"name\", \"fromType\": \"type\", \"to\": \"name\", \"toType\": \"type\", \"relation\": \"references|depends_on|related_to|part_of|supersedes\"}]\n}`;\n\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [{ role: \"user\", content: prompt }],\n temperature: 0,\n max_tokens: 1000,\n response_format: { type: \"json_object\" },\n });\n\n const text = res.choices[0]?.message?.content?.trim() || \"{}\";\n const parsed = JSON.parse(text);\n\n const extractedEntities: ExtractedEntity[] = parsed.entities || [];\n const extractedRelations: ExtractedRelation[] = parsed.relations || [];\n\n let entityCount = 0;\n let relationCount = 0;\n\n // Upsert entities\n const entityMap = new Map<string, string>(); // name:type -> id\n\n for (const ent of extractedEntities.slice(0, 20)) {\n if (!ent.name || !ent.type) continue;\n\n const embedding = await embedSingle(`${ent.type}: ${ent.name} - ${ent.description || \"\"}`);\n\n const [entity] = await db\n .insert(entities)\n .values({\n projectId,\n name: ent.name,\n entityType: ent.type,\n description: ent.description,\n metadata: { ...metadata, autoExtracted: true },\n sourceChunkId: chunkId,\n embedding,\n })\n .onConflictDoUpdate({\n target: [entities.projectId, entities.name, entities.entityType],\n set: {\n description: ent.description,\n sourceChunkId: chunkId,\n embedding,\n updatedAt: new Date(),\n },\n })\n .returning();\n\n entityMap.set(`${ent.name}:${ent.type}`, entity.id);\n entityCount++;\n }\n\n // Upsert relations\n for (const rel of extractedRelations.slice(0, 30)) {\n if (!rel.from || !rel.to || !rel.relation) continue;\n\n const fromId = entityMap.get(`${rel.from}:${rel.fromType}`);\n const toId = entityMap.get(`${rel.to}:${rel.toType}`);\n\n if (!fromId || !toId) continue;\n\n // Validate relation type\n const validRelations = [\n \"imports\", \"exports\", \"calls\", \"implements\", \"extends\",\n \"references\", \"depends_on\", \"related_to\", \"part_of\",\n \"contradicts\", \"supersedes\",\n ];\n if (!validRelations.includes(rel.relation)) continue;\n\n await db\n .insert(relations)\n .values({\n projectId,\n fromEntityId: fromId,\n toEntityId: toId,\n relationType: rel.relation as any,\n metadata: { autoExtracted: true },\n })\n .onConflictDoUpdate({\n target: [relations.fromEntityId, relations.toEntityId, relations.relationType],\n set: { metadata: { autoExtracted: true } },\n });\n\n relationCount++;\n }\n\n return { entities: entityCount, relations: relationCount };\n } catch {\n return { entities: 0, relations: 0 };\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY EXTRACTION (runs on conversation messages)\n// ═══════════════════════════════════════════════════════════════\n\ninterface ExtractedMemory {\n content: string;\n type: \"factual\" | \"episodic\" | \"semantic\" | \"procedural\";\n importance: number;\n}\n\n/**\n * Analyzes a conversation message (or batch) and extracts facts worth remembering.\n * Call this after adding messages to a conversation.\n */\nexport async function extractMemories(\n projectId: string,\n messages: { role: string; content: string }[],\n opts?: { userId?: string; sessionId?: string; agentId?: string }\n): Promise<{ memoriesCreated: number }> {\n if (messages.length === 0) return { memoriesCreated: 0 };\n\n const conversation = messages\n .map((m) => `[${m.role}]: ${m.content}`)\n .join(\"\\n\\n\");\n\n // Skip very short conversations\n if (conversation.length < 50) return { memoriesCreated: 0 };\n\n const prompt = `Analyze this conversation and extract important facts, preferences, decisions, or knowledge worth remembering for future interactions.\n\nRules:\n- Only extract truly useful information (not greetings, acknowledgments, etc.)\n- Each memory should be a standalone fact\n- Set importance 0-1 (1 = critical preference/decision, 0.3 = minor detail)\n- Type: factual (facts/preferences), episodic (what happened), semantic (general knowledge), procedural (how to do something)\n- If nothing worth remembering, return empty array\n\nConversation:\n${conversation.slice(0, 4000)}\n\nRespond with JSON only:\n{\n \"memories\": [\n {\"content\": \"standalone fact\", \"type\": \"factual|episodic|semantic|procedural\", \"importance\": 0.5}\n ]\n}`;\n\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [{ role: \"user\", content: prompt }],\n temperature: 0,\n max_tokens: 500,\n response_format: { type: \"json_object\" },\n });\n\n const text = res.choices[0]?.message?.content?.trim() || \"{}\";\n const parsed = JSON.parse(text);\n const extracted: ExtractedMemory[] = parsed.memories || [];\n\n let created = 0;\n\n for (const mem of extracted.slice(0, 10)) {\n if (!mem.content || mem.content.length < 10) continue;\n\n const embedding = await embedSingle(mem.content);\n\n const validTypes = [\"factual\", \"episodic\", \"semantic\", \"procedural\"];\n const memType = validTypes.includes(mem.type) ? mem.type : \"factual\";\n const importance = Math.max(0, Math.min(1, mem.importance || 0.5));\n\n await db.insert(memories).values({\n projectId,\n content: mem.content,\n memoryType: memType as any,\n importance,\n userId: opts?.userId,\n sessionId: opts?.sessionId,\n agentId: opts?.agentId,\n embedding,\n metadata: { autoExtracted: true },\n });\n\n created++;\n }\n\n return { memoriesCreated: created };\n } catch {\n return { memoriesCreated: 0 };\n }\n}\n"],"mappings":"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","names":["eq","and","sql","text","OpenAI","openai","text","text","createHash","OpenAI","openai","estimateTokens","text","eq","chunks","OpenAI","openai","OpenAI","text","createHash","eq","and","eq","sql","text"]}
1
+ {"version":3,"sources":["../../src/mcp/server.ts","../../src/engine/compressor.ts","../../src/engine/retriever.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { prisma } from \"../db/index.js\";\nimport { retrieve } from \"../engine/retriever.js\";\nimport { ingestDocument } from \"../engine/ingest.js\";\nimport { embedSingle } from \"../engine/embeddings.js\";\n\nconst ORG_ID = process.env.WHISPER_ORG_ID || \"\";\n\nconst server = new McpServer({\n name: \"whisper-context\",\n version: \"0.1.0\",\n});\n\nasync function resolveProject(name: string) {\n const proj = await prisma.project.findFirst({\n where: {\n orgId: ORG_ID,\n OR: [\n { name },\n { slug: name },\n ],\n },\n });\n return proj;\n}\n\n// ─── query_context ──────────────────────────────────────────\n\nserver.tool(\n \"query_context\",\n \"Search your knowledge base for relevant context. Returns packed context ready for LLM consumption. Supports hybrid vector+keyword search, memory inclusion, and knowledge graph traversal.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"What are you looking for?\"),\n top_k: z.number().optional().default(10).describe(\"Number of results\"),\n chunk_types: z.array(z.string()).optional().describe(\"Filter: code, function, class, documentation, api_spec, schema, config, text\"),\n include_memories: z.boolean().optional().default(false).describe(\"Include relevant memories\"),\n include_graph: z.boolean().optional().default(false).describe(\"Include knowledge graph traversal\"),\n user_id: z.string().optional().describe(\"User ID for memory scoping\"),\n session_id: z.string().optional().describe(\"Session ID for memory scoping\"),\n max_tokens: z.number().optional().describe(\"Max tokens for packed context\"),\n },\n async ({ project, query, top_k, chunk_types, include_memories, include_graph, user_id, session_id, max_tokens }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const response = await retrieve({\n projectId: proj.id,\n query,\n topK: top_k,\n chunkTypes: chunk_types,\n includeMemories: include_memories,\n includeGraph: include_graph,\n userId: user_id,\n sessionId: session_id,\n maxTokens: max_tokens,\n });\n\n if (response.results.length === 0) {\n return { content: [{ type: \"text\" as const, text: \"No relevant context found.\" }] };\n }\n\n const header = `Found ${response.meta.totalResults} results (${response.meta.latencyMs}ms${response.meta.cacheHit ? \", cached\" : \"\"}):\\n\\n`;\n return { content: [{ type: \"text\" as const, text: header + response.context }] };\n }\n);\n\n// ─── add_memory ─────────────────────────────────────────────\n\nserver.tool(\n \"add_memory\",\n \"Store a memory (fact, preference, decision) that persists across conversations. Memories can be scoped to a user, session, or agent.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n content: z.string().describe(\"The memory content to store\"),\n memory_type: z.enum([\"factual\", \"episodic\", \"semantic\", \"procedural\"]).optional().default(\"factual\"),\n user_id: z.string().optional().describe(\"User this memory belongs to\"),\n session_id: z.string().optional().describe(\"Session scope\"),\n agent_id: z.string().optional().describe(\"Agent scope\"),\n importance: z.number().optional().default(0.5).describe(\"Importance 0-1\"),\n },\n async ({ project, content, memory_type, user_id, session_id, agent_id, importance }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const embedding = await embedSingle(content);\n const memory = await prisma.memory.create({\n data: {\n projectId: proj.id,\n content,\n memoryType: memory_type,\n userId: user_id,\n sessionId: session_id,\n agentId: agent_id,\n importance,\n embedding,\n } as any,\n });\n\n return { content: [{ type: \"text\" as const, text: `Memory stored (id: ${memory.id}, type: ${memory_type}).` }] };\n }\n);\n\n// ─── search_memories ────────────────────────────────────────\n\nserver.tool(\n \"search_memories\",\n \"Search stored memories by semantic similarity. Recall facts, preferences, past decisions from previous interactions.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"What to search for\"),\n user_id: z.string().optional().describe(\"Filter by user\"),\n session_id: z.string().optional().describe(\"Filter by session\"),\n top_k: z.number().optional().default(10).describe(\"Number of results\"),\n },\n async ({ project, query, user_id, session_id, top_k }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const queryEmbedding = await embedSingle(query);\n \n // Using raw query for vector search with dynamic conditions\n let whereClause = `\n project_id = '${proj.id}' \n AND is_active = true \n AND (expires_at IS NULL OR expires_at > NOW())\n `;\n if (user_id) whereClause += ` AND user_id = '${user_id}'`;\n if (session_id) whereClause += ` AND session_id = '${session_id}'`;\n\n const results = await prisma.$queryRawUnsafe(`\n SELECT \n id, content, memory_type as \"memoryType\", importance,\n 1 - (embedding <=> '${JSON.stringify(queryEmbedding)}'::vector) as similarity\n FROM memories\n WHERE ${whereClause}\n ORDER BY embedding <=> '${JSON.stringify(queryEmbedding)}'::vector\n LIMIT ${top_k}\n `);\n\n if ((results as any[]).length === 0) return { content: [{ type: \"text\" as const, text: \"No memories found.\" }] };\n\n const text = (results as any[])\n .map((r, i) => `${i + 1}. [${r.memoryType}, importance: ${r.importance}, score: ${(r.similarity as number).toFixed(3)}]\\n${r.content}`)\n .join(\"\\n\\n\");\n\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── list_projects ──────────────────────────────────────────\n\nserver.tool(\n \"list_projects\",\n \"List all available context projects.\",\n {},\n async () => {\n const projs = await prisma.project.findMany({\n where: { orgId: ORG_ID },\n });\n const text = projs.length === 0\n ? \"No projects found.\"\n : projs.map((p) => `- ${p.name} (${p.slug})${p.description ? `: ${p.description}` : \"\"}`).join(\"\\n\");\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── list_sources ───────────────────────────────────────────\n\nserver.tool(\n \"list_sources\",\n \"List all data sources connected to a project.\",\n { project: z.string().describe(\"Project name or slug\") },\n async ({ project }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const srcs = await prisma.source.findMany({\n where: { projectId: proj.id },\n });\n const text = srcs.length === 0\n ? \"No sources connected.\"\n : srcs.map((s) => `- ${s.name} (${s.connectorType}) — ${s.status} | ${s.documentCount} docs, ${s.chunkCount} chunks`).join(\"\\n\");\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── add_context ────────────────────────────────────────────\n\nserver.tool(\n \"add_context\",\n \"Add text content to a project's knowledge base.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n title: z.string().describe(\"Title for this content\"),\n content: z.string().describe(\"The text content to index\"),\n },\n async ({ project, title, content }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n let directSource = await prisma.source.findFirst({\n where: {\n projectId: proj.id,\n connectorType: \"custom\",\n name: \"mcp-ingest\",\n },\n });\n\n if (!directSource) {\n directSource = await prisma.source.create({\n data: {\n orgId: ORG_ID,\n projectId: proj.id,\n name: \"mcp-ingest\",\n type: \"custom\",\n connectorType: \"custom\",\n config: {},\n status: \"READY\",\n },\n });\n }\n\n await ingestDocument({ sourceId: directSource.id, projectId: proj.id, externalId: `mcp-${title}`, title, content });\n return { content: [{ type: \"text\" as const, text: `Indexed \"${title}\" (${content.length} chars) into '${project}'.` }] };\n }\n);\n\n// ─── track_conversation ─────────────────────────────────────\n\nserver.tool(\n \"track_conversation\",\n \"Add a message to a conversation. Creates the conversation if it doesn't exist.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Unique session identifier\"),\n role: z.enum([\"user\", \"assistant\", \"system\", \"tool\"]),\n content: z.string().describe(\"Message content\"),\n user_id: z.string().optional().describe(\"User identifier\"),\n },\n async ({ project, session_id, role, content, user_id }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n let conv = await prisma.session.findFirst({\n where: {\n projectId: proj.id,\n sessionId: session_id,\n },\n });\n\n if (!conv) {\n conv = await prisma.session.create({\n data: {\n projectId: proj.id,\n sessionId: session_id,\n userId: user_id,\n },\n });\n }\n\n await prisma.message.create({\n data: {\n conversationId: conv.id,\n role,\n content,\n },\n });\n\n await prisma.session.update({\n where: { id: conv.id },\n data: {\n messageCount: { increment: 1 },\n updatedAt: new Date(),\n },\n });\n\n return { content: [{ type: \"text\" as const, text: `Message added (session: ${session_id}).` }] };\n }\n);\n\n// ─── get_conversation ───────────────────────────────────────\n\nserver.tool(\n \"get_conversation\",\n \"Retrieve conversation history for a session.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Session identifier\"),\n limit: z.number().optional().default(50),\n },\n async ({ project, session_id, limit }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const conv = await prisma.session.findFirst({\n where: {\n projectId: proj.id,\n sessionId: session_id,\n },\n });\n\n if (!conv) return { content: [{ type: \"text\" as const, text: \"No conversation found for this session.\" }] };\n\n const msgs = await prisma.message.findMany({\n where: { conversationId: conv.id },\n orderBy: { createdAt: 'asc' },\n take: limit,\n });\n\n const text = msgs.map((m) => `[${m.role}]: ${m.content}`).join(\"\\n\\n\");\n return { content: [{ type: \"text\" as const, text: text || \"No messages yet.\" }] };\n }\n);\n\n// ─── SOTA MEMORY TOOLS ──────────────────────────────────────\n\nserver.tool(\n \"memory_search_sota\",\n \"SOTA memory search with temporal reasoning and relation graphs. Searches memories with support for temporal queries ('what did I say yesterday?'), type filtering, and knowledge graph traversal.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"Search query (supports temporal: 'yesterday', 'last week')\"),\n user_id: z.string().optional().describe(\"Filter by user\"),\n session_id: z.string().optional().describe(\"Filter by session\"),\n question_date: z.string().optional().describe(\"ISO datetime for temporal grounding\"),\n memory_types: z.array(z.enum([\"factual\", \"preference\", \"event\", \"relationship\", \"opinion\", \"goal\", \"instruction\"])).optional(),\n top_k: z.number().optional().default(10),\n include_relations: z.boolean().optional().default(true).describe(\"Include related memories via knowledge graph\"),\n },\n async ({ project, query, user_id, session_id, question_date, memory_types, top_k, include_relations }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n // Import SOTA search function\n const { searchMemories } = await import(\"../engine/memory/search.js\");\n\n const results = await searchMemories({\n query,\n questionDate: question_date ? new Date(question_date) : new Date(),\n projectId: proj.id,\n orgId: ORG_ID,\n userId: user_id,\n sessionId: session_id,\n topK: top_k,\n memoryTypes: memory_types,\n });\n\n if (results.length === 0) return { content: [{ type: \"text\" as const, text: \"No memories found.\" }] };\n\n const text = results.map((r, i) => {\n let line = `${i + 1}. [${r.memory.memoryType}, confidence: ${r.memory.confidence.toFixed(2)}, score: ${r.similarity.toFixed(3)}]\\n`;\n line += ` ${r.memory.content}\\n`;\n if (r.memory.temporal.eventDate) {\n line += ` Event: ${r.memory.temporal.eventDate.toISOString().split('T')[0]}\\n`;\n }\n if (include_relations && r.relations && r.relations.length > 0) {\n line += ` Relations: ${r.relations.map(rel => rel.relationType).join(\", \")}\\n`;\n }\n return line;\n }).join(\"\\n\");\n\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\nserver.tool(\n \"ingest_conversation\",\n \"Extract memories from a conversation session. Automatically handles disambiguation, temporal grounding, and relation detection.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Session identifier\"),\n user_id: z.string().optional().describe(\"User identifier\"),\n messages: z.array(z.object({\n role: z.string(),\n content: z.string(),\n timestamp: z.string(),\n })).describe(\"Array of conversation messages with timestamps\"),\n },\n async ({ project, session_id, user_id, messages }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const { ingestSession } = await import(\"../engine/memory/ingest.js\");\n\n const result = await ingestSession({\n sessionId: session_id,\n projectId: proj.id,\n orgId: ORG_ID,\n userId: user_id,\n messages: messages.map(m => ({\n role: m.role,\n content: m.content,\n timestamp: new Date(m.timestamp),\n })),\n });\n\n return {\n content: [{\n type: \"text\" as const,\n text: `Processed ${messages.length} messages:\\n` +\n `- Created ${result.memoriesCreated} memories\\n` +\n `- Detected ${result.relationsCreated} relations\\n` +\n `- Updated ${result.memoriesInvalidated} outdated memories` +\n (result.errors && result.errors.length > 0 ? `\\n- Errors: ${result.errors.join(\", \")}` : \"\"),\n }],\n };\n }\n);\n\n// ─── CONTEXT LAYER TOOLS ────────────────────────────────────\n\nserver.tool(\n \"oracle_search\",\n \"Oracle Research Mode - Tree-guided document navigation with multi-step reasoning. More precise than standard search, especially for bleeding-edge features.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n query: z.string().describe(\"Research question\"),\n mode: z.enum([\"search\", \"research\"]).optional().default(\"search\").describe(\"'search' for tree-guided, 'research' for multi-step reasoning\"),\n max_results: z.number().optional().default(5),\n max_steps: z.number().optional().default(5).describe(\"For research mode: max reasoning steps\"),\n },\n async ({ project, query, mode, max_results, max_steps }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const { oracleSearch, oracleResearch } = await import(\"../engine/oracle.js\");\n\n if (mode === \"research\") {\n const result = await oracleResearch({\n question: query,\n projectId: proj.id,\n maxSteps: max_steps,\n });\n\n let text = `Answer: ${result.answer}\\n\\nReasoning Steps:\\n`;\n result.steps.forEach((step, i) => {\n text += `${i + 1}. Query: ${step.query}\\n Reasoning: ${step.reasoning}\\n Results: ${step.results.length} items\\n`;\n });\n\n return { content: [{ type: \"text\" as const, text }] };\n } else {\n const results = await oracleSearch({\n query,\n projectId: proj.id,\n topK: max_results,\n });\n\n if (results.length === 0) return { content: [{ type: \"text\" as const, text: \"No results found.\" }] };\n\n const text = results.map((r, i) =>\n `${i + 1}. [${r.path}] (relevance: ${r.relevance.toFixed(3)})\\n${r.content.slice(0, 200)}...`\n ).join(\"\\n\\n\");\n\n return { content: [{ type: \"text\" as const, text }] };\n }\n }\n);\n\nserver.tool(\n \"autosubscribe_dependencies\",\n \"Automatically index a project's dependencies (package.json, requirements.txt, etc.). Resolves docs URLs and indexes documentation.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n source_type: z.enum([\"github\", \"local\"]).describe(\"Source location\"),\n github_owner: z.string().optional().describe(\"For GitHub: owner/org name\"),\n github_repo: z.string().optional().describe(\"For GitHub: repository name\"),\n local_path: z.string().optional().describe(\"For local: path to dependency file\"),\n dependency_file: z.enum([\"package.json\", \"requirements.txt\", \"Cargo.toml\", \"go.mod\", \"Gemfile\"]).optional(),\n index_limit: z.number().optional().default(20).describe(\"Max dependencies to index\"),\n },\n async ({ project, source_type, github_owner, github_repo, local_path, dependency_file, index_limit }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const { autosubscribe } = await import(\"../engine/autosubscribe.js\");\n\n const result = await autosubscribe({\n projectId: proj.id,\n orgId: ORG_ID,\n source: source_type === \"github\"\n ? { type: \"github\", owner: github_owner!, repo: github_repo! }\n : { type: \"local\", filePath: local_path! },\n indexLimit: index_limit,\n });\n\n return {\n content: [{\n type: \"text\" as const,\n text: `Autosubscribe completed:\\n` +\n `- Discovered: ${result.discovered} dependencies\\n` +\n `- Indexed: ${result.indexed} successfully\\n` +\n `- Skipped: ${result.skipped} (already indexed)\\n` +\n `- Errors: ${result.errors.length}`,\n }],\n };\n }\n);\n\nserver.tool(\n \"share_context\",\n \"Create a shareable snapshot of a conversation with memories. Returns a URL that can be shared or resumed later.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n session_id: z.string().describe(\"Session to share\"),\n title: z.string().optional().describe(\"Title for the shared context\"),\n expiry_days: z.number().optional().default(30).describe(\"Days until expiry\"),\n },\n async ({ project, session_id, title, expiry_days }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const { createSharedContext } = await import(\"../engine/context-sharing.js\");\n\n const result = await createSharedContext({\n sessionId: session_id,\n projectId: proj.id,\n orgId: ORG_ID,\n includeMemories: true,\n expiryDays: expiry_days,\n });\n\n return {\n content: [{\n type: \"text\" as const,\n text: `Shared context created:\\n` +\n `- Share ID: ${result.id}\\n` +\n `- Memories: ${result.memories?.length || 0}\\n` +\n `- Messages: ${result.messages?.length || 0}\\n` +\n `- Expires: ${result.expiresAt?.toISOString() || 'Never'}\\n` +\n `\\nShare URL: ${result.shareUrl}`,\n }],\n };\n }\n);\n\n// ─── OPTIMIZATION TOOLS ─────────────────────────────────────\n\nserver.tool(\n \"consolidate_memories\",\n \"Find and merge duplicate memories to reduce bloat. Uses vector similarity + LLM merging.\",\n {\n project: z.string().describe(\"Project name or slug\"),\n similarity_threshold: z.number().optional().default(0.95).describe(\"Similarity threshold (0-1)\"),\n dry_run: z.boolean().optional().default(false).describe(\"Preview without merging\"),\n },\n async ({ project, similarity_threshold, dry_run }) => {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n\n const { findDuplicateMemories, consolidateMemories } = await import(\"../engine/memory/consolidation.js\");\n\n if (dry_run) {\n const clusters = await findDuplicateMemories({\n projectId: proj.id,\n similarityThreshold: similarity_threshold,\n });\n\n const totalDuplicates = clusters.reduce((sum, c) => sum + c.duplicates.length, 0);\n\n return {\n content: [{\n type: \"text\" as const,\n text: `Found ${clusters.length} duplicate clusters:\\n` +\n `- Total duplicates: ${totalDuplicates}\\n` +\n `- Estimated savings: ${totalDuplicates} memories\\n` +\n `\\nRun without dry_run to merge.`,\n }],\n };\n } else {\n const result = await consolidateMemories({\n projectId: proj.id,\n similarityThreshold: similarity_threshold,\n dryRun: false,\n });\n\n return {\n content: [{\n type: \"text\" as const,\n text: `Consolidation complete:\\n` +\n `- Clusters found: ${result.clustersFound}\\n` +\n `- Memories merged: ${result.memoriesMerged}\\n` +\n `- Memories deactivated: ${result.memoriesDeactivated}`,\n }],\n };\n }\n }\n);\n\nserver.tool(\n \"get_cost_summary\",\n \"Get cost tracking summary showing spending by model and task. Includes savings vs always-Opus.\",\n {\n project: z.string().optional().describe(\"Project name or slug (optional for org-wide)\"),\n days: z.number().optional().default(30).describe(\"Time period in days\"),\n },\n async ({ project, days }) => {\n let projectId: string | undefined;\n if (project) {\n const proj = await resolveProject(project);\n if (!proj) return { content: [{ type: \"text\" as const, text: `Project '${project}' not found.` }] };\n projectId = proj.id;\n }\n\n const { getCostSummary, calculateSavings } = await import(\"../engine/cost-optimization.js\");\n\n const endDate = new Date();\n const startDate = new Date(endDate.getTime() - days * 24 * 60 * 60 * 1000);\n\n const summary = getCostSummary({\n since: startDate,\n groupBy: \"model\",\n });\n\n const savings = calculateSavings({\n since: startDate,\n });\n\n let text = `Cost Summary (last ${days} days):\\n\\n`;\n text += `Total Cost: $${savings.actualCost.toFixed(2)}\\n`;\n text += `Total Requests: ${Object.values(summary).reduce((sum, s) => sum + s.calls, 0)}\\n`;\n text += `Avg Cost/Request: $${(savings.actualCost / (Object.values(summary).reduce((sum, s) => sum + s.calls, 0) || 1)).toFixed(4)}\\n\\n`;\n text += `By Model:\\n`;\n Object.entries(summary).forEach(([model, stats]) => {\n text += `- ${model}: $${stats.totalCost.toFixed(2)} (${stats.calls} calls)\\n`;\n });\n text += `\\nSavings vs Always-Opus:\\n`;\n text += `- Actual: $${savings.actualCost.toFixed(2)}\\n`;\n text += `- Opus-only: $${savings.opusCost.toFixed(2)}\\n`;\n text += `- Saved: $${savings.savings.toFixed(2)} (${savings.savingsPercent.toFixed(1)}%)\\n`;\n\n return { content: [{ type: \"text\" as const, text }] };\n }\n);\n\n// ─── Start ──────────────────────────────────────────────────\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"Whisper Context MCP server running on stdio\");\n}\n\nmain().catch(console.error);\n","import OpenAI from \"openai\";\nimport { createHash } from \"crypto\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport interface CompressedContext {\n context: string;\n originalTokens: number;\n compressedTokens: number;\n reductionPercent: number;\n strategy: string;\n}\n\nexport interface CompressionOptions {\n maxTokens?: number;\n strategy?: \"summarize\" | \"extract\" | \"delta\" | \"adaptive\";\n previousContextHash?: string; // for delta mode\n previousContext?: string; // for delta mode\n targetReduction?: number; // 0-1, e.g. 0.6 = reduce by 60%\n}\n\n// ─── In-memory delta cache ──────────────────────────────────\n\nconst deltaCache = new Map<string, { context: string; hash: string; timestamp: number }>();\nconst DELTA_CACHE_TTL = 600_000; // 10 min\n\nfunction hashContext(text: string): string {\n return createHash(\"sha256\").update(text).digest(\"hex\").slice(0, 16);\n}\n\n// ─── Main Compression Function ──────────────────────────────\n\nexport async function compressContext(\n rawContext: string,\n opts: CompressionOptions = {}\n): Promise<CompressedContext> {\n const {\n maxTokens = 4000,\n strategy = \"adaptive\",\n previousContextHash,\n previousContext,\n targetReduction = 0.5,\n } = opts;\n\n const originalTokens = estimateTokens(rawContext);\n\n // If already under budget, return as-is\n if (originalTokens <= maxTokens) {\n return {\n context: rawContext,\n originalTokens,\n compressedTokens: originalTokens,\n reductionPercent: 0,\n strategy: \"none\",\n };\n }\n\n switch (strategy) {\n case \"delta\":\n return deltaCompress(rawContext, originalTokens, maxTokens, previousContextHash, previousContext);\n case \"summarize\":\n return summarizeCompress(rawContext, originalTokens, maxTokens);\n case \"extract\":\n return extractCompress(rawContext, originalTokens, maxTokens);\n case \"adaptive\":\n default:\n return adaptiveCompress(rawContext, originalTokens, maxTokens, previousContextHash, previousContext);\n }\n}\n\n// ─── Adaptive Strategy ──────────────────────────────────────\n// Picks the best strategy based on context characteristics\n\nasync function adaptiveCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number,\n previousHash?: string,\n previousCtx?: string\n): Promise<CompressedContext> {\n const ratio = originalTokens / maxTokens;\n\n // If we have previous context and it's similar, use delta\n if (previousHash || previousCtx) {\n const delta = await deltaCompress(rawContext, originalTokens, maxTokens, previousHash, previousCtx);\n if (delta.compressedTokens <= maxTokens) return delta;\n }\n\n // Light compression (under 2x budget): extract key info\n if (ratio < 2) {\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Heavy compression (over 2x budget): summarize\n return summarizeCompress(rawContext, originalTokens, maxTokens);\n}\n\n// ─── Delta Compression ──────────────────────────────────────\n// Only sends what changed since the last context\n\nasync function deltaCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number,\n previousHash?: string,\n previousCtx?: string\n): Promise<CompressedContext> {\n const currentHash = hashContext(rawContext);\n\n // Check if identical\n if (previousHash && previousHash === currentHash) {\n return {\n context: \"[No changes since last context]\",\n originalTokens,\n compressedTokens: 8,\n reductionPercent: 99,\n strategy: \"delta-identical\",\n };\n }\n\n // Get previous context from cache or parameter\n let prevCtx = previousCtx;\n if (!prevCtx && previousHash) {\n const cached = deltaCache.get(previousHash);\n if (cached && Date.now() - cached.timestamp < DELTA_CACHE_TTL) {\n prevCtx = cached.context;\n }\n }\n\n if (!prevCtx) {\n // No previous context to diff against, fall back to extract\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Split into blocks and find differences\n const prevBlocks = new Set(prevCtx.split(\"\\n---\\n\").map((b) => b.trim()));\n const currentBlocks = rawContext.split(\"\\n---\\n\").map((b) => b.trim());\n\n const newBlocks: string[] = [];\n const unchangedCount = { count: 0 };\n\n for (const block of currentBlocks) {\n if (prevBlocks.has(block)) {\n unchangedCount.count++;\n } else {\n newBlocks.push(block);\n }\n }\n\n let deltaContext: string;\n if (newBlocks.length === 0) {\n deltaContext = \"[No new information since last query]\";\n } else {\n const header = `[${unchangedCount.count} unchanged results omitted, ${newBlocks.length} new/updated]\\n\\n`;\n deltaContext = header + newBlocks.join(\"\\n---\\n\");\n }\n\n // Trim if still over budget\n const deltaTokens = estimateTokens(deltaContext);\n if (deltaTokens > maxTokens) {\n const truncated = truncateToTokens(deltaContext, maxTokens);\n deltaCache.set(currentHash, { context: rawContext, hash: currentHash, timestamp: Date.now() });\n\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"delta-truncated\",\n };\n }\n\n // Cache current context for next delta\n deltaCache.set(currentHash, { context: rawContext, hash: currentHash, timestamp: Date.now() });\n\n return {\n context: deltaContext,\n originalTokens,\n compressedTokens: estimateTokens(deltaContext),\n reductionPercent: Math.round((1 - estimateTokens(deltaContext) / originalTokens) * 100),\n strategy: \"delta\",\n };\n}\n\n// ─── Extract Compression ────────────────────────────────────\n// LLM extracts only the most relevant parts\n\nasync function extractCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number\n): Promise<CompressedContext> {\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n {\n role: \"system\",\n content: `You are a context compressor. Extract and preserve ONLY the most important information from the provided context. Remove redundancy, boilerplate, and low-value content. Keep code snippets, key facts, API signatures, and important relationships. Output should be ${maxTokens} tokens or less. Do NOT add commentary — just output the compressed context.`,\n },\n { role: \"user\", content: rawContext },\n ],\n max_tokens: maxTokens,\n temperature: 0,\n });\n\n const compressed = res.choices[0]?.message?.content?.trim() || rawContext;\n const compressedTokens = estimateTokens(compressed);\n\n return {\n context: compressed,\n originalTokens,\n compressedTokens,\n reductionPercent: Math.round((1 - compressedTokens / originalTokens) * 100),\n strategy: \"extract\",\n };\n } catch {\n // Fallback to truncation\n const truncated = truncateToTokens(rawContext, maxTokens);\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"truncate-fallback\",\n };\n }\n}\n\n// ─── Summarize Compression ──────────────────────────────────\n// For heavy compression — summarizes each block then combines\n\nasync function summarizeCompress(\n rawContext: string,\n originalTokens: number,\n maxTokens: number\n): Promise<CompressedContext> {\n const blocks = rawContext.split(\"\\n---\\n\").filter((b) => b.trim());\n\n // If few blocks, summarize the whole thing\n if (blocks.length <= 3) {\n return extractCompress(rawContext, originalTokens, maxTokens);\n }\n\n // Summarize each block individually, then combine\n const budgetPerBlock = Math.floor(maxTokens / blocks.length);\n\n try {\n const summaries = await Promise.all(\n blocks.map(async (block) => {\n if (estimateTokens(block) <= budgetPerBlock) return block;\n\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n {\n role: \"system\",\n content: `Summarize this context block in ${budgetPerBlock} tokens or less. Preserve code signatures, key facts, and important details. Output only the summary.`,\n },\n { role: \"user\", content: block },\n ],\n max_tokens: budgetPerBlock,\n temperature: 0,\n });\n\n return res.choices[0]?.message?.content?.trim() || block.slice(0, budgetPerBlock * 4);\n })\n );\n\n const compressed = summaries.join(\"\\n\\n---\\n\\n\");\n let compressedTokens = estimateTokens(compressed);\n\n // Final trim if still over\n let finalContext = compressed;\n if (compressedTokens > maxTokens) {\n finalContext = truncateToTokens(compressed, maxTokens);\n compressedTokens = estimateTokens(finalContext);\n }\n\n return {\n context: finalContext,\n originalTokens,\n compressedTokens,\n reductionPercent: Math.round((1 - compressedTokens / originalTokens) * 100),\n strategy: \"summarize\",\n };\n } catch {\n const truncated = truncateToTokens(rawContext, maxTokens);\n return {\n context: truncated,\n originalTokens,\n compressedTokens: estimateTokens(truncated),\n reductionPercent: Math.round((1 - estimateTokens(truncated) / originalTokens) * 100),\n strategy: \"truncate-fallback\",\n };\n }\n}\n\n// ─── Pre-computed Chunk Summaries ────────────────────────────\n// Summarize chunks at ingest time so retrieval is cheaper\n\nexport async function summarizeChunk(content: string, chunkType: string): Promise<string> {\n // Only summarize large chunks\n if (estimateTokens(content) < 200) return content;\n\n try {\n const prompt = chunkType === \"code\"\n ? \"Summarize this code in 2-3 sentences. Include: function/class names, what it does, parameters, return type.\"\n : \"Summarize this text in 2-3 sentences. Preserve key facts, names, and important details.\";\n\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [\n { role: \"system\", content: prompt },\n { role: \"user\", content: content.slice(0, 3000) },\n ],\n max_tokens: 150,\n temperature: 0,\n });\n\n return res.choices[0]?.message?.content?.trim() || content;\n } catch {\n return content;\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction truncateToTokens(text: string, maxTokens: number): string {\n const maxChars = maxTokens * 4;\n if (text.length <= maxChars) return text;\n return text.slice(0, maxChars) + \"\\n\\n[...truncated]\";\n}\n\n// Cleanup stale delta cache entries periodically\nsetInterval(() => {\n const now = Date.now();\n for (const [key, val] of deltaCache) {\n if (now - val.timestamp > DELTA_CACHE_TTL) deltaCache.delete(key);\n }\n}, 60_000);\n","import { prisma } from \"../db/index.js\";\nimport { embedSingle } from \"./embeddings.js\";\nimport { compressContext, type CompressionOptions } from \"./compressor.js\";\nimport { createHash } from \"crypto\";\nimport OpenAI from \"openai\";\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n\n// ─── Types ───────────────────────────────────────────────────\n\nexport interface RetrievalResult {\n id: string;\n content: string;\n score: number;\n metadata: Record<string, any>;\n documentTitle?: string;\n sourceName?: string;\n chunkType: string;\n source: \"vector\" | \"bm25\" | \"hybrid\" | \"memory\" | \"graph\";\n}\n\nexport interface QueryOptions {\n projectId: string;\n query: string;\n topK?: number;\n threshold?: number;\n chunkTypes?: string[];\n sourceIds?: string[];\n // Hybrid search\n hybridSearch?: boolean;\n vectorWeight?: number; // 0-1, default 0.7\n bm25Weight?: number; // 0-1, default 0.3\n // Reranking\n rerank?: boolean;\n rerankTopK?: number;\n // Memory inclusion\n includeMemories?: boolean;\n userId?: string;\n sessionId?: string;\n agentId?: string;\n // Graph\n includeGraph?: boolean;\n graphDepth?: number;\n // Context packing\n maxTokens?: number;\n // Compression\n compress?: boolean;\n compressionStrategy?: \"summarize\" | \"extract\" | \"delta\" | \"adaptive\";\n previousContextHash?: string;\n // Caching\n useCache?: boolean;\n cacheTtlSeconds?: number;\n}\n\nexport interface ContextResponse {\n results: RetrievalResult[];\n context: string; // packed context string ready for LLM\n meta: {\n totalResults: number;\n latencyMs: number;\n cacheHit: boolean;\n tokensUsed: number;\n contextHash?: string;\n compression?: {\n originalTokens: number;\n compressedTokens: number;\n reductionPercent: number;\n strategy: string;\n };\n };\n}\n\n// ─── Main Query Function ─────────────────────────────────────\n\nexport async function retrieve(opts: QueryOptions): Promise<ContextResponse> {\n const {\n projectId,\n query,\n topK = 10,\n threshold = 0.3,\n chunkTypes,\n hybridSearch = true,\n vectorWeight = 0.7,\n bm25Weight = 0.3,\n rerank = true,\n rerankTopK,\n includeMemories = false,\n userId,\n sessionId,\n agentId,\n includeGraph = false,\n graphDepth = 1,\n maxTokens,\n compress = false,\n compressionStrategy = \"adaptive\",\n previousContextHash,\n useCache = true,\n cacheTtlSeconds = 300,\n } = opts;\n\n const startTime = Date.now();\n\n // ─── Check Cache ─────────────────────────────────────────\n if (useCache) {\n const cached = await checkCache(projectId, query);\n if (cached) {\n const cachedResults = cached as unknown as RetrievalResult[];\n return {\n results: cachedResults,\n context: packContext(cachedResults, maxTokens),\n meta: {\n totalResults: cachedResults.length,\n latencyMs: Date.now() - startTime,\n cacheHit: true,\n tokensUsed: 0,\n },\n };\n }\n }\n\n // ─── Embed Query ─────────────────────────────────────────\n const queryEmbedding = await embedSingle(query);\n\n let allResults: RetrievalResult[] = [];\n\n // ─── Vector Search ───────────────────────────────────────\n const vectorResults = await vectorSearch(projectId, queryEmbedding, topK * 2, chunkTypes);\n allResults.push(...vectorResults);\n\n // ─── BM25 Full-Text Search ───────────────────────────────\n if (hybridSearch) {\n const bm25Results = await fullTextSearch(projectId, query, topK * 2, chunkTypes);\n allResults.push(...bm25Results);\n }\n\n // ─── Memory Search ───────────────────────────────────────\n if (includeMemories) {\n const memoryResults = await memorySearch(projectId, queryEmbedding, {\n userId,\n sessionId,\n agentId,\n topK: Math.ceil(topK / 3),\n });\n allResults.push(...memoryResults);\n }\n\n // ─── Graph Traversal ─────────────────────────────────────\n if (includeGraph) {\n const graphResults = await graphSearch(projectId, queryEmbedding, {\n depth: graphDepth,\n topK: Math.ceil(topK / 3),\n });\n allResults.push(...graphResults);\n }\n\n // ─── Deduplicate ─────────────────────────────────────────\n allResults = deduplicateResults(allResults);\n\n // ─── Reciprocal Rank Fusion (for hybrid) ─────────────────\n if (hybridSearch) {\n allResults = reciprocalRankFusion(allResults, vectorWeight, bm25Weight);\n }\n\n // ─── Filter by threshold ─────────────────────────────────\n allResults = allResults.filter((r) => r.score >= threshold);\n\n // ─── Rerank with LLM ────────────────────────────────────\n if (rerank && allResults.length > 0) {\n const reranked = await rerankResults(query, allResults, rerankTopK || topK);\n allResults = reranked;\n }\n\n // ─── Limit to topK ──────────────────────────────────────\n allResults = allResults.slice(0, topK);\n\n // ─── Enrich with document/source metadata ────────────────\n allResults = await enrichResults(allResults);\n\n // ─── Context packing ─────────────────────────────────────\n let context = packContext(allResults, maxTokens);\n const contextHash = createHash(\"sha256\").update(context).digest(\"hex\").slice(0, 16);\n\n // ─── Compression ──────────────────────────────────────────\n let compressionMeta: ContextResponse[\"meta\"][\"compression\"];\n if (compress && context.length > 0) {\n const compressed = await compressContext(context, {\n maxTokens: maxTokens || 4000,\n strategy: compressionStrategy,\n previousContextHash,\n });\n context = compressed.context;\n compressionMeta = {\n originalTokens: compressed.originalTokens,\n compressedTokens: compressed.compressedTokens,\n reductionPercent: compressed.reductionPercent,\n strategy: compressed.strategy,\n };\n }\n\n // ─── Cache results ───────────────────────────────────────\n if (useCache && allResults.length > 0) {\n await setCache(projectId, query, allResults, cacheTtlSeconds);\n }\n\n const latencyMs = Date.now() - startTime;\n\n return {\n results: allResults,\n context,\n meta: {\n totalResults: allResults.length,\n latencyMs,\n cacheHit: false,\n tokensUsed: estimateTokens(context),\n contextHash,\n compression: compressionMeta,\n },\n };\n}\n\n// ─── Vector Search ───────────────────────────────────────────\n\nasync function vectorSearch(\n projectId: string,\n queryEmbedding: number[],\n limit: number,\n chunkTypes?: string[]\n): Promise<RetrievalResult[]> {\n let whereClause = `\"projectId\" = '${projectId}'`;\n if (chunkTypes && chunkTypes.length > 0) {\n whereClause += ` AND \"chunkType\" IN (${chunkTypes.map(t => `'${t}'`).join(',')})`;\n }\n\n const results = await prisma.$queryRawUnsafe(`\n SELECT\n id, content, \"chunkType\", metadata,\n 1 - (embedding <=> '${JSON.stringify(queryEmbedding)}'::vector) as similarity\n FROM chunks\n WHERE ${whereClause}\n ORDER BY embedding <=> '${JSON.stringify(queryEmbedding)}'::vector\n LIMIT ${limit}\n `);\n\n return (results as any[]).map((r) => ({\n id: r.id,\n content: r.content,\n score: r.similarity,\n metadata: r.metadata || {},\n chunkType: r.chunkType,\n source: \"vector\" as const,\n }));\n}\n\n// ─── Full-Text Search (BM25-style via pg tsvector) ───────────\n\nasync function fullTextSearch(\n projectId: string,\n query: string,\n limit: number,\n chunkTypes?: string[]\n): Promise<RetrievalResult[]> {\n // Sanitize query for tsquery\n const tsQuery = query\n .replace(/[^\\w\\s]/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter((w) => w.length > 1)\n .join(\" & \");\n\n if (!tsQuery) return [];\n\n let whereClause = `\"projectId\" = '${projectId}'`;\n if (chunkTypes && chunkTypes.length > 0) {\n whereClause += ` AND \"chunkType\" IN (${chunkTypes.map(t => `'${t}'`).join(',')})`;\n }\n\n const results = await prisma.$queryRawUnsafe(`\n SELECT\n id, content, \"chunkType\", metadata,\n ts_rank(to_tsvector('english', coalesce(\"searchContent\", content)), to_tsquery('english', '${tsQuery}')) as rank\n FROM chunks\n WHERE ${whereClause}\n AND to_tsvector('english', coalesce(\"searchContent\", content)) @@ to_tsquery('english', '${tsQuery}')\n ORDER BY rank DESC\n LIMIT ${limit}\n `);\n\n // Normalize ranks to 0-1\n const maxRank = (results as any[]).length > 0 ? Math.max(...(results as any[]).map((r) => r.rank)) : 1;\n\n return (results as any[]).map((r) => ({\n id: r.id,\n content: r.content,\n score: maxRank > 0 ? r.rank / maxRank : 0,\n metadata: r.metadata || {},\n chunkType: r.chunkType,\n source: \"bm25\" as const,\n }));\n}\n\n// ─── Memory Search ───────────────────────────────────────────\n\nasync function memorySearch(\n projectId: string,\n queryEmbedding: number[],\n opts: { userId?: string; sessionId?: string; agentId?: string; topK: number }\n): Promise<RetrievalResult[]> {\n let whereClause = `\n project_id = '${projectId}' \n AND is_active = true \n AND (expires_at IS NULL OR expires_at > NOW())\n `;\n\n if (opts.userId) whereClause += ` AND user_id = '${opts.userId}'`;\n if (opts.sessionId) whereClause += ` AND session_id = '${opts.sessionId}'`;\n if (opts.agentId) whereClause += ` AND agent_id = '${opts.agentId}'`;\n\n const results = await prisma.$queryRawUnsafe(`\n SELECT \n id, content, memory_type as \"memoryType\", metadata, importance,\n 1 - (embedding <=> '${JSON.stringify(queryEmbedding)}'::vector) as similarity\n FROM memories\n WHERE ${whereClause}\n ORDER BY embedding <=> '${JSON.stringify(queryEmbedding)}'::vector\n LIMIT ${opts.topK}\n `);\n\n // Update access counts\n const ids = (results as any[]).map((r) => r.id);\n if (ids.length > 0) {\n await prisma.memory.updateMany({\n where: { id: { in: ids } },\n data: {\n accessCount: { increment: 1 },\n lastAccessedAt: new Date(),\n },\n });\n }\n\n return (results as any[]).map((r) => ({\n id: r.id,\n content: r.content,\n score: r.similarity * (r.importance || 0.5),\n metadata: { ...(r.metadata || {}), memoryType: r.memoryType },\n chunkType: \"memory\" as any,\n source: \"memory\" as const,\n }));\n}\n\n// ─── Graph Search ────────────────────────────────────────────\n\nasync function graphSearch(\n projectId: string,\n queryEmbedding: number[],\n opts: { depth: number; topK: number }\n): Promise<RetrievalResult[]> {\n // Find most relevant entities using vector search\n const relevantEntities = await prisma.$queryRawUnsafe(`\n SELECT \n id, name, entity_type as \"entityType\", description, metadata, source_chunk_id as \"sourceChunkId\",\n 1 - (embedding <=> '${JSON.stringify(queryEmbedding)}'::vector) as similarity\n FROM entities\n WHERE project_id = '${projectId}'\n ORDER BY embedding <=> '${JSON.stringify(queryEmbedding)}'::vector\n LIMIT 5\n `);\n\n if ((relevantEntities as any[]).length === 0) return [];\n\n // Traverse relationships\n const entityIds = (relevantEntities as any[]).map((e) => e.id);\n const entityIdsStr = entityIds.map(id => `'${id}'`).join(',');\n\n const relatedEntities = await prisma.$queryRawUnsafe(`\n SELECT \n e.id, e.name, e.entity_type as \"entityType\", e.description, e.metadata, e.source_chunk_id as \"sourceChunkId\",\n er.relation_type as \"relationType\", er.weight\n FROM entity_relations er\n INNER JOIN entities e ON er.to_entity_id = e.id\n WHERE er.project_id = '${projectId}'\n AND er.from_entity_id IN (${entityIdsStr})\n LIMIT ${opts.topK}\n `);\n\n // Get chunks for related entities\n const chunkIds = [\n ...(relevantEntities as any[]).map((e) => e.sourceChunkId).filter(Boolean),\n ...(relatedEntities as any[]).map((e) => e.sourceChunkId).filter(Boolean),\n ] as string[];\n\n if (chunkIds.length === 0) return [];\n\n const relatedChunks = await prisma.chunk.findMany({\n where: { id: { in: chunkIds } },\n });\n\n return relatedChunks.map((c) => {\n const entity = (relevantEntities as any[]).find((e) => e.sourceChunkId === c.id);\n return {\n id: c.id,\n content: c.content,\n score: entity ? entity.similarity * 0.8 : 0.5,\n metadata: {\n ...(c.metadata as any),\n entityName: entity?.name,\n entityType: entity?.entityType,\n },\n chunkType: c.chunkType || \"text\",\n source: \"graph\" as const,\n };\n });\n}\n\n// ─── Reciprocal Rank Fusion ──────────────────────────────────\n\nfunction reciprocalRankFusion(\n results: RetrievalResult[],\n vectorWeight: number,\n bm25Weight: number,\n k = 60\n): RetrievalResult[] {\n const scoreMap = new Map<string, { result: RetrievalResult; score: number }>();\n\n // Group by source type and rank\n const vectorResults = results.filter((r) => r.source === \"vector\");\n const bm25Results = results.filter((r) => r.source === \"bm25\");\n const otherResults = results.filter((r) => r.source !== \"vector\" && r.source !== \"bm25\");\n\n // RRF scoring for vector results\n vectorResults.forEach((r, rank) => {\n const existing = scoreMap.get(r.id);\n const rrfScore = vectorWeight / (k + rank + 1);\n if (existing) {\n existing.score += rrfScore;\n } else {\n scoreMap.set(r.id, { result: r, score: rrfScore });\n }\n });\n\n // RRF scoring for BM25 results\n bm25Results.forEach((r, rank) => {\n const existing = scoreMap.get(r.id);\n const rrfScore = bm25Weight / (k + rank + 1);\n if (existing) {\n existing.score += rrfScore;\n existing.result.source = \"hybrid\";\n } else {\n scoreMap.set(r.id, { result: { ...r, source: \"hybrid\" }, score: rrfScore });\n }\n });\n\n // Add other results with their original scores\n otherResults.forEach((r) => {\n if (!scoreMap.has(r.id)) {\n scoreMap.set(r.id, { result: r, score: r.score * 0.5 });\n }\n });\n\n return Array.from(scoreMap.values())\n .sort((a, b) => b.score - a.score)\n .map((entry) => ({ ...entry.result, score: entry.score }));\n}\n\n// ─── LLM Reranking ───────────────────────────────────────────\n\nasync function rerankResults(\n query: string,\n results: RetrievalResult[],\n topK: number\n): Promise<RetrievalResult[]> {\n if (results.length <= 3) return results; // not worth reranking\n\n // Take top candidates for reranking (limit to save tokens)\n const candidates = results.slice(0, Math.min(results.length, topK * 3));\n\n const prompt = `Given the query: \"${query}\"\n\nRank these ${candidates.length} text passages by relevance (most relevant first). Return ONLY a JSON array of indices (0-based), e.g. [2, 0, 4, 1, 3].\n\n${candidates.map((r, i) => `[${i}] ${r.content.slice(0, 300)}`).join(\"\\n\\n\")}`;\n\n try {\n const res = await openai.chat.completions.create({\n model: \"gpt-4.1-nano\",\n messages: [{ role: \"user\", content: prompt }],\n temperature: 0,\n max_tokens: 200,\n });\n\n const text = res.choices[0]?.message?.content?.trim() || \"\";\n const match = text.match(/\\[[\\d,\\s]+\\]/);\n if (!match) return results;\n\n const indices: number[] = JSON.parse(match[0]);\n const reranked: RetrievalResult[] = [];\n\n for (const idx of indices) {\n if (idx >= 0 && idx < candidates.length) {\n reranked.push({\n ...candidates[idx],\n score: 1 - reranked.length * (1 / indices.length), // normalize\n });\n }\n }\n\n // Add any results that weren't reranked\n for (const r of results) {\n if (!reranked.find((rr) => rr.id === r.id)) {\n reranked.push(r);\n }\n }\n\n return reranked.slice(0, topK);\n } catch {\n // Fallback to original ordering if reranking fails\n return results.slice(0, topK);\n }\n}\n\n// ─── Deduplication ───────────────────────────────────────────\n\nfunction deduplicateResults(results: RetrievalResult[]): RetrievalResult[] {\n const seen = new Map<string, RetrievalResult>();\n\n for (const r of results) {\n const existing = seen.get(r.id);\n if (!existing || r.score > existing.score) {\n seen.set(r.id, r);\n }\n }\n\n return Array.from(seen.values());\n}\n\n// ─── Context Packing ─────────────────────────────────────────\n\nfunction packContext(results: RetrievalResult[], maxTokens?: number): string {\n if (results.length === 0) return \"\";\n\n const limit = maxTokens || 8000;\n let totalTokens = 0;\n const packed: string[] = [];\n\n for (const r of results) {\n const header = buildChunkHeader(r);\n const block = `${header}\\n${r.content}\\n`;\n const tokens = estimateTokens(block);\n\n if (totalTokens + tokens > limit) break;\n\n packed.push(block);\n totalTokens += tokens;\n }\n\n return packed.join(\"\\n---\\n\\n\");\n}\n\nfunction buildChunkHeader(r: RetrievalResult): string {\n const parts: string[] = [];\n\n if (r.sourceName) parts.push(`Source: ${r.sourceName}`);\n if (r.documentTitle) parts.push(`Document: ${r.documentTitle}`);\n if (r.metadata?.filePath) parts.push(`File: ${r.metadata.filePath}`);\n if (r.metadata?.startLine) parts.push(`Lines: ${r.metadata.startLine}-${r.metadata.endLine || \"?\"}`);\n if (r.chunkType && r.chunkType !== \"text\") parts.push(`Type: ${r.chunkType}`);\n\n return parts.length > 0 ? `[${parts.join(\" | \")}]` : \"\";\n}\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n// ─── Enrich Results ──────────────────────────────────────────\n\nasync function enrichResults(results: RetrievalResult[]): Promise<RetrievalResult[]> {\n // Get unique document IDs from chunk results\n const chunkResults = results.filter((r) => r.source !== \"memory\");\n if (chunkResults.length === 0) return results;\n\n // We need document IDs — stored in metadata or we need to query\n const chunkIds = chunkResults.map((r) => r.id);\n\n const chunkDocs = await prisma.$queryRawUnsafe(`\n SELECT\n c.id as \"chunkId\", d.title as \"docTitle\", s.name as \"sourceName\"\n FROM chunks c\n INNER JOIN documents d ON c.\"documentId\" = d.id\n INNER JOIN sources s ON d.\"sourceId\" = s.id\n WHERE c.id IN (${chunkIds.map(id => `'${id}'`).join(',')})\n `);\n\n const enrichMap = new Map((chunkDocs as any[]).map((d) => [d.chunkId, d]));\n\n return results.map((r) => {\n const enrichment = enrichMap.get(r.id);\n if (enrichment) {\n return {\n ...r,\n documentTitle: enrichment.docTitle || undefined,\n sourceName: enrichment.sourceName || undefined,\n };\n }\n return r;\n });\n}\n\n// ─── Cache ───────────────────────────────────────────────────\n\nfunction hashQuery(query: string): string {\n return createHash(\"sha256\").update(query.toLowerCase().trim()).digest(\"hex\");\n}\n\nasync function checkCache(projectId: string, query: string) {\n const hash = hashQuery(query);\n\n const cached = await prisma.queryCache.findFirst({\n where: {\n projectId,\n queryHash: hash,\n expiresAt: { gt: new Date() },\n },\n });\n\n if (cached) {\n await prisma.queryCache.update({\n where: { id: cached.id },\n data: { hitCount: { increment: 1 } },\n });\n\n return cached.results;\n }\n\n return null;\n}\n\nasync function setCache(\n projectId: string,\n query: string,\n results: RetrievalResult[],\n ttlSeconds: number\n) {\n const hash = hashQuery(query);\n const expiresAt = new Date(Date.now() + ttlSeconds * 1000);\n\n await prisma.queryCache.upsert({\n where: {\n projectId_queryHash: {\n projectId,\n queryHash: hash,\n },\n },\n update: {\n results: results as any,\n expiresAt,\n hitCount: 0,\n },\n create: {\n projectId,\n queryHash: hash,\n query,\n results: results as any,\n expiresAt,\n },\n });\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;;;ACFlB,OAAO,YAAY;AACnB,SAAS,kBAAkB;AAE3B,IAAM,SAAS,IAAI,OAAO,EAAE,QAAQ,QAAQ,IAAI,eAAe,CAAC;AAsBhE,IAAM,aAAa,oBAAI,IAAkE;AACzF,IAAM,kBAAkB;AAExB,SAAS,YAAY,MAAsB;AACzC,SAAO,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACpE;AAIA,eAAsB,gBACpB,YACA,OAA2B,CAAC,GACA;AAC5B,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,EACpB,IAAI;AAEJ,QAAM,iBAAiB,eAAe,UAAU;AAGhD,MAAI,kBAAkB,WAAW;AAC/B,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,kBAAkB;AAAA,MAClB,kBAAkB;AAAA,MAClB,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,cAAc,YAAY,gBAAgB,WAAW,qBAAqB,eAAe;AAAA,IAClG,KAAK;AACH,aAAO,kBAAkB,YAAY,gBAAgB,SAAS;AAAA,IAChE,KAAK;AACH,aAAO,gBAAgB,YAAY,gBAAgB,SAAS;AAAA,IAC9D,KAAK;AAAA,IACL;AACE,aAAO,iBAAiB,YAAY,gBAAgB,WAAW,qBAAqB,eAAe;AAAA,EACvG;AACF;AAKA,eAAe,iBACb,YACA,gBACA,WACA,cACA,aAC4B;AAC5B,QAAM,QAAQ,iBAAiB;AAG/B,MAAI,gBAAgB,aAAa;AAC/B,UAAM,QAAQ,MAAM,cAAc,YAAY,gBAAgB,WAAW,cAAc,WAAW;AAClG,QAAI,MAAM,oBAAoB,UAAW,QAAO;AAAA,EAClD;AAGA,MAAI,QAAQ,GAAG;AACb,WAAO,gBAAgB,YAAY,gBAAgB,SAAS;AAAA,EAC9D;AAGA,SAAO,kBAAkB,YAAY,gBAAgB,SAAS;AAChE;AAKA,eAAe,cACb,YACA,gBACA,WACA,cACA,aAC4B;AAC5B,QAAM,cAAc,YAAY,UAAU;AAG1C,MAAI,gBAAgB,iBAAiB,aAAa;AAChD,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,kBAAkB;AAAA,MAClB,kBAAkB;AAAA,MAClB,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,UAAU;AACd,MAAI,CAAC,WAAW,cAAc;AAC5B,UAAM,SAAS,WAAW,IAAI,YAAY;AAC1C,QAAI,UAAU,KAAK,IAAI,IAAI,OAAO,YAAY,iBAAiB;AAC7D,gBAAU,OAAO;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,CAAC,SAAS;AAEZ,WAAO,gBAAgB,YAAY,gBAAgB,SAAS;AAAA,EAC9D;AAGA,QAAM,aAAa,IAAI,IAAI,QAAQ,MAAM,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACxE,QAAM,gBAAgB,WAAW,MAAM,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAErE,QAAM,YAAsB,CAAC;AAC7B,QAAM,iBAAiB,EAAE,OAAO,EAAE;AAElC,aAAW,SAAS,eAAe;AACjC,QAAI,WAAW,IAAI,KAAK,GAAG;AACzB,qBAAe;AAAA,IACjB,OAAO;AACL,gBAAU,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,UAAU,WAAW,GAAG;AAC1B,mBAAe;AAAA,EACjB,OAAO;AACL,UAAM,SAAS,IAAI,eAAe,KAAK,+BAA+B,UAAU,MAAM;AAAA;AAAA;AACtF,mBAAe,SAAS,UAAU,KAAK,SAAS;AAAA,EAClD;AAGA,QAAM,cAAc,eAAe,YAAY;AAC/C,MAAI,cAAc,WAAW;AAC3B,UAAM,YAAY,iBAAiB,cAAc,SAAS;AAC1D,eAAW,IAAI,aAAa,EAAE,SAAS,YAAY,MAAM,aAAa,WAAW,KAAK,IAAI,EAAE,CAAC;AAE7F,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,kBAAkB,eAAe,SAAS;AAAA,MAC1C,kBAAkB,KAAK,OAAO,IAAI,eAAe,SAAS,IAAI,kBAAkB,GAAG;AAAA,MACnF,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,aAAW,IAAI,aAAa,EAAE,SAAS,YAAY,MAAM,aAAa,WAAW,KAAK,IAAI,EAAE,CAAC;AAE7F,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,kBAAkB,eAAe,YAAY;AAAA,IAC7C,kBAAkB,KAAK,OAAO,IAAI,eAAe,YAAY,IAAI,kBAAkB,GAAG;AAAA,IACtF,UAAU;AAAA,EACZ;AACF;AAKA,eAAe,gBACb,YACA,gBACA,WAC4B;AAC5B,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,KAAK,YAAY,OAAO;AAAA,MAC/C,OAAO;AAAA,MACP,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,SAAS,yQAAyQ,SAAS;AAAA,QAC7R;AAAA,QACA,EAAE,MAAM,QAAQ,SAAS,WAAW;AAAA,MACtC;AAAA,MACA,YAAY;AAAA,MACZ,aAAa;AAAA,IACf,CAAC;AAED,UAAM,aAAa,IAAI,QAAQ,CAAC,GAAG,SAAS,SAAS,KAAK,KAAK;AAC/D,UAAM,mBAAmB,eAAe,UAAU;AAElD,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,kBAAkB,KAAK,OAAO,IAAI,mBAAmB,kBAAkB,GAAG;AAAA,MAC1E,UAAU;AAAA,IACZ;AAAA,EACF,QAAQ;AAEN,UAAM,YAAY,iBAAiB,YAAY,SAAS;AACxD,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,kBAAkB,eAAe,SAAS;AAAA,MAC1C,kBAAkB,KAAK,OAAO,IAAI,eAAe,SAAS,IAAI,kBAAkB,GAAG;AAAA,MACnF,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAKA,eAAe,kBACb,YACA,gBACA,WAC4B;AAC5B,QAAM,SAAS,WAAW,MAAM,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;AAGjE,MAAI,OAAO,UAAU,GAAG;AACtB,WAAO,gBAAgB,YAAY,gBAAgB,SAAS;AAAA,EAC9D;AAGA,QAAM,iBAAiB,KAAK,MAAM,YAAY,OAAO,MAAM;AAE3D,MAAI;AACF,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,IAAI,OAAO,UAAU;AAC1B,YAAI,eAAe,KAAK,KAAK,eAAgB,QAAO;AAEpD,cAAM,MAAM,MAAM,OAAO,KAAK,YAAY,OAAO;AAAA,UAC/C,OAAO;AAAA,UACP,UAAU;AAAA,YACR;AAAA,cACE,MAAM;AAAA,cACN,SAAS,mCAAmC,cAAc;AAAA,YAC5D;AAAA,YACA,EAAE,MAAM,QAAQ,SAAS,MAAM;AAAA,UACjC;AAAA,UACA,YAAY;AAAA,UACZ,aAAa;AAAA,QACf,CAAC;AAED,eAAO,IAAI,QAAQ,CAAC,GAAG,SAAS,SAAS,KAAK,KAAK,MAAM,MAAM,GAAG,iBAAiB,CAAC;AAAA,MACtF,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,UAAU,KAAK,aAAa;AAC/C,QAAI,mBAAmB,eAAe,UAAU;AAGhD,QAAI,eAAe;AACnB,QAAI,mBAAmB,WAAW;AAChC,qBAAe,iBAAiB,YAAY,SAAS;AACrD,yBAAmB,eAAe,YAAY;AAAA,IAChD;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,kBAAkB,KAAK,OAAO,IAAI,mBAAmB,kBAAkB,GAAG;AAAA,MAC1E,UAAU;AAAA,IACZ;AAAA,EACF,QAAQ;AACN,UAAM,YAAY,iBAAiB,YAAY,SAAS;AACxD,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,kBAAkB,eAAe,SAAS;AAAA,MAC1C,kBAAkB,KAAK,OAAO,IAAI,eAAe,SAAS,IAAI,kBAAkB,GAAG;AAAA,MACnF,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAgCA,SAAS,eAAe,MAAsB;AAC5C,SAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AAClC;AAEA,SAAS,iBAAiB,MAAc,WAA2B;AACjE,QAAM,WAAW,YAAY;AAC7B,MAAI,KAAK,UAAU,SAAU,QAAO;AACpC,SAAO,KAAK,MAAM,GAAG,QAAQ,IAAI;AACnC;AAGA,YAAY,MAAM;AAChB,QAAM,MAAM,KAAK,IAAI;AACrB,aAAW,CAAC,KAAK,GAAG,KAAK,YAAY;AACnC,QAAI,MAAM,IAAI,YAAY,gBAAiB,YAAW,OAAO,GAAG;AAAA,EAClE;AACF,GAAG,GAAM;;;ACvVT,SAAS,cAAAA,mBAAkB;AAC3B,OAAOC,aAAY;AAEnB,IAAMC,UAAS,IAAID,QAAO,EAAE,QAAQ,QAAQ,IAAI,eAAe,CAAC;AAoEhE,eAAsB,SAAS,MAA8C;AAC3E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,YAAY;AAAA,IACZ;AAAA,IACA,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,SAAS;AAAA,IACT;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,aAAa;AAAA,IACb;AAAA,IACA,WAAW;AAAA,IACX,sBAAsB;AAAA,IACtB;AAAA,IACA,WAAW;AAAA,IACX,kBAAkB;AAAA,EACpB,IAAI;AAEJ,QAAM,YAAY,KAAK,IAAI;AAG3B,MAAI,UAAU;AACZ,UAAM,SAAS,MAAM,WAAW,WAAW,KAAK;AAChD,QAAI,QAAQ;AACV,YAAM,gBAAgB;AACtB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,YAAY,eAAe,SAAS;AAAA,QAC7C,MAAM;AAAA,UACJ,cAAc,cAAc;AAAA,UAC5B,WAAW,KAAK,IAAI,IAAI;AAAA,UACxB,UAAU;AAAA,UACV,YAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAiB,MAAM,YAAY,KAAK;AAE9C,MAAI,aAAgC,CAAC;AAGrC,QAAM,gBAAgB,MAAM,aAAa,WAAW,gBAAgB,OAAO,GAAG,UAAU;AACxF,aAAW,KAAK,GAAG,aAAa;AAGhC,MAAI,cAAc;AAChB,UAAM,cAAc,MAAM,eAAe,WAAW,OAAO,OAAO,GAAG,UAAU;AAC/E,eAAW,KAAK,GAAG,WAAW;AAAA,EAChC;AAGA,MAAI,iBAAiB;AACnB,UAAM,gBAAgB,MAAM,aAAa,WAAW,gBAAgB;AAAA,MAClE;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,KAAK,KAAK,OAAO,CAAC;AAAA,IAC1B,CAAC;AACD,eAAW,KAAK,GAAG,aAAa;AAAA,EAClC;AAGA,MAAI,cAAc;AAChB,UAAM,eAAe,MAAM,YAAY,WAAW,gBAAgB;AAAA,MAChE,OAAO;AAAA,MACP,MAAM,KAAK,KAAK,OAAO,CAAC;AAAA,IAC1B,CAAC;AACD,eAAW,KAAK,GAAG,YAAY;AAAA,EACjC;AAGA,eAAa,mBAAmB,UAAU;AAG1C,MAAI,cAAc;AAChB,iBAAa,qBAAqB,YAAY,cAAc,UAAU;AAAA,EACxE;AAGA,eAAa,WAAW,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS;AAG1D,MAAI,UAAU,WAAW,SAAS,GAAG;AACnC,UAAM,WAAW,MAAM,cAAc,OAAO,YAAY,cAAc,IAAI;AAC1E,iBAAa;AAAA,EACf;AAGA,eAAa,WAAW,MAAM,GAAG,IAAI;AAGrC,eAAa,MAAM,cAAc,UAAU;AAG3C,MAAI,UAAU,YAAY,YAAY,SAAS;AAC/C,QAAM,cAAcD,YAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAGlF,MAAI;AACJ,MAAI,YAAY,QAAQ,SAAS,GAAG;AAClC,UAAM,aAAa,MAAM,gBAAgB,SAAS;AAAA,MAChD,WAAW,aAAa;AAAA,MACxB,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AACD,cAAU,WAAW;AACrB,sBAAkB;AAAA,MAChB,gBAAgB,WAAW;AAAA,MAC3B,kBAAkB,WAAW;AAAA,MAC7B,kBAAkB,WAAW;AAAA,MAC7B,UAAU,WAAW;AAAA,IACvB;AAAA,EACF;AAGA,MAAI,YAAY,WAAW,SAAS,GAAG;AACrC,UAAM,SAAS,WAAW,OAAO,YAAY,eAAe;AAAA,EAC9D;AAEA,QAAM,YAAY,KAAK,IAAI,IAAI;AAE/B,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,MAAM;AAAA,MACJ,cAAc,WAAW;AAAA,MACzB;AAAA,MACA,UAAU;AAAA,MACV,YAAYG,gBAAe,OAAO;AAAA,MAClC;AAAA,MACA,aAAa;AAAA,IACf;AAAA,EACF;AACF;AAIA,eAAe,aACb,WACA,gBACA,OACA,YAC4B;AAC5B,MAAI,cAAc,kBAAkB,SAAS;AAC7C,MAAI,cAAc,WAAW,SAAS,GAAG;AACvC,mBAAe,wBAAwB,WAAW,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,EAChF;AAEA,QAAM,UAAU,MAAM,OAAO,gBAAgB;AAAA;AAAA;AAAA,4BAGnB,KAAK,UAAU,cAAc,CAAC;AAAA;AAAA,YAE9C,WAAW;AAAA,8BACO,KAAK,UAAU,cAAc,CAAC;AAAA,YAChD,KAAK;AAAA,GACd;AAED,SAAQ,QAAkB,IAAI,CAAC,OAAO;AAAA,IACpC,IAAI,EAAE;AAAA,IACN,SAAS,EAAE;AAAA,IACX,OAAO,EAAE;AAAA,IACT,UAAU,EAAE,YAAY,CAAC;AAAA,IACzB,WAAW,EAAE;AAAA,IACb,QAAQ;AAAA,EACV,EAAE;AACJ;AAIA,eAAe,eACb,WACA,OACA,OACA,YAC4B;AAE5B,QAAM,UAAU,MACb,QAAQ,YAAY,GAAG,EACvB,KAAK,EACL,MAAM,KAAK,EACX,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EAC1B,KAAK,KAAK;AAEb,MAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,MAAI,cAAc,kBAAkB,SAAS;AAC7C,MAAI,cAAc,WAAW,SAAS,GAAG;AACvC,mBAAe,wBAAwB,WAAW,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,EAChF;AAEA,QAAM,UAAU,MAAM,OAAO,gBAAgB;AAAA;AAAA;AAAA,mGAGoD,OAAO;AAAA;AAAA,YAE9F,WAAW;AAAA,iGAC0E,OAAO;AAAA;AAAA,YAE5F,KAAK;AAAA,GACd;AAGD,QAAM,UAAW,QAAkB,SAAS,IAAI,KAAK,IAAI,GAAI,QAAkB,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI;AAErG,SAAQ,QAAkB,IAAI,CAAC,OAAO;AAAA,IACpC,IAAI,EAAE;AAAA,IACN,SAAS,EAAE;AAAA,IACX,OAAO,UAAU,IAAI,EAAE,OAAO,UAAU;AAAA,IACxC,UAAU,EAAE,YAAY,CAAC;AAAA,IACzB,WAAW,EAAE;AAAA,IACb,QAAQ;AAAA,EACV,EAAE;AACJ;AAIA,eAAe,aACb,WACA,gBACA,MAC4B;AAC5B,MAAI,cAAc;AAAA,oBACA,SAAS;AAAA;AAAA;AAAA;AAK3B,MAAI,KAAK,OAAQ,gBAAe,mBAAmB,KAAK,MAAM;AAC9D,MAAI,KAAK,UAAW,gBAAe,sBAAsB,KAAK,SAAS;AACvE,MAAI,KAAK,QAAS,gBAAe,oBAAoB,KAAK,OAAO;AAEjE,QAAM,UAAU,MAAM,OAAO,gBAAgB;AAAA;AAAA;AAAA,4BAGnB,KAAK,UAAU,cAAc,CAAC;AAAA;AAAA,YAE9C,WAAW;AAAA,8BACO,KAAK,UAAU,cAAc,CAAC;AAAA,YAChD,KAAK,IAAI;AAAA,GAClB;AAGD,QAAM,MAAO,QAAkB,IAAI,CAAC,MAAM,EAAE,EAAE;AAC9C,MAAI,IAAI,SAAS,GAAG;AAClB,UAAM,OAAO,OAAO,WAAW;AAAA,MAC7B,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE;AAAA,MACzB,MAAM;AAAA,QACJ,aAAa,EAAE,WAAW,EAAE;AAAA,QAC5B,gBAAgB,oBAAI,KAAK;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAQ,QAAkB,IAAI,CAAC,OAAO;AAAA,IACpC,IAAI,EAAE;AAAA,IACN,SAAS,EAAE;AAAA,IACX,OAAO,EAAE,cAAc,EAAE,cAAc;AAAA,IACvC,UAAU,EAAE,GAAI,EAAE,YAAY,CAAC,GAAI,YAAY,EAAE,WAAW;AAAA,IAC5D,WAAW;AAAA,IACX,QAAQ;AAAA,EACV,EAAE;AACJ;AAIA,eAAe,YACb,WACA,gBACA,MAC4B;AAE5B,QAAM,mBAAmB,MAAM,OAAO,gBAAgB;AAAA;AAAA;AAAA,4BAG5B,KAAK,UAAU,cAAc,CAAC;AAAA;AAAA,0BAEhC,SAAS;AAAA,8BACL,KAAK,UAAU,cAAc,CAAC;AAAA;AAAA,GAEzD;AAED,MAAK,iBAA2B,WAAW,EAAG,QAAO,CAAC;AAGtD,QAAM,YAAa,iBAA2B,IAAI,CAAC,MAAM,EAAE,EAAE;AAC7D,QAAM,eAAe,UAAU,IAAI,QAAM,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;AAE5D,QAAM,kBAAkB,MAAM,OAAO,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAM1B,SAAS;AAAA,kCACJ,YAAY;AAAA,YAClC,KAAK,IAAI;AAAA,GAClB;AAGD,QAAM,WAAW;AAAA,IACf,GAAI,iBAA2B,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,OAAO;AAAA,IACzE,GAAI,gBAA0B,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,OAAO;AAAA,EAC1E;AAEA,MAAI,SAAS,WAAW,EAAG,QAAO,CAAC;AAEnC,QAAM,gBAAgB,MAAM,OAAO,MAAM,SAAS;AAAA,IAChD,OAAO,EAAE,IAAI,EAAE,IAAI,SAAS,EAAE;AAAA,EAChC,CAAC;AAED,SAAO,cAAc,IAAI,CAAC,MAAM;AAC9B,UAAM,SAAU,iBAA2B,KAAK,CAAC,MAAM,EAAE,kBAAkB,EAAE,EAAE;AAC/E,WAAO;AAAA,MACL,IAAI,EAAE;AAAA,MACN,SAAS,EAAE;AAAA,MACX,OAAO,SAAS,OAAO,aAAa,MAAM;AAAA,MAC1C,UAAU;AAAA,QACR,GAAI,EAAE;AAAA,QACN,YAAY,QAAQ;AAAA,QACpB,YAAY,QAAQ;AAAA,MACtB;AAAA,MACA,WAAW,EAAE,aAAa;AAAA,MAC1B,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACH;AAIA,SAAS,qBACP,SACA,cACA,YACA,IAAI,IACe;AACnB,QAAM,WAAW,oBAAI,IAAwD;AAG7E,QAAM,gBAAgB,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ;AACjE,QAAM,cAAc,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAC7D,QAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY,EAAE,WAAW,MAAM;AAGvF,gBAAc,QAAQ,CAAC,GAAG,SAAS;AACjC,UAAM,WAAW,SAAS,IAAI,EAAE,EAAE;AAClC,UAAM,WAAW,gBAAgB,IAAI,OAAO;AAC5C,QAAI,UAAU;AACZ,eAAS,SAAS;AAAA,IACpB,OAAO;AACL,eAAS,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,SAAS,CAAC;AAAA,IACnD;AAAA,EACF,CAAC;AAGD,cAAY,QAAQ,CAAC,GAAG,SAAS;AAC/B,UAAM,WAAW,SAAS,IAAI,EAAE,EAAE;AAClC,UAAM,WAAW,cAAc,IAAI,OAAO;AAC1C,QAAI,UAAU;AACZ,eAAS,SAAS;AAClB,eAAS,OAAO,SAAS;AAAA,IAC3B,OAAO;AACL,eAAS,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,GAAG,QAAQ,SAAS,GAAG,OAAO,SAAS,CAAC;AAAA,IAC5E;AAAA,EACF,CAAC;AAGD,eAAa,QAAQ,CAAC,MAAM;AAC1B,QAAI,CAAC,SAAS,IAAI,EAAE,EAAE,GAAG;AACvB,eAAS,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,CAAC;AAAA,IACxD;AAAA,EACF,CAAC;AAED,SAAO,MAAM,KAAK,SAAS,OAAO,CAAC,EAChC,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,IAAI,CAAC,WAAW,EAAE,GAAG,MAAM,QAAQ,OAAO,MAAM,MAAM,EAAE;AAC7D;AAIA,eAAe,cACb,OACA,SACA,MAC4B;AAC5B,MAAI,QAAQ,UAAU,EAAG,QAAO;AAGhC,QAAM,aAAa,QAAQ,MAAM,GAAG,KAAK,IAAI,QAAQ,QAAQ,OAAO,CAAC,CAAC;AAEtE,QAAM,SAAS,qBAAqB,KAAK;AAAA;AAAA,aAE9B,WAAW,MAAM;AAAA;AAAA,EAE5B,WAAW,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,QAAQ,MAAM,GAAG,GAAG,CAAC,EAAE,EAAE,KAAK,MAAM,CAAC;AAE1E,MAAI;AACF,UAAM,MAAM,MAAMD,QAAO,KAAK,YAAY,OAAO;AAAA,MAC/C,OAAO;AAAA,MACP,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,MAC5C,aAAa;AAAA,MACb,YAAY;AAAA,IACd,CAAC;AAED,UAAM,OAAO,IAAI,QAAQ,CAAC,GAAG,SAAS,SAAS,KAAK,KAAK;AACzD,UAAM,QAAQ,KAAK,MAAM,cAAc;AACvC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,UAAoB,KAAK,MAAM,MAAM,CAAC,CAAC;AAC7C,UAAM,WAA8B,CAAC;AAErC,eAAW,OAAO,SAAS;AACzB,UAAI,OAAO,KAAK,MAAM,WAAW,QAAQ;AACvC,iBAAS,KAAK;AAAA,UACZ,GAAG,WAAW,GAAG;AAAA,UACjB,OAAO,IAAI,SAAS,UAAU,IAAI,QAAQ;AAAA;AAAA,QAC5C,CAAC;AAAA,MACH;AAAA,IACF;AAGA,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,SAAS,KAAK,CAAC,OAAO,GAAG,OAAO,EAAE,EAAE,GAAG;AAC1C,iBAAS,KAAK,CAAC;AAAA,MACjB;AAAA,IACF;AAEA,WAAO,SAAS,MAAM,GAAG,IAAI;AAAA,EAC/B,QAAQ;AAEN,WAAO,QAAQ,MAAM,GAAG,IAAI;AAAA,EAC9B;AACF;AAIA,SAAS,mBAAmB,SAA+C;AACzE,QAAM,OAAO,oBAAI,IAA6B;AAE9C,aAAW,KAAK,SAAS;AACvB,UAAM,WAAW,KAAK,IAAI,EAAE,EAAE;AAC9B,QAAI,CAAC,YAAY,EAAE,QAAQ,SAAS,OAAO;AACzC,WAAK,IAAI,EAAE,IAAI,CAAC;AAAA,IAClB;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,KAAK,OAAO,CAAC;AACjC;AAIA,SAAS,YAAY,SAA4B,WAA4B;AAC3E,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,QAAQ,aAAa;AAC3B,MAAI,cAAc;AAClB,QAAM,SAAmB,CAAC;AAE1B,aAAW,KAAK,SAAS;AACvB,UAAM,SAAS,iBAAiB,CAAC;AACjC,UAAM,QAAQ,GAAG,MAAM;AAAA,EAAK,EAAE,OAAO;AAAA;AACrC,UAAM,SAASC,gBAAe,KAAK;AAEnC,QAAI,cAAc,SAAS,MAAO;AAElC,WAAO,KAAK,KAAK;AACjB,mBAAe;AAAA,EACjB;AAEA,SAAO,OAAO,KAAK,WAAW;AAChC;AAEA,SAAS,iBAAiB,GAA4B;AACpD,QAAM,QAAkB,CAAC;AAEzB,MAAI,EAAE,WAAY,OAAM,KAAK,WAAW,EAAE,UAAU,EAAE;AACtD,MAAI,EAAE,cAAe,OAAM,KAAK,aAAa,EAAE,aAAa,EAAE;AAC9D,MAAI,EAAE,UAAU,SAAU,OAAM,KAAK,SAAS,EAAE,SAAS,QAAQ,EAAE;AACnE,MAAI,EAAE,UAAU,UAAW,OAAM,KAAK,UAAU,EAAE,SAAS,SAAS,IAAI,EAAE,SAAS,WAAW,GAAG,EAAE;AACnG,MAAI,EAAE,aAAa,EAAE,cAAc,OAAQ,OAAM,KAAK,SAAS,EAAE,SAAS,EAAE;AAE5E,SAAO,MAAM,SAAS,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,MAAM;AACvD;AAEA,SAASA,gBAAe,MAAsB;AAC5C,SAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AAClC;AAIA,eAAe,cAAc,SAAwD;AAEnF,QAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ;AAChE,MAAI,aAAa,WAAW,EAAG,QAAO;AAGtC,QAAM,WAAW,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE;AAE7C,QAAM,YAAY,MAAM,OAAO,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAM5B,SAAS,IAAI,QAAM,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,GACzD;AAED,QAAM,YAAY,IAAI,IAAK,UAAoB,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;AAEzE,SAAO,QAAQ,IAAI,CAAC,MAAM;AACxB,UAAM,aAAa,UAAU,IAAI,EAAE,EAAE;AACrC,QAAI,YAAY;AACd,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe,WAAW,YAAY;AAAA,QACtC,YAAY,WAAW,cAAc;AAAA,MACvC;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAIA,SAAS,UAAU,OAAuB;AACxC,SAAOH,YAAW,QAAQ,EAAE,OAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK;AAC7E;AAEA,eAAe,WAAW,WAAmB,OAAe;AAC1D,QAAM,OAAO,UAAU,KAAK;AAE5B,QAAM,SAAS,MAAM,OAAO,WAAW,UAAU;AAAA,IAC/C,OAAO;AAAA,MACL;AAAA,MACA,WAAW;AAAA,MACX,WAAW,EAAE,IAAI,oBAAI,KAAK,EAAE;AAAA,IAC9B;AAAA,EACF,CAAC;AAED,MAAI,QAAQ;AACV,UAAM,OAAO,WAAW,OAAO;AAAA,MAC7B,OAAO,EAAE,IAAI,OAAO,GAAG;AAAA,MACvB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE;AAAA,IACrC,CAAC;AAED,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO;AACT;AAEA,eAAe,SACb,WACA,OACA,SACA,YACA;AACA,QAAM,OAAO,UAAU,KAAK;AAC5B,QAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,aAAa,GAAI;AAEzD,QAAM,OAAO,WAAW,OAAO;AAAA,IAC7B,OAAO;AAAA,MACL,qBAAqB;AAAA,QACnB;AAAA,QACA,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AFjpBA,IAAM,SAAS,QAAQ,IAAI,kBAAkB;AAE7C,IAAM,SAAS,IAAI,UAAU;AAAA,EAC3B,MAAM;AAAA,EACN,SAAS;AACX,CAAC;AAED,eAAe,eAAe,MAAc;AAC1C,QAAM,OAAO,MAAM,OAAO,QAAQ,UAAU;AAAA,IAC1C,OAAO;AAAA,MACL,OAAO;AAAA,MACP,IAAI;AAAA,QACF,EAAE,KAAK;AAAA,QACP,EAAE,MAAM,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,OAAO,EAAE,OAAO,EAAE,SAAS,2BAA2B;AAAA,IACtD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,SAAS,mBAAmB;AAAA,IACrE,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,8EAA8E;AAAA,IACnI,kBAAkB,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,KAAK,EAAE,SAAS,2BAA2B;AAAA,IAC5F,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,KAAK,EAAE,SAAS,mCAAmC;AAAA,IACjG,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,4BAA4B;AAAA,IACpE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,+BAA+B;AAAA,IAC1E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC5E;AAAA,EACA,OAAO,EAAE,SAAS,OAAO,OAAO,aAAa,kBAAkB,eAAe,SAAS,YAAY,WAAW,MAAM;AAClH,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,WAAW,MAAM,SAAS;AAAA,MAC9B,WAAW,KAAK;AAAA,MAChB;AAAA,MACA,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,IACb,CAAC;AAED,QAAI,SAAS,QAAQ,WAAW,GAAG;AACjC,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,6BAA6B,CAAC,EAAE;AAAA,IACpF;AAEA,UAAM,SAAS,SAAS,SAAS,KAAK,YAAY,aAAa,SAAS,KAAK,SAAS,KAAK,SAAS,KAAK,WAAW,aAAa,EAAE;AAAA;AAAA;AACnI,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,SAAS,SAAS,QAAQ,CAAC,EAAE;AAAA,EACjF;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,SAAS,EAAE,OAAO,EAAE,SAAS,6BAA6B;AAAA,IAC1D,aAAa,EAAE,KAAK,CAAC,WAAW,YAAY,YAAY,YAAY,CAAC,EAAE,SAAS,EAAE,QAAQ,SAAS;AAAA,IACnG,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,6BAA6B;AAAA,IACrE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,eAAe;AAAA,IAC1D,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,aAAa;AAAA,IACtD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,GAAG,EAAE,SAAS,gBAAgB;AAAA,EAC1E;AAAA,EACA,OAAO,EAAE,SAAS,SAAS,aAAa,SAAS,YAAY,UAAU,WAAW,MAAM;AACtF,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,YAAY,MAAM,YAAY,OAAO;AAC3C,UAAM,SAAS,MAAM,OAAO,OAAO,OAAO;AAAA,MACxC,MAAM;AAAA,QACJ,WAAW,KAAK;AAAA,QAChB;AAAA,QACA,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,sBAAsB,OAAO,EAAE,WAAW,WAAW,KAAK,CAAC,EAAE;AAAA,EACjH;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,OAAO,EAAE,OAAO,EAAE,SAAS,oBAAoB;AAAA,IAC/C,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,gBAAgB;AAAA,IACxD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mBAAmB;AAAA,IAC9D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,SAAS,mBAAmB;AAAA,EACvE;AAAA,EACA,OAAO,EAAE,SAAS,OAAO,SAAS,YAAY,MAAM,MAAM;AACxD,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,iBAAiB,MAAM,YAAY,KAAK;AAG9C,QAAI,cAAc;AAAA,sBACA,KAAK,EAAE;AAAA;AAAA;AAAA;AAIzB,QAAI,QAAS,gBAAe,mBAAmB,OAAO;AACtD,QAAI,WAAY,gBAAe,sBAAsB,UAAU;AAE/D,UAAM,UAAU,MAAM,OAAO,gBAAgB;AAAA;AAAA;AAAA,8BAGnB,KAAK,UAAU,cAAc,CAAC;AAAA;AAAA,cAE9C,WAAW;AAAA,gCACO,KAAK,UAAU,cAAc,CAAC;AAAA,cAChD,KAAK;AAAA,KACd;AAED,QAAK,QAAkB,WAAW,EAAG,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,qBAAqB,CAAC,EAAE;AAE/G,UAAM,OAAQ,QACX,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,iBAAiB,EAAE,UAAU,YAAa,EAAE,WAAsB,QAAQ,CAAC,CAAC;AAAA,EAAM,EAAE,OAAO,EAAE,EACrI,KAAK,MAAM;AAEd,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,EACtD;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA,CAAC;AAAA,EACD,YAAY;AACV,UAAM,QAAQ,MAAM,OAAO,QAAQ,SAAS;AAAA,MAC1C,OAAO,EAAE,OAAO,OAAO;AAAA,IACzB,CAAC;AACD,UAAM,OAAO,MAAM,WAAW,IAC1B,uBACA,MAAM,IAAI,CAAC,MAAM,KAAK,EAAE,IAAI,KAAK,EAAE,IAAI,IAAI,EAAE,cAAc,KAAK,EAAE,WAAW,KAAK,EAAE,EAAE,EAAE,KAAK,IAAI;AACrG,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,EACtD;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB,EAAE;AAAA,EACvD,OAAO,EAAE,QAAQ,MAAM;AACrB,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,OAAO,MAAM,OAAO,OAAO,SAAS;AAAA,MACxC,OAAO,EAAE,WAAW,KAAK,GAAG;AAAA,IAC9B,CAAC;AACD,UAAM,OAAO,KAAK,WAAW,IACzB,0BACA,KAAK,IAAI,CAAC,MAAM,KAAK,EAAE,IAAI,KAAK,EAAE,aAAa,YAAO,EAAE,MAAM,MAAM,EAAE,aAAa,UAAU,EAAE,UAAU,SAAS,EAAE,KAAK,IAAI;AACjI,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,EACtD;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,OAAO,EAAE,OAAO,EAAE,SAAS,wBAAwB;AAAA,IACnD,SAAS,EAAE,OAAO,EAAE,SAAS,2BAA2B;AAAA,EAC1D;AAAA,EACA,OAAO,EAAE,SAAS,OAAO,QAAQ,MAAM;AACrC,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,QAAI,eAAe,MAAM,OAAO,OAAO,UAAU;AAAA,MAC/C,OAAO;AAAA,QACL,WAAW,KAAK;AAAA,QAChB,eAAe;AAAA,QACf,MAAM;AAAA,MACR;AAAA,IACF,CAAC;AAED,QAAI,CAAC,cAAc;AACjB,qBAAe,MAAM,OAAO,OAAO,OAAO;AAAA,QACxC,MAAM;AAAA,UACJ,OAAO;AAAA,UACP,WAAW,KAAK;AAAA,UAChB,MAAM;AAAA,UACN,MAAM;AAAA,UACN,eAAe;AAAA,UACf,QAAQ,CAAC;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,eAAe,EAAE,UAAU,aAAa,IAAI,WAAW,KAAK,IAAI,YAAY,OAAO,KAAK,IAAI,OAAO,QAAQ,CAAC;AAClH,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,KAAK,MAAM,QAAQ,MAAM,iBAAiB,OAAO,KAAK,CAAC,EAAE;AAAA,EACzH;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,YAAY,EAAE,OAAO,EAAE,SAAS,2BAA2B;AAAA,IAC3D,MAAM,EAAE,KAAK,CAAC,QAAQ,aAAa,UAAU,MAAM,CAAC;AAAA,IACpD,SAAS,EAAE,OAAO,EAAE,SAAS,iBAAiB;AAAA,IAC9C,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,iBAAiB;AAAA,EAC3D;AAAA,EACA,OAAO,EAAE,SAAS,YAAY,MAAM,SAAS,QAAQ,MAAM;AACzD,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,QAAI,OAAO,MAAM,OAAO,QAAQ,UAAU;AAAA,MACxC,OAAO;AAAA,QACL,WAAW,KAAK;AAAA,QAChB,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAED,QAAI,CAAC,MAAM;AACT,aAAO,MAAM,OAAO,QAAQ,OAAO;AAAA,QACjC,MAAM;AAAA,UACJ,WAAW,KAAK;AAAA,UAChB,WAAW;AAAA,UACX,QAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,QAAQ,OAAO;AAAA,MAC1B,MAAM;AAAA,QACJ,gBAAgB,KAAK;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,OAAO,QAAQ,OAAO;AAAA,MAC1B,OAAO,EAAE,IAAI,KAAK,GAAG;AAAA,MACrB,MAAM;AAAA,QACJ,cAAc,EAAE,WAAW,EAAE;AAAA,QAC7B,WAAW,oBAAI,KAAK;AAAA,MACtB;AAAA,IACF,CAAC;AAED,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,2BAA2B,UAAU,KAAK,CAAC,EAAE;AAAA,EACjG;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,YAAY,EAAE,OAAO,EAAE,SAAS,oBAAoB;AAAA,IACpD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE;AAAA,EACzC;AAAA,EACA,OAAO,EAAE,SAAS,YAAY,MAAM,MAAM;AACxC,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,OAAO,MAAM,OAAO,QAAQ,UAAU;AAAA,MAC1C,OAAO;AAAA,QACL,WAAW,KAAK;AAAA,QAChB,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAED,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,0CAA0C,CAAC,EAAE;AAE1G,UAAM,OAAO,MAAM,OAAO,QAAQ,SAAS;AAAA,MACzC,OAAO,EAAE,gBAAgB,KAAK,GAAG;AAAA,MACjC,SAAS,EAAE,WAAW,MAAM;AAAA,MAC5B,MAAM;AAAA,IACR,CAAC;AAED,UAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,MAAM;AACrE,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,mBAAmB,CAAC,EAAE;AAAA,EAClF;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,OAAO,EAAE,OAAO,EAAE,SAAS,4DAA4D;AAAA,IACvF,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,gBAAgB;AAAA,IACxD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mBAAmB;AAAA,IAC9D,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,qCAAqC;AAAA,IACnF,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,WAAW,cAAc,SAAS,gBAAgB,WAAW,QAAQ,aAAa,CAAC,CAAC,EAAE,SAAS;AAAA,IAC7H,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE;AAAA,IACvC,mBAAmB,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,IAAI,EAAE,SAAS,8CAA8C;AAAA,EACjH;AAAA,EACA,OAAO,EAAE,SAAS,OAAO,SAAS,YAAY,eAAe,cAAc,OAAO,kBAAkB,MAAM;AACxG,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAGlG,UAAM,EAAE,eAAe,IAAI,MAAM,OAAO,sBAA4B;AAEpE,UAAM,UAAU,MAAM,eAAe;AAAA,MACnC;AAAA,MACA,cAAc,gBAAgB,IAAI,KAAK,aAAa,IAAI,oBAAI,KAAK;AAAA,MACjE,WAAW,KAAK;AAAA,MAChB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAED,QAAI,QAAQ,WAAW,EAAG,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,qBAAqB,CAAC,EAAE;AAEpG,UAAM,OAAO,QAAQ,IAAI,CAAC,GAAG,MAAM;AACjC,UAAI,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,UAAU,iBAAiB,EAAE,OAAO,WAAW,QAAQ,CAAC,CAAC,YAAY,EAAE,WAAW,QAAQ,CAAC,CAAC;AAAA;AAC9H,cAAQ,MAAM,EAAE,OAAO,OAAO;AAAA;AAC9B,UAAI,EAAE,OAAO,SAAS,WAAW;AAC/B,gBAAQ,aAAa,EAAE,OAAO,SAAS,UAAU,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;AAAA;AAAA,MAC9E;AACA,UAAI,qBAAqB,EAAE,aAAa,EAAE,UAAU,SAAS,GAAG;AAC9D,gBAAQ,iBAAiB,EAAE,UAAU,IAAI,SAAO,IAAI,YAAY,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,MAC9E;AACA,aAAO;AAAA,IACT,CAAC,EAAE,KAAK,IAAI;AAEZ,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,EACtD;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,YAAY,EAAE,OAAO,EAAE,SAAS,oBAAoB;AAAA,IACpD,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,iBAAiB;AAAA,IACzD,UAAU,EAAE,MAAM,EAAE,OAAO;AAAA,MACzB,MAAM,EAAE,OAAO;AAAA,MACf,SAAS,EAAE,OAAO;AAAA,MAClB,WAAW,EAAE,OAAO;AAAA,IACtB,CAAC,CAAC,EAAE,SAAS,gDAAgD;AAAA,EAC/D;AAAA,EACA,OAAO,EAAE,SAAS,YAAY,SAAS,SAAS,MAAM;AACpD,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,sBAA4B;AAEnE,UAAM,SAAS,MAAM,cAAc;AAAA,MACjC,WAAW;AAAA,MACX,WAAW,KAAK;AAAA,MAChB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,UAAU,SAAS,IAAI,QAAM;AAAA,QAC3B,MAAM,EAAE;AAAA,QACR,SAAS,EAAE;AAAA,QACX,WAAW,IAAI,KAAK,EAAE,SAAS;AAAA,MACjC,EAAE;AAAA,IACJ,CAAC;AAED,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM,aAAa,SAAS,MAAM;AAAA,YACnB,OAAO,eAAe;AAAA,aACrB,OAAO,gBAAgB;AAAA,YACxB,OAAO,mBAAmB,wBACtC,OAAO,UAAU,OAAO,OAAO,SAAS,IAAI;AAAA,YAAe,OAAO,OAAO,KAAK,IAAI,CAAC,KAAK;AAAA,MAC7F,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,OAAO,EAAE,OAAO,EAAE,SAAS,mBAAmB;AAAA,IAC9C,MAAM,EAAE,KAAK,CAAC,UAAU,UAAU,CAAC,EAAE,SAAS,EAAE,QAAQ,QAAQ,EAAE,SAAS,+DAA+D;AAAA,IAC1I,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,IAC5C,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,SAAS,wCAAwC;AAAA,EAC/F;AAAA,EACA,OAAO,EAAE,SAAS,OAAO,MAAM,aAAa,UAAU,MAAM;AAC1D,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,EAAE,cAAc,eAAe,IAAI,MAAM,OAAO,sBAAqB;AAE3E,QAAI,SAAS,YAAY;AACvB,YAAM,SAAS,MAAM,eAAe;AAAA,QAClC,UAAU;AAAA,QACV,WAAW,KAAK;AAAA,QAChB,UAAU;AAAA,MACZ,CAAC;AAED,UAAI,OAAO,WAAW,OAAO,MAAM;AAAA;AAAA;AAAA;AACnC,aAAO,MAAM,QAAQ,CAAC,MAAM,MAAM;AAChC,gBAAQ,GAAG,IAAI,CAAC,YAAY,KAAK,KAAK;AAAA,gBAAmB,KAAK,SAAS;AAAA,cAAiB,KAAK,QAAQ,MAAM;AAAA;AAAA,MAC7G,CAAC;AAED,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,IACtD,OAAO;AACL,YAAM,UAAU,MAAM,aAAa;AAAA,QACjC;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,MAAM;AAAA,MACR,CAAC;AAED,UAAI,QAAQ,WAAW,EAAG,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,oBAAoB,CAAC,EAAE;AAEnG,YAAM,OAAO,QAAQ;AAAA,QAAI,CAAC,GAAG,MAC3B,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,iBAAiB,EAAE,UAAU,QAAQ,CAAC,CAAC;AAAA,EAAM,EAAE,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,MAC1F,EAAE,KAAK,MAAM;AAEb,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,IACtD;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,aAAa,EAAE,KAAK,CAAC,UAAU,OAAO,CAAC,EAAE,SAAS,iBAAiB;AAAA,IACnE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,4BAA4B;AAAA,IACzE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,6BAA6B;AAAA,IACzE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,oCAAoC;AAAA,IAC/E,iBAAiB,EAAE,KAAK,CAAC,gBAAgB,oBAAoB,cAAc,UAAU,SAAS,CAAC,EAAE,SAAS;AAAA,IAC1G,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,SAAS,2BAA2B;AAAA,EACrF;AAAA,EACA,OAAO,EAAE,SAAS,aAAa,cAAc,aAAa,YAAY,iBAAiB,YAAY,MAAM;AACvG,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,6BAA4B;AAEnE,UAAM,SAAS,MAAM,cAAc;AAAA,MACjC,WAAW,KAAK;AAAA,MAChB,OAAO;AAAA,MACP,QAAQ,gBAAgB,WACpB,EAAE,MAAM,UAAU,OAAO,cAAe,MAAM,YAAa,IAC3D,EAAE,MAAM,SAAS,UAAU,WAAY;AAAA,MAC3C,YAAY;AAAA,IACd,CAAC;AAED,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,gBACa,OAAO,UAAU;AAAA,aACpB,OAAO,OAAO;AAAA,aACd,OAAO,OAAO;AAAA,YACf,OAAO,OAAO,MAAM;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,YAAY,EAAE,OAAO,EAAE,SAAS,kBAAkB;AAAA,IAClD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8BAA8B;AAAA,IACpE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,SAAS,mBAAmB;AAAA,EAC7E;AAAA,EACA,OAAO,EAAE,SAAS,YAAY,OAAO,YAAY,MAAM;AACrD,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,+BAA8B;AAE3E,UAAM,SAAS,MAAM,oBAAoB;AAAA,MACvC,WAAW;AAAA,MACX,WAAW,KAAK;AAAA,MAChB,OAAO;AAAA,MACP,iBAAiB;AAAA,MACjB,YAAY;AAAA,IACd,CAAC;AAED,WAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,cACW,OAAO,EAAE;AAAA,cACT,OAAO,UAAU,UAAU,CAAC;AAAA,cAC5B,OAAO,UAAU,UAAU,CAAC;AAAA,aAC7B,OAAO,WAAW,YAAY,KAAK,OAAO;AAAA;AAAA,aACxC,OAAO,QAAQ;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAIA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,sBAAsB;AAAA,IACnD,sBAAsB,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI,EAAE,SAAS,4BAA4B;AAAA,IAC/F,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,KAAK,EAAE,SAAS,yBAAyB;AAAA,EACnF;AAAA,EACA,OAAO,EAAE,SAAS,sBAAsB,QAAQ,MAAM;AACpD,UAAM,OAAO,MAAM,eAAe,OAAO;AACzC,QAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAElG,UAAM,EAAE,uBAAuB,oBAAoB,IAAI,MAAM,OAAO,6BAAmC;AAEvG,QAAI,SAAS;AACX,YAAM,WAAW,MAAM,sBAAsB;AAAA,QAC3C,WAAW,KAAK;AAAA,QAChB,qBAAqB;AAAA,MACvB,CAAC;AAED,YAAM,kBAAkB,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,WAAW,QAAQ,CAAC;AAEhF,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM,SAAS,SAAS,MAAM;AAAA,sBACL,eAAe;AAAA,uBACd,eAAe;AAAA;AAAA;AAAA,QAE3C,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,YAAM,SAAS,MAAM,oBAAoB;AAAA,QACvC,WAAW,KAAK;AAAA,QAChB,qBAAqB;AAAA,QACrB,QAAQ;AAAA,MACV,CAAC;AAED,aAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,MAAM;AAAA,UACN,MAAM;AAAA,oBACiB,OAAO,aAAa;AAAA,qBACnB,OAAO,cAAc;AAAA,0BAChB,OAAO,mBAAmB;AAAA,QACzD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,IACE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8CAA8C;AAAA,IACtF,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,SAAS,qBAAqB;AAAA,EACxE;AAAA,EACA,OAAO,EAAE,SAAS,KAAK,MAAM;AAC3B,QAAI;AACJ,QAAI,SAAS;AACX,YAAM,OAAO,MAAM,eAAe,OAAO;AACzC,UAAI,CAAC,KAAM,QAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,OAAO,eAAe,CAAC,EAAE;AAClG,kBAAY,KAAK;AAAA,IACnB;AAEA,UAAM,EAAE,gBAAgB,iBAAiB,IAAI,MAAM,OAAO,iCAAgC;AAE1F,UAAM,UAAU,oBAAI,KAAK;AACzB,UAAM,YAAY,IAAI,KAAK,QAAQ,QAAQ,IAAI,OAAO,KAAK,KAAK,KAAK,GAAI;AAEzE,UAAM,UAAU,eAAe;AAAA,MAC7B,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,UAAM,UAAU,iBAAiB;AAAA,MAC/B,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,sBAAsB,IAAI;AAAA;AAAA;AACrC,YAAQ,gBAAgB,QAAQ,WAAW,QAAQ,CAAC,CAAC;AAAA;AACrD,YAAQ,mBAAmB,OAAO,OAAO,OAAO,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC,CAAC;AAAA;AACtF,YAAQ,uBAAuB,QAAQ,cAAc,OAAO,OAAO,OAAO,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC;AAAA;AAAA;AAClI,YAAQ;AAAA;AACR,WAAO,QAAQ,OAAO,EAAE,QAAQ,CAAC,CAAC,OAAO,KAAK,MAAM;AAClD,cAAQ,KAAK,KAAK,MAAM,MAAM,UAAU,QAAQ,CAAC,CAAC,KAAK,MAAM,KAAK;AAAA;AAAA,IACpE,CAAC;AACD,YAAQ;AAAA;AAAA;AACR,YAAQ,cAAc,QAAQ,WAAW,QAAQ,CAAC,CAAC;AAAA;AACnD,YAAQ,iBAAiB,QAAQ,SAAS,QAAQ,CAAC,CAAC;AAAA;AACpD,YAAQ,aAAa,QAAQ,QAAQ,QAAQ,CAAC,CAAC,KAAK,QAAQ,eAAe,QAAQ,CAAC,CAAC;AAAA;AAErF,WAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC,EAAE;AAAA,EACtD;AACF;AAIA,eAAe,OAAO;AACpB,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAC9B,UAAQ,MAAM,6CAA6C;AAC7D;AAEA,KAAK,EAAE,MAAM,QAAQ,KAAK;","names":["createHash","OpenAI","openai","estimateTokens"]}
package/package.json CHANGED
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "name": "@usewhisper/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
+ "scripts": {
5
+ "build": "tsup ../src/mcp/server.ts --format esm --out-dir dist",
6
+ "prepublishOnly": "npm run build"
7
+ },
4
8
  "description": "Model Context Protocol server for Whisper Context API - Connect Claude Desktop to your knowledge base",
5
9
  "type": "module",
6
10
  "bin": {
@@ -11,7 +15,6 @@
11
15
  "dist",
12
16
  "README.md"
13
17
  ],
14
- "scripts": {},
15
18
  "keywords": [
16
19
  "whisper",
17
20
  "context",
@@ -35,11 +38,7 @@
35
38
  },
36
39
  "dependencies": {
37
40
  "@modelcontextprotocol/sdk": "^1.12.0",
38
- "drizzle-orm": "^0.45.1",
39
- "openai": "^4.80.0",
40
- "postgres": "^3.4.0",
41
- "zod": "^3.24.0",
42
- "dotenv": "^16.0.0"
41
+ "zod": "^3.24.0"
43
42
  },
44
43
  "devDependencies": {
45
44
  "@types/node": "^22.0.0",