@automagik/genie-brain 0.260404.8

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 automagik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ var JJ=Object.defineProperty;var XJ=(J)=>J;function ZJ(J,X){this[J]=XJ.bind(null,X)}var D=(J,X)=>{for(var Z in X)JJ(J,Z,{get:X[Z],enumerable:!0,configurable:!0,set:ZJ.bind(X,Z)})};var I=(J,X)=>()=>(J&&(X=J(J=0)),X);var _=import.meta.require;var m={};D(m,{normalizeDocid:()=>p,isDocid:()=>xJ,generateDocid:()=>UJ,contentHash:()=>OJ});import{createHash as g}from"crypto";function UJ(J){return g("sha256").update(J).digest("hex").slice(0,6)}function OJ(J){return g("sha256").update(J).digest("hex")}function p(J){let X=J.trim();if(X.startsWith('"')&&X.endsWith('"')||X.startsWith("'")&&X.endsWith("'"))X=X.slice(1,-1);if(X.startsWith("#"))X=X.slice(1);return X}function xJ(J){let X=p(J);return X.length>=6&&/^[a-f0-9]+$/i.test(X)}var u=()=>{};var K={};D(K,{upsertDocument:()=>LJ,upsertChunks:()=>AJ,upsertBrain:()=>zJ,updateBrainStats:()=>_J,runMigration:()=>d,runAllMigrations:()=>l,releaseBrainLock:()=>RJ,listDocuments:()=>EJ,listBrains:()=>qJ,getDocumentHashMap:()=>PJ,getDocument:()=>CJ,getDb:()=>N,getBrainByPath:()=>QJ,getBrain:()=>BJ,ensureBrainTables:()=>KJ,deleteStaleDocs:()=>jJ,checkDependencies:()=>TJ,acquireBrainLock:()=>MJ});import{readFileSync as HJ}from"fs";import{join as q}from"path";async function N(){if(L)return L;try{L=await(await import("genie/lib/db.js")).getConnection()}catch{let J=await import("postgres"),X=J.default??J,Z=Number(process.env.PGPORT??19642),$=process.env.PGHOST??"127.0.0.1",F=process.env.PGDATABASE??"genie";L=X({host:$,port:Z,database:F,username:process.env.PGUSER??"postgres",password:process.env.PGPASSWORD??"postgres",max:10,idle_timeout:5,connect_timeout:5})}return L}async function KJ(){if(T)return;try{let J=await N();await J`SELECT 1 FROM brains LIMIT 0`,await J`SELECT brain_id FROM brain_documents LIMIT 0`,T=!0}catch{await l(),T=!0}}async function d(J){let X=await N(),Z=HJ(J,"utf-8");await X.unsafe(Z)}async function l(){let{existsSync:J,readdirSync:X}=await import("fs"),Z=[q(import.meta.dir,"..","db","migrations"),q(import.meta.dir,"..","src","db","migrations"),q(import.meta.dir,"db","migrations"),q(import.meta.dir,"..","..","src","db","migrations"),q(import.meta.dir,"..","..","db","migrations")],$=Z.find((W)=>J(W));if(!$)throw Error(`Brain migrations not found. Searched: ${Z.join(", ")}`);let F=X($).filter((W)=>W.endsWith(".sql")).sort(),Y=[];for(let W of F)await d(q($,W)),Y.push(W);return Y}async function zJ(J){let X=await N(),[Z]=await X`
4
+ INSERT INTO brains (id, short_name, name, description, brain_type, owner_type, owner_id, lifecycle, home_path)
5
+ VALUES (${J.id}, ${J.shortName}, ${J.name}, ${J.description??null}, ${J.brainType}, ${J.ownerType}, ${J.ownerId}, ${J.lifecycle}, ${J.homePath})
6
+ ON CONFLICT (id) DO UPDATE SET
7
+ name = EXCLUDED.name,
8
+ description = EXCLUDED.description,
9
+ brain_type = EXCLUDED.brain_type,
10
+ home_path = EXCLUDED.home_path,
11
+ updated_at = now()
12
+ RETURNING *
13
+ `;return P(Z)}async function BJ(J){let X=await N(),[Z]=await X`SELECT * FROM brains WHERE id = ${J}`;return Z?P(Z):null}async function QJ(J){let X=await N(),[Z]=await X`SELECT * FROM brains WHERE home_path = ${J} LIMIT 1`;return Z?P(Z):null}async function qJ(){return(await(await N())`SELECT * FROM brains ORDER BY updated_at DESC`).map(P)}async function _J(J,X){await(await N())`
14
+ UPDATE brains SET
15
+ file_count = COALESCE(${X.fileCount??null}, file_count),
16
+ chunk_count = COALESCE(${X.chunkCount??null}, chunk_count),
17
+ mount_count = COALESCE(${X.mountCount??null}, mount_count),
18
+ last_update_at = now(),
19
+ updated_at = now()
20
+ WHERE id = ${J}
21
+ `}async function LJ(J){let X=await N(),Z=J.frontmatter?JSON.stringify(J.frontmatter):null,[$]=await X`
22
+ INSERT INTO brain_documents (brain_id, path, title, docid, content_hash, modality, mime_type, content, frontmatter, source_type, parent_doc_id)
23
+ VALUES (${J.brainId}, ${J.path}, ${J.title}, ${J.docid}, ${J.contentHash}, ${J.modality}, ${J.mimeType}, ${J.content}, ${Z}::jsonb, ${J.sourceType}, ${J.parentDocId})
24
+ ON CONFLICT (brain_id, path) DO UPDATE SET
25
+ title = EXCLUDED.title,
26
+ docid = EXCLUDED.docid,
27
+ content_hash = EXCLUDED.content_hash,
28
+ content = EXCLUDED.content,
29
+ frontmatter = EXCLUDED.frontmatter,
30
+ source_type = EXCLUDED.source_type,
31
+ updated_at = now()
32
+ RETURNING id, (xmax = 0) as is_new
33
+ `;return{id:$.id,isNew:$.is_new}}async function CJ(J,X){let Z=await N(),$,{isDocid:F,normalizeDocid:Y}=await Promise.resolve().then(() => (u(),m));if(F(X)){let W=Y(X);[$]=await Z`
34
+ SELECT * FROM brain_documents
35
+ WHERE brain_id = ${J} AND docid LIKE ${`${W}%`}
36
+ LIMIT 1
37
+ `}else[$]=await Z`
38
+ SELECT * FROM brain_documents
39
+ WHERE brain_id = ${J} AND path = ${X}
40
+ `;return $?c($):null}async function EJ(J,X){let Z=await N(),$;if(X?.modality)$=await Z`
41
+ SELECT * FROM brain_documents
42
+ WHERE brain_id = ${J} AND modality = ${X.modality}
43
+ ORDER BY updated_at DESC
44
+ `;else if(X?.sourceType)$=await Z`
45
+ SELECT * FROM brain_documents
46
+ WHERE brain_id = ${J} AND source_type = ${X.sourceType}
47
+ ORDER BY updated_at DESC
48
+ `;else $=await Z`
49
+ SELECT * FROM brain_documents
50
+ WHERE brain_id = ${J}
51
+ ORDER BY updated_at DESC
52
+ `;return $.map(c)}async function PJ(J){let Z=await(await N())`
53
+ SELECT path, content_hash FROM brain_documents WHERE brain_id = ${J}
54
+ `;return new Map(Z.map(($)=>[$.path,$.content_hash]))}async function jJ(J,X){let Z=await N();if(X.size===0)return(await Z`DELETE FROM brain_documents WHERE brain_id = ${J}`).count;let $=Array.from(X);return(await Z`
55
+ DELETE FROM brain_documents
56
+ WHERE brain_id = ${J}
57
+ AND path != ALL(${$})
58
+ `).count}async function AJ(J,X,Z){let $=await N();if(await $`DELETE FROM brain_chunks WHERE document_id = ${J}`,Z.length===0)return;for(let F of Z)await $`
59
+ INSERT INTO brain_chunks (document_id, brain_id, chunk_index, heading, content, token_count)
60
+ VALUES (${J}, ${X}, ${F.chunkIndex}, ${F.heading}, ${F.content}, ${F.tokenCount})
61
+ `}async function MJ(J,X=!1){let Z=await N();if(X){let[$]=await Z`SELECT pg_try_advisory_lock(hashtext(${J})) as acquired`;return $.acquired}return await Z`SELECT pg_advisory_lock(hashtext(${J}))`,!0}async function RJ(J){await(await N())`SELECT pg_advisory_unlock(hashtext(${J}))`}async function TJ(){let J=await N(),X=[];try{await J`SELECT 'test'::text % 'test'::text`,X.push({name:"pg_trgm",available:!0,required:!0})}catch{X.push({name:"pg_trgm",available:!1,required:!0,message:"Run: CREATE EXTENSION IF NOT EXISTS pg_trgm;"})}try{await J`SELECT '[1,2,3]'::vector`,X.push({name:"pgvector",available:!0,required:!0})}catch{X.push({name:"pgvector",available:!1,required:!0,message:"Install pgvector extension in Postgres, then: CREATE EXTENSION IF NOT EXISTS vector;"})}return X}function P(J){return{id:J.id,shortName:J.short_name,name:J.name,description:J.description,brainType:J.brain_type??"generic",ownerType:J.owner_type,ownerId:J.owner_id,lifecycle:J.lifecycle??"permanent",homePath:J.home_path,fileCount:J.file_count??0,chunkCount:J.chunk_count??0,mountCount:J.mount_count??0,healthScore:J.health_score,healthCheckedAt:J.health_checked_at?new Date(J.health_checked_at):null,lastQueryAt:J.last_query_at?new Date(J.last_query_at):null,lastUpdateAt:J.last_update_at?new Date(J.last_update_at):null,totalQueries:J.total_queries??0,createdAt:new Date(J.created_at),updatedAt:new Date(J.updated_at)}}function c(J){return{id:J.id,brainId:J.brain_id,path:J.path,title:J.title,docid:J.docid,contentHash:J.content_hash,modality:J.modality??"text",mimeType:J.mime_type,content:J.content,frontmatter:J.frontmatter,sourceType:J.source_type??"direct",parentDocId:J.parent_doc_id,createdAt:new Date(J.created_at),updatedAt:new Date(J.updated_at)}}var L=null,T=!1;var z=()=>{};import{existsSync as a}from"fs";import{extname as kJ,join as j}from"path";function $J(J,X=0.7){if(J.length===0)return 0;return J.reduce(($,F)=>{return $+(F.judgeScore>=X?F.reciprocalRank:0)},0)/J.length}function YJ(J,X){if(J.length===0)return 0;let Z=[...J].sort((W,V)=>W.rank-V.rank).slice(0,X),$=0;for(let W=0;W<Z.length;W++)$+=Z[W].relevance/Math.log2(W+2);let F=[...J].sort((W,V)=>V.relevance-W.relevance).slice(0,X),Y=0;for(let W=0;W<F.length;W++)Y+=F[W].relevance/Math.log2(W+2);return Y===0?0:$/Y}function FJ(J,X,Z=0.7){if(J.length===0)return 0;return J.filter((F)=>F.hitAtK&&F.judgeScore>=Z).length/J.length}function WJ(J,X,Z=0.7){if(J.length===0)return 0;return J.filter((F)=>F.hitAtK&&F.judgeScore>=Z).length/J.length}function VJ(J,X){if(J+X===0)return 0;return 2*J*X/(J+X)}function GJ(J){if(J.length===0)return{min:0,max:0,mean:0,median:0,p95:0,p99:0,stdDev:0,count:0};let X=[...J].sort((V,G)=>V-G),Z=X.length,F=X.reduce((V,G)=>V+G,0)/Z,Y=X.reduce((V,G)=>V+(G-F)**2,0)/Z,W=Math.sqrt(Y);return{min:X[0],max:X[Z-1],mean:F,median:Z%2===0?(X[Z/2-1]+X[Z/2])/2:X[Math.floor(Z/2)],p95:X[Math.min(Math.ceil(Z*0.95)-1,Z-1)],p99:X[Math.min(Math.ceil(Z*0.99)-1,Z-1)],stdDev:W,count:Z}}function NJ(J){let X={};for(let Z of J){let $=Z??"UNKNOWN";X[$]=(X[$]??0)+1}return X}function S(J,X=10,Z=0.7){if(J.length===0)return{count:0,mrr:0,ndcg:0,hitAtK:0,precisionAtK:0,recallAtK:0,f1AtK:0,avgScore:0,hitRate:0,k:X,latency:{min:0,max:0,mean:0,median:0,p95:0,p99:0,stdDev:0,count:0},confidenceDistribution:{}};let $=$J(J,Z),F=FJ(J,X,Z),Y=WJ(J,X,Z),W=J.map((O)=>({rank:0,relevance:O.judgeScore})),V=YJ(W,X),G=F,U=VJ(G,Y),H=J.reduce((O,R)=>O+R.judgeScore,0)/J.length,C=J.filter((O)=>O.judgeScore>=Z).length/J.length,E=GJ(J.map((O)=>O.latencyMs)),M=NJ(J.map((O)=>O.confidenceLevel));return{count:J.length,mrr:$,ndcg:V,hitAtK:F,precisionAtK:G,recallAtK:Y,f1AtK:U,avgScore:H,hitRate:C,k:X,latency:E,confidenceDistribution:M}}function y(J,X=10,Z=0.7){let $=S(J,X,Z),F=new Map;for(let W of J){let V=W.questionType??"unknown",G=F.get(V)??[];G.push(W),F.set(V,G)}let Y={};for(let[W,V]of F)Y[W]=S(V,X,Z);return{overall:$,byType:Y}}var f={rrf_k:{default:60,range:[20,120],step:10,description:"RRF constant k \u2014 higher values reduce rank position influence",source:"src/lib/strategies/rag.ts"},bm25_weight:{default:1,range:[0,2],step:0.2,description:"Weight for BM25 full-text search in RRF fusion",source:"src/lib/strategies/rag.ts"},trigram_weight:{default:0.8,range:[0,2],step:0.2,description:"Weight for trigram similarity search in RRF fusion",source:"src/lib/strategies/rag.ts"},vector_weight:{default:1.2,range:[0,2],step:0.2,description:"Weight for vector cosine similarity in RRF fusion",source:"src/lib/strategies/rag.ts"},top_rank_bonus_0:{default:0.05,range:[0,0.15],step:0.01,description:"Bonus added to rank-0 result in RRF",source:"src/lib/rrf.ts"},top_rank_bonus_2:{default:0.02,range:[0,0.1],step:0.01,description:"Bonus added to rank-0,1,2 results in RRF",source:"src/lib/rrf.ts"},vector_threshold:{default:0.45,range:[0.2,0.8],step:0.05,description:"Minimum cosine similarity to include vector result",source:"src/lib/strategies/rag.ts"},normalization_ceiling:{default:0.98,range:[0.7,1],step:0.05,description:"Maximum normalized score ceiling",source:"src/lib/search.ts"},normalization_floor:{default:0.2,range:[0.05,0.5],step:0.05,description:"Minimum score floor for quality ceiling calculation",source:"src/lib/search.ts"},confidence_full:{default:0.8,range:[0.6,0.95],step:0.05,description:"Top score threshold for FULL confidence",source:"src/lib/types.ts"},confidence_high:{default:0.7,range:[0.5,0.85],step:0.05,description:"Top score threshold for HIGH confidence",source:"src/lib/types.ts"},confidence_partial:{default:0.5,range:[0.3,0.7],step:0.05,description:"Top score threshold for PARTIAL confidence",source:"src/lib/types.ts"},authority_direct:{default:1,range:[0.5,1.5],step:0.1,description:"Authority weight for direct source documents",source:"src/lib/types.ts"},authority_learning:{default:1.2,range:[0.5,2],step:0.1,description:"Authority weight for learning/memory documents",source:"src/lib/types.ts"}};var Q={quality:25,mrr:20,f1AtK:15,hitRate:15,speed:15,cost:10},v={maxLatencyMs:1e4,maxCostCentsPerQuestion:5};function w(J,X=1){let Z=(H)=>Math.max(0,Math.min(1,H)),$=Z(J.quality),F=Z(J.mrr),Y=Z(J.f1AtK),W=Z(J.hitRate),V=Z(1-J.p95LatencyMs/v.maxLatencyMs),G=X>0?J.costCents/X:0,U=Z(1-G/v.maxCostCentsPerQuestion);return $*Q.quality+F*Q.mrr+Y*Q.f1AtK+W*Q.hitRate+V*Q.speed+U*Q.cost}function b(J,X,Z){let $=`${J.toFixed(0)}%`,F=X>=1000?`${(X/1000).toFixed(1)}s`:`${X.toFixed(0)}ms`,Y=Z>=100?`$${(Z/100).toFixed(2)}`:`${Z.toFixed(1)}c`;return`${$} / ${F} / ${Y}`}function h(J){let X=new Set;for(let Z=0;Z<J.length;Z++){let $=!1;for(let F=0;F<J.length;F++){if(Z===F)continue;let Y=J[F],W=J[Z],V=Y.brainScore>=W.brainScore,G=Y.avgLatencyMs<=W.avgLatencyMs,U=Y.totalCostCents<=W.totalCostCents;if(V&&G&&U){if(Y.brainScore>W.brainScore||Y.avgLatencyMs<W.avgLatencyMs||Y.totalCostCents<W.totalCostCents){$=!0;break}}}if(!$)X.add(Z)}return X}var A={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, OPTIONS","Access-Control-Allow-Headers":"Content-Type"};function x(J,X=200){return new Response(JSON.stringify(J,null,2),{status:X,headers:{...A,"Content-Type":"application/json"}})}function B(J,X=400){return x({error:J},X)}async function DJ(){let{getDb:J}=await Promise.resolve().then(() => (z(),K)),Z=await(await J())`
62
+ SELECT id, brain_id, source_path, questions_path, total_questions,
63
+ budget_cents, spent_cents, status, current_round,
64
+ winning_strategy, started_at, finished_at
65
+ FROM brain_auto_kb_runs
66
+ ORDER BY started_at DESC
67
+ LIMIT 50
68
+ `;return x(Z)}async function IJ(J){let{getDb:X}=await Promise.resolve().then(() => (z(),K)),Z=await X(),$=await Z`SELECT * FROM brain_auto_kb_runs WHERE id = ${J}`;if($.length===0)return B("Run not found",404);let F=await Z`
69
+ SELECT strategy, kb_layout, domain_pattern,
70
+ COUNT(*) as total_questions,
71
+ AVG(judge_score) as avg_score,
72
+ COUNT(*) FILTER (WHERE judge_score >= 0.7) * 100.0 / COUNT(*) as hit_rate_pct,
73
+ AVG(latency_ms) as avg_latency_ms,
74
+ SUM(cost_cents) as total_cost_cents
75
+ FROM brain_benchmark_runs
76
+ WHERE run_id = ${J}
77
+ GROUP BY strategy, kb_layout, domain_pattern
78
+ ORDER BY avg_score DESC
79
+ `;return x({run:$[0],strategyResults:F})}async function SJ(J){let{getDb:X}=await Promise.resolve().then(() => (z(),K)),$=await(await X())`
80
+ SELECT question_id, question, strategy, judge_score, latency_ms,
81
+ domain_pattern, metadata
82
+ FROM brain_benchmark_runs
83
+ WHERE run_id = ${J}
84
+ ORDER BY question_id
85
+ `;if($.length===0)return B("No results for this run",404);let F=$.map((V)=>({questionId:String(V.question_id),questionType:V.domain_pattern?String(V.domain_pattern):void 0,judgeScore:Number(V.judge_score??0),reciprocalRank:Number(V.judge_score??0)>=0.7?1:0,hitAtK:Number(V.judge_score??0)>=0.7,latencyMs:Number(V.latency_ms??0),confidenceLevel:void 0})),Y=new Map;for(let V=0;V<$.length;V++){let G=String($[V].strategy),U=Y.get(G)??[];U.push(F[V]),Y.set(G,U)}let W={};for(let[V,G]of Y)W[V]=y(G);return x({runId:J,totalQuestions:$.length,strategies:W})}async function yJ(J){if(J.length<2)return B("Need at least 2 run IDs to compare");let{getDb:X}=await Promise.resolve().then(() => (z(),K)),Z=await X(),$={};for(let F of J){let Y=await Z`
86
+ SELECT strategy, kb_layout,
87
+ COUNT(*) as questions,
88
+ AVG(judge_score) as avg_score,
89
+ COUNT(*) FILTER (WHERE judge_score >= 0.7) * 100.0 / COUNT(*) as hit_rate_pct,
90
+ AVG(latency_ms) as avg_latency_ms,
91
+ SUM(cost_cents) as cost_cents
92
+ FROM brain_benchmark_runs
93
+ WHERE run_id = ${F}
94
+ GROUP BY strategy, kb_layout
95
+ ORDER BY avg_score DESC
96
+ `;$[F]=Y}return x($)}async function fJ(){let{getDb:J}=await Promise.resolve().then(() => (z(),K)),$=(await(await J())`
97
+ SELECT strategy, kb_layout,
98
+ COUNT(*) as total_evaluations,
99
+ AVG(judge_score) as avg_score,
100
+ COUNT(*) FILTER (WHERE judge_score >= 0.7) * 100.0 / COUNT(*) as hit_rate_pct,
101
+ COUNT(*) FILTER (WHERE judge_score >= 0.9) * 100.0 / COUNT(*) as perfect_rate_pct,
102
+ AVG(latency_ms) as avg_latency_ms,
103
+ PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY latency_ms) as p95_latency_ms,
104
+ SUM(cost_cents) as total_cost_cents,
105
+ COUNT(DISTINCT run_id) as runs
106
+ FROM brain_benchmark_runs
107
+ WHERE judge_score IS NOT NULL
108
+ GROUP BY strategy, kb_layout
109
+ HAVING COUNT(*) >= 3
110
+ ORDER BY avg_score DESC
111
+ LIMIT 50
112
+ `).map((Y)=>{let W=Number(Y.avg_score??0),V=Number(Y.hit_rate_pct??0),G=Number(Y.avg_latency_ms??0),U=Number(Y.p95_latency_ms??G),H=Number(Y.total_cost_cents??0),C=Number(Y.total_evaluations??0),E=W,M=W*0.95,O=V/100*W*2/(V/100+W+0.001),R=w({quality:W,mrr:E,f1AtK:O,hitRate:V/100,p95LatencyMs:U,costCents:H},C),r=b(V,U,H);return{strategy:String(Y.strategy),kbLayout:Y.kb_layout?String(Y.kb_layout):null,totalEvaluations:C,avgScore:W,hitRatePct:V,perfectRatePct:Number(Y.perfect_rate_pct??0),avgLatencyMs:G,p95LatencyMs:U,totalCostCents:H,runs:Number(Y.runs??0),mrr:E,ndcg:M,f1AtK:O,brainScore:R,memScore:r,isParetoOptimal:!1}}),F=h($.map((Y)=>({brainScore:Y.brainScore,avgLatencyMs:Y.avgLatencyMs,totalCostCents:Y.totalCostCents})));for(let Y of F)$[Y].isParetoOptimal=!0;return $.sort((Y,W)=>W.brainScore-Y.brainScore),x($)}async function vJ(J){let{getDb:X}=await Promise.resolve().then(() => (z(),K)),$=await(await X())`
113
+ SELECT question_id, question, strategy, judge_score, latency_ms,
114
+ cost_cents, domain_pattern, metadata,
115
+ CASE WHEN judge_score >= 0.7 THEN true ELSE false END as hit_at_k
116
+ FROM brain_benchmark_runs
117
+ WHERE run_id = ${J}
118
+ ORDER BY question_id
119
+ `;if($.length===0)return B("No results for this run",404);let F=$.map((Y)=>({questionId:String(Y.question_id),question:Y.question?String(Y.question):null,strategy:String(Y.strategy),judgeScore:Number(Y.judge_score??0),latencyMs:Number(Y.latency_ms??0),costCents:Number(Y.cost_cents??0),hitAtK:Boolean(Y.hit_at_k),reciprocalRank:Number(Y.judge_score??0)>=0.7?1:0,domainPattern:Y.domain_pattern?String(Y.domain_pattern):null}));return x({runId:J,questions:F})}async function wJ(J){let{getDb:X}=await Promise.resolve().then(() => (z(),K)),$=await(await X())`
120
+ SELECT question_id, question, strategy, judge_score, latency_ms,
121
+ cost_cents, domain_pattern,
122
+ CASE WHEN judge_score >= 0.7 THEN true ELSE false END as hit_at_k
123
+ FROM brain_benchmark_runs
124
+ WHERE strategy = ${J}
125
+ ORDER BY run_id DESC, question_id
126
+ LIMIT 500
127
+ `;if($.length===0)return B("No results for this strategy",404);let F=$.map((Y)=>({questionId:String(Y.question_id),question:Y.question?String(Y.question):null,strategy:String(Y.strategy),judgeScore:Number(Y.judge_score??0),latencyMs:Number(Y.latency_ms??0),costCents:Number(Y.cost_cents??0),hitAtK:Boolean(Y.hit_at_k),reciprocalRank:Number(Y.judge_score??0)>=0.7?1:0,domainPattern:Y.domain_pattern?String(Y.domain_pattern):null}));return x({strategy:J,questions:F})}var n=new Set;function bJ(){let J=new ReadableStream({start(X){n.add(X),X.enqueue(new TextEncoder().encode(`data: ${JSON.stringify({type:"heartbeat"})}
128
+
129
+ `))},cancel(X){n.delete(X)}});return new Response(J,{headers:{...A,"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}function hJ(){return x(f)}function gJ(){return x({status:"ok",service:"brain-lab",timestamp:new Date().toISOString()})}var pJ={".html":"text/html",".css":"text/css",".js":"text/javascript",".json":"application/json",".png":"image/png",".svg":"image/svg+xml",".ico":"image/x-icon"};function o(){let J=j(import.meta.dir,"../../dist/bench-ui");if(a(J))return J;return j(import.meta.dir,"ui")}async function i(J){let X=o(),Z=j(X,J);if(!Z.startsWith(X))return null;let $=Bun.file(Z);if(!await $.exists())return null;let F=kJ(Z),Y=pJ[F]??"application/octet-stream";return new Response($,{headers:{...A,"Content-Type":Y}})}async function mJ(J){let X=new URL(J.url),Z=X.pathname;if(J.method==="OPTIONS")return new Response(null,{headers:A});try{if(Z==="/api/health")return gJ();if(Z==="/api/params")return hJ();if(Z==="/api/events")return bJ();if(Z==="/api/leaderboard")return await fJ();if(Z==="/api/runs"&&!X.pathname.includes("/api/runs/"))return await DJ();let $=Z.match(/^\/api\/runs\/by-strategy\/([^/]+)\/questions$/);if($)return await wJ(decodeURIComponent($[1]));let F=Z.match(/^\/api\/runs\/([^/]+)\/questions$/);if(F)return await vJ(F[1]);let Y=Z.match(/^\/api\/runs\/([^/]+)\/metrics$/);if(Y)return await SJ(Y[1]);let W=Z.match(/^\/api\/runs\/([^/]+)$/);if(W)return await IJ(W[1]);if(Z==="/api/compare"){let V=X.searchParams.get("ids")?.split(",")??[];return await yJ(V)}if(Z==="/"||Z==="/index.html"){let V=await i("index.html");if(V)return V}if(Z.startsWith("/css/")||Z.startsWith("/js/")||Z.startsWith("/vendor/")){let V=await i(Z.slice(1));if(V)return V}return B("Not found",404)}catch($){let F=$ instanceof Error?$.message:String($);return console.error(`[brain-lab] Error: ${F}`),B(F,500)}}function s(J={}){let X=J.port??3847,Z=Bun.serve({port:X,fetch:mJ}),$=`http://localhost:${Z.port}`,F=o(),Y=a(j(F,"index.html"));if(console.log(`
130
+ Brain Lab running at ${$}
131
+ `),Y)console.log(" Dashboard: /");return console.log(" API:"),console.log(" GET /api/leaderboard \u2014 strategy rankings + BrainScore + Pareto"),console.log(" GET /api/runs \u2014 list experiment runs"),console.log(" GET /api/compare \u2014 side-by-side comparison"),console.log(" GET /api/params \u2014 tunable parameters"),console.log(" GET /api/events \u2014 SSE live progress"),console.log(""),{port:Z.port??X,stop:()=>Z.stop(),url:$}}function uJ(){let J=process.argv.slice(2),X={port:3847,open:!1,help:!1};for(let Z=0;Z<J.length;Z++){let $=J[Z];switch($){case"--help":case"-h":X.help=!0;break;case"--port":case"-p":{let F=J[++Z],Y=Number(F);if(!F||Number.isNaN(Y))console.error("--port requires a number"),process.exit(1);X.port=Y;break}case"--open":case"-o":X.open=!0;break;default:if($==="--dashboard")break;console.error(`Unknown argument: ${$}`),e(),process.exit(1)}}return X}function e(){console.log(`
132
+ Brain Lab \u2014 Benchmark Dashboard
133
+
134
+ Usage: brain-bench [options]
135
+
136
+ Options:
137
+ --port, -p N Server port (default: 3847)
138
+ --open, -o Open browser after starting
139
+ --help, -h Show this help
140
+
141
+ Examples:
142
+ brain-bench # Start on default port
143
+ brain-bench --port 4000 # Custom port
144
+ brain-bench --open # Start and open browser
145
+ `)}var k=uJ();if(k.help)e(),process.exit(0);var{url:t}=s({port:k.port});if(k.open)try{let{exec:J}=await import("child_process"),X=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";J(`${X} ${t}`)}catch{console.log(`Open ${t} in your browser`)}console.log(`Press Ctrl+C to stop.
146
+ `);