UNPKG

cntx-ui

Version:

File context management tool with web UI and MCP server for AI development workflows - bundle project files for LLM consumption

2 lines (1 loc) 7.06 kB
class u{constructor(e="http://localhost:3333/api/heuristics/config"){this.configUrl=e,this.config=null,this.cache=new Map,this.lastLoaded=null,this.loadPromise=null}async loadConfig(){return this.loadPromise?this.loadPromise:(this.loadPromise=this._loadConfigInternal(),this.loadPromise)}async _loadConfigInternal(){try{const e=await fetch(this.configUrl);if(!e.ok){if(e.status===404){console.warn("Heuristics config not found at API, using fallback"),this.config=this.getFallbackConfig();return}throw new Error(`HTTP ${e.status}: ${e.statusText}`)}const t=await e.json();this.validateConfig(t),this.config=t,this.lastLoaded=Date.now(),this.cache.clear(),console.log("✅ Heuristics configuration loaded successfully")}catch(e){console.error("❌ Failed to load heuristics config:",e.message),console.log("📦 Falling back to hardcoded heuristics"),this.config=this.getFallbackConfig()}finally{this.loadPromise=null}}validateConfig(e){const t=["purposeHeuristics","bundleHeuristics","semanticTypeMapping"];for(const a of t)if(!e[a])throw new Error(`Missing required field: ${a}`);if(!e.purposeHeuristics.patterns||!e.purposeHeuristics.fallback)throw new Error("Invalid purposeHeuristics structure");if(!e.bundleHeuristics.patterns||!e.bundleHeuristics.fallback)throw new Error("Invalid bundleHeuristics structure")}async getConfig(){return this.config||await this.loadConfig(),this.config}async determinePurpose(e){const t=await this.getConfig(),a=e.name.toLowerCase();for(const[s,n]of Object.entries(t.purposeHeuristics.patterns))if(this.evaluateConditions(n.conditions,{func:e,name:a}))return n.purpose;return t.purposeHeuristics.fallback.purpose}async suggestBundlesForFile(e){const t=await this.getConfig(),a=e.toLowerCase(),s=a.split("/"),n=[];for(const[r,c]of Object.entries(t.bundleHeuristics.patterns))if(this.evaluateConditions(c.conditions,{fileName:a,filePath:e,pathParts:s})&&(n.push(c.bundle),c.subPatterns))for(const[i,o]of Object.entries(c.subPatterns))this.evaluateConditions(o.conditions,{fileName:a,filePath:e,pathParts:s})&&n.push(o.bundle);if(n.length===0){const r=t.bundleHeuristics.fallback;r.webFallback&&this.evaluateConditions(r.webFallback.conditions,{fileName:a,filePath:e,pathParts:s})?n.push(r.webFallback.bundle):r.defaultFallback&&n.push(...r.defaultFallback.bundles)}return[...new Set(n)]}async getSemanticTypeMapping(){const e=await this.getConfig(),t={};for(const[a,s]of Object.entries(e.semanticTypeMapping.clusters))for(const n of s.types)t[n]=s.clusterId;return t}evaluateConditions(e,t){return Array.isArray(e)||(e=[e]),this.requiresAndLogic(e)?e.every(s=>{try{return this.evaluateCondition(s,t)}catch(n){return console.warn(`Failed to evaluate condition: ${s}`,n),!1}}):e.some(s=>{try{return this.evaluateCondition(s,t)}catch(n){return console.warn(`Failed to evaluate condition: ${s}`,n),!1}})}requiresAndLogic(e){return!!(e.length===2&&e.some(t=>t.includes("name.startsWith"))&&e.some(t=>t.includes("func.type"))||e.length===2&&e.some(t=>t.includes("pathParts.includes('web')"))&&e.some(t=>t.includes("pathParts.includes('src')")))}evaluateCondition(e,t){const{func:a,name:s,fileName:n,filePath:r,pathParts:c}=t;if(e.includes("func.type ===")){const i=e.match(/func\.type === ['"]([^'"]+)['"]/);if(i&&a)return a.type===i[1]}if(e.includes("name.startsWith(")){const i=e.match(/name\.startsWith\(['"]([^'"]+)['"]\)/);if(i&&s)return s.startsWith(i[1])}if(e.includes("name.includes(")){const i=e.match(/name\.includes\(['"]([^'"]+)['"]\)/);if(i&&s)return s.includes(i[1])}if(e.includes("fileName.includes(")){const i=e.match(/fileName\.includes\(['"]([^'"]+)['"]\)/);if(i&&n)return n.includes(i[1])}if(e.includes("fileName.endsWith(")){const i=e.match(/fileName\.endsWith\(['"]([^'"]+)['"]\)/);if(i&&n)return n.endsWith(i[1])}if(e.includes("pathParts.includes(")){const i=e.match(/pathParts\.includes\(['"]([^'"]+)['"]\)/);if(i&&c)return c.includes(i[1])}return!1}getFallbackConfig(){return{version:"1.0.0",purposeHeuristics:{patterns:{reactComponent:{conditions:["func.type === 'react_component'"],purpose:"React component",confidence:.95},reactHook:{conditions:["name.startsWith('use')","func.type === 'function'"],purpose:"React hook",confidence:.9},apiHandler:{conditions:["name.includes('api')","name.includes('endpoint')"],purpose:"API handler",confidence:.85},dataRetrieval:{conditions:["name.includes('get')","name.includes('fetch')"],purpose:"Data retrieval",confidence:.8},dataCreation:{conditions:["name.includes('create')","name.includes('add')"],purpose:"Data creation",confidence:.8},dataModification:{conditions:["name.includes('update')","name.includes('edit')"],purpose:"Data modification",confidence:.8},dataDeletion:{conditions:["name.includes('delete')","name.includes('remove')"],purpose:"Data deletion",confidence:.8},validation:{conditions:["name.includes('validate')","name.includes('check')"],purpose:"Validation",confidence:.75},dataProcessing:{conditions:["name.includes('parse')","name.includes('format')"],purpose:"Data processing",confidence:.75}},fallback:{purpose:"Utility function",confidence:.5}},bundleHeuristics:{patterns:{frontend:{conditions:["pathParts.includes('web')","pathParts.includes('src')"],bundle:"frontend",confidence:.8,subPatterns:{uiComponents:{conditions:["pathParts.includes('components')"],bundle:"ui-components",confidence:.9}}},server:{conditions:["fileName.includes('server')","fileName.includes('api')","pathParts.includes('bin')"],bundle:"server",confidence:.85},configuration:{conditions:["fileName.includes('config')","fileName.includes('setup')","fileName.endsWith('.json')","fileName.endsWith('.sh')","fileName.includes('package')"],bundle:"config",confidence:.9},documentation:{conditions:["fileName.endsWith('.md')","fileName.includes('doc')","fileName.includes('readme')"],bundle:"docs",confidence:.95}},fallback:{webFallback:{conditions:["pathParts.includes('web')"],bundle:"frontend",confidence:.6},defaultFallback:{bundles:["server","config"],confidence:.4}}},semanticTypeMapping:{clusters:{businessLogic:{types:["business_logic","algorithm"],clusterId:0},dataLayer:{types:["data_processing","database"],clusterId:1},apiLayer:{types:["api_integration","middleware","routing"],clusterId:2},uiLayer:{types:["ui_component","page_component","layout_component","hook"],clusterId:3},utilities:{types:["utility","configuration","function","type_definition"],clusterId:4},testing:{types:["testing","documentation","monitoring"],clusterId:5},infrastructure:{types:["error_handling","performance","security"],clusterId:6},unknown:{types:["unknown"],clusterId:7}}}}}async updateConfig(e){this.validateConfig(e);try{const t=await fetch(this.configUrl,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);return this.config=e,this.cache.clear(),this.lastLoaded=Date.now(),!0}catch(t){throw console.error("Failed to update heuristics config:",t.message),t}}getPerformanceMetrics(){return{totalEvaluations:0,accuracyScore:0,lastUpdated:this.lastLoaded}}}export{u as default};