toolnet-memory 0.2.16 → 0.2.18

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/bundle/mcp.js CHANGED
@@ -1,7 +1,50 @@
1
- import"dotenv/config";import{existsSync as br,readFileSync as Sr}from"node:fs";import{homedir as Er}from"node:os";import{join as Cr}from"node:path";function xr(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function vr(){let r=process.env.TOOLNET_GLOBAL_ENV??Cr(Er(),".config","toolnet-memory",".env");if(!br(r))return;let e=Sr(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let s=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=xr(o.slice(n+1)))}}vr();function D(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function F(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function qe(){return{memory:{autoCapture:D(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:D(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:D(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:D(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:F(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:F(process.env.MEMORY_RERANK_TOP,10),finalContext:F(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:F(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:D(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:F(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}var wr={critical:100,high:75,normal:50,temporary:20};function He(r){return wr[r]}function Ve(r,e){let t=e.toLowerCase();return t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c")||t.includes("must not")||t.includes("critical")?"critical":r==="rule"||r==="decision"?"high":r==="todo"?"normal":r==="activity"||r==="summary"?"temporary":"normal"}import{createHash as Pr}from"node:crypto";import{existsSync as Me,mkdirSync as Ar,readFileSync as Rr,renameSync as Lr,writeFileSync as jr}from"node:fs";import{basename as Mr,dirname as Y,join as Q,parse as Je,resolve as K}from"node:path";var Qe=".toolnet",Tr="project.json";function Ir(r){return Pr("sha256").update(r).digest("hex").slice(0,16)}function Te(r){return Q(r,Qe,Tr)}function _r(r){return Me(Te(r))}function kr(r,e){let t=K(r),o=Je(t).root;for(;;){if(_r(t))return t;if(t===o||e&&t===K(e))break;let n=Y(t);if(n===t)break;t=n}return null}function Nr(r){let e=K(r),t=Je(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(s=>Me(Q(e,s))))return e;if(e===t)break;let n=Y(e);if(n===e)break;e=n}return K(r)}function Or(r){let e;try{e=JSON.parse(Rr(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let o=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:Y(Y(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function We(r,e){let t=Q(r,Qe);Ar(t,{recursive:!0});let o=Te(r),n=`${o}.tmp-${process.pid}`;jr(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Lr(n,o)}function Ye(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var J=class{detect(e=process.cwd()){let t=K(e),o=Nr(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>Me(Q(o,d))),i=kr(t,s?o:void 0);if(i){let d=Te(i),f=Or(d);return f.rootPath!==i&&(f.rootPath=i,f.updatedAt=new Date().toISOString(),We(i,f)),Ye(f,i)}let a=new Date().toISOString(),c=Mr(o),l={version:1,id:Ir(o),name:c,remote:c,rootPath:o,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return We(o,l),Ye(l,o)}};import{randomUUID as zr}from"node:crypto";var Dr=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],Z=class{scan(e){let t=[];for(let o of Dr){let n=new RegExp(o.regex.source,o.regex.flags);for(let s of e.matchAll(n))t.push({type:o.type,value:s[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var k=class{scanner=new Z;sanitize(e){let t=e,o=this.scanner.scan(e),n=new Set;for(let s of o)n.add(s.type),t=t.split(s.value).join(`[REDACTED:${s.type}]`);return{text:t,redacted:o.length,secretTypes:[...n]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[o,n]of Object.entries(e)){let s=o.toLowerCase();s.includes("password")||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")?t[o]="[REDACTED]":t[o]=this.sanitizeValue(n)}return t}return e}};var Fr=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),Kr=new Set(["d\xF9ng","s\u1EED","d\u1EE5ng","use","using","the","a","an","cho","v\xE0","l\xE0","c\u1EE7a","to","for","with","quy\u1EBFt","\u0111\u1ECBnh"]);function Ze(r){return new Set(r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!Kr.has(e)))}function Gr(r,e){let t=Ze(r),o=Ze(e);if(t.size===0||o.size===0)return 0;let n=0;for(let i of t)o.has(i)&&n++;let s=new Set([...t,...o]).size;return n/s}function Xe(r){return new Set(r.tags.filter(e=>!Fr.has(e.toLowerCase())))}var X=class{findSuperseded(e,t){if(e.type!=="rule"&&e.type!=="decision")return[];let o=typeof e.metadata?.topic=="string"?e.metadata.topic:void 0,n=Xe(e);return t.filter(s=>{if(s.id===e.id||s.projectId!==e.projectId||s.type!==e.type||s.metadata?.supersededBy)return!1;let i=typeof s.metadata?.topic=="string"?s.metadata.topic:void 0;if(o&&i&&o===i)return!0;let a=Xe(s);for(let c of n)if(a.has(c))return!0;return Gr(e.content,s.content)>=.6})}};var $r={critical:100,high:75,normal:50,temporary:20},Ur={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function et(r,e,t=new Date){let o;if(e==="temporary"&&(o=30),r==="activity"&&(o=Math.min(o??14,14)),r==="summary"&&(o=Math.min(o??30,30)),!!o)return new Date(t.getTime()+o*864e5).toISOString()}function Ie(r,e=Date.now()){return r.expiresAt?new Date(r.expiresAt).getTime()<=e:!1}function Br(r){return!!r.metadata?.supersededBy}function _e(r,e=Date.now()){return!Ie(r,e)&&!Br(r)}function G(r,e=Date.now()){if(!_e(r,e))return 0;let t=$r[r.importance];if(r.importance==="critical")return t;let o=Ur[r.type]??180,s=Math.max(0,e-new Date(r.updatedAt).getTime())/864e5,i=Math.pow(.5,s/o);return t*i}var ee=class{memories=new Map;sanitizer=new k;conflicts=new X;remember(e){let t=new Date().toISOString(),o=this.sanitizer.sanitize(e.content.trim()).text,n=e.importance??Ve(e.type,o),s={id:zr(),projectId:e.projectId,type:e.type,content:o,importance:n,importanceScore:He(n),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??et(e.type,n,new Date(t)),metadata:this.sanitizer.sanitizeValue(e.metadata)},i=this.conflicts.findSuperseded(s,this.list(e.projectId));if(i.length){s.metadata={...s.metadata??{},supersedes:i.map(a=>a.id)};for(let a of i)a.updatedAt=t,a.metadata={...a.metadata??{},supersededBy:s.id,supersededAt:t},this.memories.set(a.id,a)}return this.memories.set(s.id,s),s}importRecords(e){let t=0;for(let o of e)o?.id&&(this.memories.set(o.id,o),t++);return t}exportProject(e){return this.listAll(e)}get(e){return this.memories.get(e)}delete(e){return this.memories.delete(e)}listAll(e){return[...this.memories.values()].filter(t=>t.projectId===e).sort((t,o)=>o.createdAt.localeCompare(t.createdAt))}list(e){return this.listAll(e).filter(t=>_e(t))}recent(e,t=10){return this.list(e).slice(0,t)}byType(e,t){return this.list(e).filter(o=>o.type===t)}search(e){let t=e.query.trim().toLowerCase(),o=e.limit??10,n=t.split(/\s+/).filter(Boolean);return this.list(e.projectId).filter(s=>{if(e.types&&!e.types.includes(s.type))return!1;let i=G(s);return!(e.minImportanceScore&&i<e.minImportanceScore||e.tags?.length&&!e.tags.some(c=>s.tags.includes(c)))}).map(s=>{let i=s.content.toLowerCase(),a=n.filter(d=>i.includes(d)).length,c=n.length===0?0:a/n.length,l=G(s)/500;return{memory:s,score:c+l,source:"memory"}}).filter(s=>t.length===0||s.score>0).sort((s,i)=>i.score-s.score).slice(0,o)}pruneExpired(e,t=Date.now()){let o=0;for(let[n,s]of this.memories)s.projectId===e&&Ie(s,t)&&(this.memories.delete(n),o++);return o}pruneSuperseded(e,t=30,o=Date.now()){let n=0,s=t*864e5;for(let[i,a]of this.memories){if(a.projectId!==e)continue;let c=a.metadata?.supersededAt;if(typeof c!="string")continue;o-new Date(c).getTime()>=s&&(this.memories.delete(i),n++)}return n}clearProject(e){let t=0;for(let[o,n]of this.memories)n.projectId===e&&(this.memories.delete(o),t++);return t}};function N(r){return r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}var te=class{score(e,t){let o=N(e),n=N([t.content,...t.tags??[],t.type].join(" "));if(o.length===0||n.length===0)return 0;let s=new Map;for(let a of n)s.set(a,(s.get(a)??0)+1);let i=0;for(let a of o){let c=s.get(a)??0;c!==0&&(i+=1+Math.log(1+c))}return i/o.length}};function tt(r,e=Date.now()){let t=r.updatedAt??r.createdAt,o=new Date(t).getTime();if(!Number.isFinite(o))return 0;let n=Math.max(0,e-o)/864e5;return Math.exp(-Math.LN2*n/30)}function rt(r){return G(r)/100}var qr={rule:1,decision:.9,todo:.8,summary:.6,activity:.3};function ot(r){return qr[r]??.4}var re=class{analyze(e){let t=e.toLowerCase(),o=[];return(t.includes("quy\u1EBFt \u0111\u1ECBnh")||t.includes("decision")||t.includes("\u0111\xE3 ch\u1ECDn"))&&o.push("decision"),(t.includes("todo")||t.includes("c\u1EA7n l\xE0m")||t.includes("ti\u1EBFp theo")||t.includes("ch\u01B0a xong"))&&o.push("todo"),(t.includes("quy t\u1EAFc")||t.includes("rule")||t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c"))&&o.push("rule"),(t.includes("t\xF3m t\u1EAFt")||t.includes("summary")||t.includes("\u0111\xE3 l\xE0m"))&&o.push("summary"),{query:e,preferredTypes:o}}};var oe=class{bm25=new te;analyzer=new re;search(e,t,o={}){let n=o.topK??8,s=o.minScore??.05,i=this.analyzer.analyze(e),a=[];for(let c of t){if(o.types?.length&&!o.types.includes(c.type))continue;let l=this.bm25.score(e,c),d=tt(c),f=rt(c),m=ot(c.type);i.preferredTypes.includes(c.type)&&(m=Math.min(1,m+.25));let u=l*.55+f*.2+d*.15+m*.1;l<=0||u<s||a.push({memory:c,score:u,scores:{keyword:l,recency:d,importance:f,type:m}})}return a.sort((c,l)=>l.score-c.score).slice(0,n)}};var ne=class{build(e,t=6e3){let o=[],n=0;for(let s of e){let i=s.memory,a=[`[${i.type.toUpperCase()}]`,i.content].join(" ");if(n+a.length>t)break;o.push(a),n+=a.length}return o.join(`
4
- `)}};var se=class{constructor(e){this.memory=e}memory;searcher=new oe;contextBuilder=new ne;search(e,t,o={}){return this.searcher.search(t,this.memory.list(e),o)}context(e,t,o={}){let n=this.search(e,t,o);return this.contextBuilder.build(n)}};var nt=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function ie(r){let e=nt.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function ae(r){return nt.some(e=>e.id===r)}function p(r){return process.env[r]?.trim()||void 0}function h(...r){return r.find(e=>!!e?.trim())}function st(){if(p("GROQ_API_KEY"))return"groq";if(p("DEEPSEEK_API_KEY"))return"deepseek";if(p("NVIDIA_API_KEY")||p("NVIDIA_NIM_API_KEY"))return"nvidia";if(p("OPENROUTER_API_KEY"))return"openrouter";if(p("ALIBABA_API_KEY")||p("DASHSCOPE_API_KEY"))return"alibaba";if(p("GEMINI_API_KEY")||p("GOOGLE_API_KEY"))return"gemini";if(p("CLOUDFLARE_API_TOKEN")&&p("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(p("HF_TOKEN"))return"huggingface";if(p("OLLAMA_MODEL")||p("OLLAMA_BASE_URL"))return"ollama"}function Hr(){let r=p("TOOLNET_LLM_PROVIDER");return r&&ae(r)?r:st()??"openai-compatible"}function ke(r){let e=ie(r);switch(r){case"alibaba":return{provider:r,apiKey:h(p("ALIBABA_API_KEY"),p("DASHSCOPE_API_KEY")),baseUrl:h(p("ALIBABA_BASE_URL"),p("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:h(p("ALIBABA_MODEL"),p("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:p("OPENROUTER_API_KEY"),baseUrl:h(p("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:p("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:p("GROQ_API_KEY"),baseUrl:h(p("GROQ_BASE_URL"),e.defaultBaseUrl),model:p("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:p("DEEPSEEK_API_KEY"),baseUrl:h(p("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:h(p("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:h(p("NVIDIA_API_KEY"),p("NVIDIA_NIM_API_KEY")),baseUrl:h(p("NVIDIA_BASE_URL"),p("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:h(p("NVIDIA_MODEL"),p("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:h(p("GEMINI_API_KEY"),p("GOOGLE_API_KEY")),baseUrl:h(p("GEMINI_BASE_URL"),e.defaultBaseUrl),model:p("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:p("HF_TOKEN"),baseUrl:h(p("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:h(p("HF_LLM_MODEL"),p("HF_MODEL"))};case"ollama":return{provider:r,apiKey:p("OLLAMA_API_KEY"),baseUrl:h(p("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:p("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:p("CLOUDFLARE_ACCOUNT_ID"),apiKey:p("CLOUDFLARE_API_TOKEN"),baseUrl:p("CLOUDFLARE_AI_BASE_URL"),model:p("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:p("CUSTOM_AI_API_KEY"),baseUrl:p("CUSTOM_AI_BASE_URL"),model:p("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:h(p("OPENAI_API_KEY"),p("MODEL_API_KEY")),baseUrl:h(p("OPENAI_BASE_URL"),p("MODEL_BASE_URL")),model:h(p("OPENAI_MODEL"),p("MODEL_NAME"))}}}function Vr(){let r=p("TOOLNET_LLM_PROVIDER"),e=r&&ae(r)?r:Hr(),t=ie(e),o=ke(e);return{provider:e,apiKey:h(p("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:h(p("TOOLNET_LLM_BASE_URL"),o.baseUrl,t.defaultBaseUrl),model:h(p("TOOLNET_LLM_MODEL"),o.model,t.defaultModel),accountId:h(p("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function Wr(){let r=p("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&ae(r)?r:p("HF_TOKEN")||p("HF_EMBEDDING_MODEL")?"huggingface":"local"}function Yr(){let r=Wr();if(r==="local")return{provider:"local",model:h(p("TOOLNET_EMBEDDING_MODEL"),p("LOCAL_EMBEDDING_MODEL"))};let e=ie(r),t,o,n,s;switch(r){case"huggingface":t=p("HF_TOKEN"),o=p("HF_INFERENCE_BASE_URL"),n=p("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=p("OPENAI_API_KEY"),o=p("OPENAI_BASE_URL"),n=p("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=p("CLOUDFLARE_API_TOKEN"),o=p("CLOUDFLARE_AI_BASE_URL"),n=p("CLOUDFLARE_EMBEDDING_MODEL"),s=p("CLOUDFLARE_ACCOUNT_ID");break;default:t=ke(r).apiKey,o=ke(r).baseUrl,n=p(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let i=h(p("TOOLNET_EMBEDDING_ACCOUNT_ID"),s),a=h(p("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),c=r==="cloudflare"&&!a&&i?`https://api.cloudflare.com/client/v4/accounts/${i}/ai/v1`:a;return{provider:r,apiKey:h(p("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:c,model:h(p("TOOLNET_EMBEDDING_MODEL"),n),accountId:i}}function it(){let r=Vr(),e=Yr();return{llm:r,embedding:e,legacy:{llm:!p("TOOLNET_LLM_PROVIDER")&&!!st(),embedding:!p("TOOLNET_EMBEDDING_PROVIDER")&&!!(p("HF_TOKEN")||p("HF_EMBEDDING_MODEL"))}}}var ce=class{constructor(e){this.options=e}options;name="gemini";async embed(e){let t=this.options.model.replace(/^models\//,""),n=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(t)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,s=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${t}`,content:{parts:[{text:e}]}})});if(!s.ok)throw new Error(`Gemini embedding failed: ${s.status} ${await s.text()}`);let a=(await s.json()).embedding?.values;if(!Array.isArray(a)||a.length===0)throw new Error("Gemini embedding returned invalid response");return a}async embedMany(e){let t=[];for(let o of e)t.push(await this.embed(o));return t}};import{createHash as Jr}from"node:crypto";var le=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),o=e.toLowerCase().split(/\s+/).filter(Boolean);for(let n of o){let i=Jr("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return Qr(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function Qr(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var de=class{constructor(e){this.options=e;this.dimensions=e.dimensions}options;name="openai-compatible";dimensions;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=this.options.baseUrl.replace(/\/+$/,""),o=await fetch(`${t}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:e})});if(!o.ok)throw new Error(`Embedding failed: ${o.status} ${await o.text()}`);let s=(await o.json()).data?.sort((i,a)=>(i.index??0)-(a.index??0)).map(i=>i.embedding);if(!s||s.length!==e.length||s.some(i=>!Array.isArray(i)))throw new Error("Embedding provider returned invalid response");return s}};var pe=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,o=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!o.ok)throw new Error(`HF embedding failed: ${o.status} ${await o.text()}`);let n=await o.json();if(!Array.isArray(n))throw new Error("HF embedding returned invalid response");return n.map(s=>Zr(s))}};function Zr(r){if(!Array.isArray(r))throw new Error("Invalid embedding");if(r.length>0&&typeof r[0]=="number")return r;if(r.length>0&&Array.isArray(r[0])){let e=r;if(e.length===0)return[];let t=e[0].length,o=new Array(t).fill(0);for(let n of e)for(let s=0;s<t;s++)o[s]+=n[s]??0;for(let n=0;n<t;n++)o[n]/=e.length;return o}throw new Error("Unsupported embedding shape")}var Ne=class{constructor(e,t=new le){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function Xr(r){return`https://api.cloudflare.com/client/v4/accounts/${r}/ai/v1`}function eo(){let r=it().embedding;if(r.provider==="local")return null;if(r.provider==="huggingface")return!r.apiKey||!r.model?null:new pe({token:r.apiKey,model:r.model});if(r.provider==="gemini")return!r.apiKey||!r.model?null:new ce({apiKey:r.apiKey,model:r.model,baseUrl:r.baseUrl});let e=r.baseUrl;return r.provider==="cloudflare"&&!e&&r.accountId&&(e=Xr(r.accountId)),e&&r.model?new de({apiKey:r.apiKey,baseUrl:e,model:r.model}):null}function at(){return new Ne(eo())}import*as C from"typescript";var O=class{symbols=new Map;edges=new Map;addSymbol(e){this.symbols.set(e.id,e)}addEdge(e){this.edges.set(e.id,e)}getSymbol(e){return this.symbols.get(e)}findByName(e,t){return[...this.symbols.values()].filter(o=>o.projectId===e&&(o.name===t||o.qualifiedName===t))}allSymbols(e){return[...this.symbols.values()].filter(t=>t.projectId===e)}allEdges(e){return[...this.edges.values()].filter(t=>t.projectId===e)}import(e,t){for(let o of e)this.addSymbol(o);for(let o of t)this.addEdge(o)}clearProject(e){for(let[t,o]of this.symbols)o.projectId===e&&this.symbols.delete(t);for(let[t,o]of this.edges)o.projectId===e&&this.edges.delete(t)}};function me(r,e){let t=r.allSymbols(e),o=r.allEdges(e),n=i=>t.filter(a=>a.type===i).length,s=i=>o.filter(a=>a.type===i).length;return{files:n("file"),classes:n("class"),interfaces:n("interface"),functions:n("function"),methods:n("method"),properties:n("property"),routes:n("route"),symbols:t.length,edges:o.length,calls:s("CALLS"),callReferences:s("CALL_REFERENCE"),imports:s("IMPORTS"),inherits:s("INHERITS"),implements:s("IMPLEMENTS"),usesType:s("USES_TYPE"),tests:s("TESTS"),routeEdges:s("ROUTE"),writes:s("WRITES")}}var fe=class{constructor(e){this.graph=e}graph;callees(e,t,o=3){return this.walk(e,t,"out",o)}callers(e,t,o=3){return this.walk(e,t,"in",o)}walk(e,t,o,n){let s=[],i=new Set([t]),a=[{id:t,depth:0}],c=this.graph.allEdges(e).filter(l=>l.type==="CALLS"||l.type==="CALL_REFERENCE");for(;a.length;){let l=a.shift();if(l.depth>=n)continue;let d=o==="out"?c.filter(f=>f.from===l.id):c.filter(f=>f.to===l.id);for(let f of d){let m=o==="out"?f.to:f.from;if(i.has(m))continue;i.add(m);let u=this.graph.getSymbol(m);if(!u)continue;let b=l.depth+1;s.push({symbol:u,depth:b}),a.push({id:m,depth:b})}}return s}};var ue=class{constructor(e){this.graph=e}graph;findSymbol(e,t){return this.graph.findByName(e,t)}findCallers(e,t){return this.graph.allEdges(e).filter(n=>n.type==="CALLS"&&n.to===t).map(n=>n.from).map(n=>this.graph.getSymbol(n)).filter(n=>!!n)}};var ge=class{constructor(e){this.graph=e}graph;analyze(e,t,o=4){let n=this.graph.allEdges(e),s=new Set([t]),i=[{id:t,depth:0}],a=[];for(;i.length;){let c=i.shift();if(c.depth>=o)continue;let l=n.filter(d=>d.to===c.id&&["CALLS","IMPORTS","INHERITS","IMPLEMENTS"].includes(d.type));for(let d of l){if(s.has(d.from))continue;s.add(d.from);let f=this.graph.getSymbol(d.from);if(!f)continue;let m=c.depth+1;a.push({symbol:f,depth:m,relation:d.type}),i.push({id:d.from,depth:m})}}return a}};function no(r,e){return e.ranges.length===0?!0:typeof r.startLine!="number"||typeof r.endLine!="number"?!1:e.ranges.some(t=>r.startLine<=t.endLine&&r.endLine>=t.startLine)}var he=class{constructor(e){this.graph=e}graph;map(e,t){let o=this.graph.allSymbols(e),n=[];for(let s of t){let i=o.filter(l=>l.filePath===s.filePath),c=i.filter(l=>l.type!=="file").filter(l=>no(l,s));if(c.length===0){let l=i.find(d=>d.type==="file");l&&n.push({symbol:l,fileStatus:s.status,direct:!0});continue}for(let l of c)n.push({symbol:l,fileStatus:s.status,direct:!0})}return n}mapFile(e,t){return this.map(e,[{filePath:t,status:"modified",ranges:[]}])}};var so={CALLS:4,CALL_REFERENCE:6,USES_TYPE:4,TESTS:2,ROUTE:4,WRITES:3,IMPORTS:3,INHERITS:5,IMPLEMENTS:5,DEFINES:1};function io(r){return r>=30?"CRITICAL":r>=16?"HIGH":r>=6?"MEDIUM":"LOW"}function ct(r){let e=r.toLowerCase().replaceAll("\\","/");return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}var ye=class{constructor(e){this.graph=e}graph;analyze(e,t,o=4){let n=this.graph.allEdges(e),s=new Map,i=0;for(let d of t){d.fileStatus==="deleted"?i+=8:d.fileStatus==="renamed"?i+=5:i+=2,d.symbol.type==="interface"&&(i+=5),d.symbol.type==="class"&&(i+=3);let f=new Set([d.symbol.id]),m=[{id:d.symbol.id,depth:0}];for(;m.length;){let u=m.shift();if(u.depth>=o)continue;let b=n.filter(S=>S.to===u.id&&["CALLS","CALL_REFERENCE","USES_TYPE","TESTS","ROUTE","WRITES","IMPORTS","INHERITS","IMPLEMENTS","DEFINES"].includes(S.type));for(let S of b){if(f.has(S.from))continue;f.add(S.from);let A=this.graph.getSymbol(S.from);if(!A)continue;let R=u.depth+1,W=`${d.symbol.id}:${A.id}`;s.set(W,{symbol:A,relation:S.type,depth:R,sourceSymbolId:d.symbol.id});let T=so[S.type]??1;i+=Math.max(1,T-(R-1)),m.push({id:A.id,depth:R})}}}let a=[...s.values()].sort((d,f)=>d.depth-f.depth),c=[...new Set(a.map(d=>d.symbol.filePath))],l=c.filter(ct);return l.length===0&&l.push(...c.filter(d=>!ct(d)).slice(0,10)),{risk:io(i),riskScore:i,changedSymbols:t,impacted:a,impactedFiles:c,suggestedTests:l}}};import{execFile as ao}from"node:child_process";import{promisify as co}from"node:util";var Oe=co(ao);function lo(r){let e=[],t=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm;for(let o of r.matchAll(t)){let n=Number(o[1]),s=Number(o[2]??1);e.push({startLine:n,endLine:Math.max(n,n+s-1)})}return e}function po(r){return r.startsWith("A")?"added":r.startsWith("D")?"deleted":r.startsWith("R")?"renamed":"modified"}async function lt(r){let e="";try{e=(await Oe("git",["diff","HEAD","--name-status","--no-renames"],{cwd:r,maxBuffer:10485760})).stdout}catch{return[]}let t=[];for(let o of e.split(/\r?\n/).filter(Boolean)){let[n,...s]=o.split(" "),i=s.at(-1);if(!i)continue;let a="";try{a=(await Oe("git",["diff","HEAD","--unified=0","--",i],{cwd:r,maxBuffer:20971520})).stdout}catch{a=""}t.push({filePath:i,status:po(n),ranges:lo(a)})}try{let o=await Oe("git",["ls-files","--others","--exclude-standard"],{cwd:r});for(let n of o.stdout.split(/\r?\n/).filter(Boolean))t.some(s=>s.filePath===n)||t.push({filePath:n,status:"added",ranges:[]})}catch{}return t}var be=class{constructor(e){this.graph=e;this.mapper=new he(e),this.blast=new ye(e)}graph;mapper;blast;async analyzeGitDiff(e,t,o={}){let n=await lt(t),s=this.mapper.map(e,n),i=this.blast.analyze(e,s,o.maxDepth??4);return{mode:"git_diff",changes:n,...i}}analyzeFile(e,t,o={}){let n=this.mapper.mapFile(e,t);return{mode:"planned_file",filePath:t,...this.blast.analyze(e,n,o.maxDepth??4)}}};var $=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};import{createHash as mo}from"node:crypto";import{readFile as fo}from"node:fs/promises";import{join as uo}from"node:path";function dt(r){return mo("sha256").update(r).digest("hex")}var Se=class{sanitizer=new k;async build(e,t,o,n={}){let s=n.maxLines??80,i=n.overlapLines??10,a=new Map;for(let l of o){let d=a.get(l.filePath)??[];d.push(l),a.set(l.filePath,d)}let c=[];for(let[l,d]of a){let f;try{f=await fo(uo(t,l),"utf8")}catch{continue}let m=f.split(/\r?\n/),u=d.filter(b=>b.type!=="file"&&typeof b.startLine=="number"&&typeof b.endLine=="number");if(u.length>0)for(let b of u)c.push(...this.chunkRange({projectId:e,filePath:l,lines:m,symbol:b,startLine:b.startLine,endLine:b.endLine,maxLines:s,overlapLines:i}));else c.push(...this.chunkRange({projectId:e,filePath:l,lines:m,startLine:1,endLine:Math.max(1,m.length),maxLines:s,overlapLines:i}))}return c}chunkRange(e){let{projectId:t,filePath:o,lines:n,symbol:s,maxLines:i}=e,a=Math.min(e.overlapLines,Math.max(0,i-1)),c=Math.max(1,e.startLine),l=Math.min(n.length,Math.max(c,e.endLine)),d=[],f=c,m=0;for(;f<=l;){let u=Math.min(l,f+i-1),b=n.slice(f-1,u).join(`
5
- `).trim();if(b){let S=this.sanitizer.sanitize(b).text,A=dt(S),R=[t,o,s?.id??"file",String(m),A].join(":");d.push({id:dt(R).slice(0,32),projectId:t,filePath:o,symbolId:s?.id,symbolName:s?.qualifiedName??s?.name,symbolType:s?.type,startLine:f,endLine:u,content:S,contentHash:A})}if(u>=l)break;f=u-a+1,m++}return d}};var Ee=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var Ce=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var xe=class{records=new Map;upsert(e){this.records.set(e.id,e)}get(e){return this.records.get(e)}has(e){return this.records.has(e)}remove(e){return this.records.delete(e)}clearProject(e){let t=0;for(let[o,n]of this.records)n.projectId===e&&(this.records.delete(o),t++);return t}exportProject(e){return[...this.records.values()].filter(t=>t.projectId===e)}importRecords(e){let t=0;for(let o of e)!o?.id||!o?.projectId||!Array.isArray(o.vector)||(this.records.set(o.id,o),t++);return t}search(e,t,o=10){let n=[];for(let s of this.records.values()){if(s.projectId!==e)continue;let i=go(t,s.vector);n.push({id:s.id,score:i,metadata:s.metadata})}return n.sort((s,i)=>i.score-s.score).slice(0,o)}size(){return this.records.size}};function go(r,e){if(r.length===0||e.length===0||r.length!==e.length)return 0;let t=0,o=0,n=0;for(let s=0;s<r.length;s++){let i=r[s]??0,a=e[s]??0;t+=i*a,o+=i*i,n+=a*a}return o===0||n===0?0:t/(Math.sqrt(o)*Math.sqrt(n))}function pt(r,e){let t=r.toLowerCase().replaceAll("\\","/"),o=e.toLowerCase(),n=/\b(test|tests|spec|fixture|mock)\b/.test(o);return(t.startsWith("tests/")||t.includes("/tests/")||t.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(t))&&!n?.35:t.includes("/generated/")||t.includes(".generated.")?.25:1}var ve=class{constructor(e){this.options=e}options;vectors=new xe;chunks=new Map;async initialize(){let{projectId:e,rootPath:t,storage:o,embeddings:n,graph:s,model:i}=this.options,a=new Ee(o),c=new Ce(o),l=await new Se().build(e,t,s.allSymbols(e));this.chunks.clear();for(let E of l)this.chunks.set(E.id,E);let d=await a.load(e),f=!d||d.chunks.length!==l.length||d.chunks.some(E=>!this.chunks.has(E.id));f&&await a.save({version:1,projectId:e,updatedAt:new Date().toISOString(),chunks:l});let m=await c.load(e),u=0;m&&m.model===i&&(u=this.vectors.importRecords(m.records));let b=new Set(l.map(E=>E.id)),S=0;for(let E of this.vectors.exportProject(e))b.has(E.id)||this.vectors.remove(E.id)&&S++;let A=l.filter(E=>{let I=this.vectors.get(E.id);return I?I.metadata?.contentHash!==E.contentHash:!0}),R=0,W=8,T=this.vectors.exportProject(e)[0]?.vector.length;for(let E=0;E<A.length;E+=W){let I=A.slice(E,E+W),hr=I.map(P=>[`file: ${P.filePath}`,P.symbolName?`symbol: ${P.symbolName}`:"",P.symbolType?`type: ${P.symbolType}`:"",P.content].filter(Boolean).join(`
6
- `)),yr=await n.embedMany(hr);for(let P=0;P<I.length;P++){let j=I[P],_=yr[P];if(!(!j||!_||_.length===0)){if(T===void 0&&(T=_.length),_.length!==T){console.warn(`[code-semantic] skip dimension mismatch: ${_.length} != ${T}`);continue}this.vectors.upsert({id:j.id,projectId:e,vector:_,metadata:{contentHash:j.contentHash,filePath:j.filePath,symbolName:j.symbolName,symbolType:j.symbolType,startLine:j.startLine,endLine:j.endLine}}),R++}}}let je=this.vectors.exportProject(e),ze=R>0||S>0||!m||m.model!==i;return ze&&await c.save({version:1,projectId:e,model:i,dimensions:je[0]?.vector.length??T??0,updatedAt:new Date().toISOString(),records:je}),{chunks:l.length,vectorsLoaded:u,vectorsIndexed:R,vectorsRemoved:S,totalVectors:je.length,savedChunks:f,savedVectors:ze}}async search(e,t=8){let o=await this.options.embeddings.embed(e),n=this.vectors.search(this.options.projectId,o,Math.max(t*4,20)),s=new Set(N(e)),i=[];for(let a of n){let c=this.chunks.get(a.id);if(!c)continue;let l=new Set(N([c.filePath,c.symbolName??"",c.symbolType??"",c.content].join(" "))),d=0;for(let S of s)l.has(S)&&d++;let f=s.size===0?0:d/s.size,m=Math.max(0,a.score),u=pt(c.filePath,e),b=(m*.75+f*.25)*u;i.push({chunk:c,score:b,vectorScore:m,lexicalScore:f})}return i.sort((a,c)=>c.score-a.score).slice(0,t)}size(){return this.chunks.size}};import*as x from"typescript";import*as g from"typescript";var Yi=new Set([g.SyntaxKind.EqualsToken,g.SyntaxKind.PlusEqualsToken,g.SyntaxKind.MinusEqualsToken,g.SyntaxKind.AsteriskEqualsToken,g.SyntaxKind.SlashEqualsToken,g.SyntaxKind.PercentEqualsToken,g.SyntaxKind.QuestionQuestionEqualsToken,g.SyntaxKind.AmpersandAmpersandEqualsToken,g.SyntaxKind.BarBarEqualsToken]);function ho(r){return r.replaceAll("\\","/").toLowerCase()}var U=class{constructor(e){this.graph=e}graph;detect(e){let t=this.graph.allSymbols(e),o=this.graph.allEdges(e),n=[];for(let i of t){if(i.type!=="route"&&i.type!=="file")continue;let a=this.classify(i,o);a&&n.push({symbolId:i.id,filePath:i.filePath,name:i.name,kind:a.kind,score:a.score,reasons:a.reasons})}let s=new Map;for(let i of n){let a=i.kind==="route"?i.symbolId:i.filePath,c=s.get(a);(!c||i.score>c.score)&&s.set(a,i)}return[...s.values()].sort((i,a)=>a.score-i.score||i.filePath.localeCompare(a.filePath))}classify(e,t){let o=ho(e.filePath),n=[];if(e.type==="route")return{kind:"route",score:100,reasons:["HTTP route"]};let s=null,i=0;if(o.startsWith("bin/"))s="cli",i=100,n.push("bin executable");else if(/(^|\/)(cli)\.[^.]+$/.test(o))s="cli",i=90,n.push("CLI entry file");else if(/(^|\/)(main|server)\.[^.]+$/.test(o))s="main",i=90,n.push("main/server file");else if(o.includes("/runtime/")&&/(^|\/)(bootstrap|index)\.[^.]+$/.test(o))s="runtime",i=75,n.push("runtime bootstrap");else if(/(^|\/)index\.[^.]+$/.test(o)){let c=t.filter(d=>d.to===e.id&&d.type!=="DEFINES").length,l=t.filter(d=>d.from===e.id&&d.type!=="DEFINES").length;(o.startsWith("packages/")||c===0||l>0)&&(s="package",i=o.startsWith("packages/")?70:55,n.push("package/public index"))}return s?(t.filter(c=>c.to===e.id&&c.type!=="DEFINES").length===0&&(i+=10,n.push("no incoming dependency")),{kind:s,score:i,reasons:n}):null}};var we=new Set(["CALLS","CALL_REFERENCE","IMPORTS","USES_TYPE","WRITES","INHERITS","IMPLEMENTS","ROUTE"]),mt=new Set(["CALLS","CALL_REFERENCE"]),w=class{constructor(e){this.graph=e}graph;findSymbols(e,t){let o=t.trim().toLowerCase();return o?this.graph.allSymbols(e).filter(n=>n.name.toLowerCase().includes(o)||(n.qualifiedName?.toLowerCase().includes(o)??!1)||n.filePath.toLowerCase().includes(o)).sort((n,s)=>{let i=n.name.toLowerCase()===o,a=s.name.toLowerCase()===o;return i!==a?i?-1:1:n.filePath.localeCompare(s.filePath)}):[]}callers(e,t){return this.relatedIncoming(e,t,mt)}callees(e,t){return this.relatedOutgoing(e,t,mt)}dependents(e,t){return this.relatedIncoming(e,t,we)}dependencies(e,t){return this.relatedOutgoing(e,t,we)}neighborhood(e,t,o=1){let n=this.graph.getSymbol(t);return!n||n.projectId!==e?null:{center:n,incoming:this.walk(e,t,"incoming",o),outgoing:this.walk(e,t,"outgoing",o)}}shortestPath(e,t,o,n=12){let s=this.graph.getSymbol(t),i=this.graph.getSymbol(o);if(!s||!i||s.projectId!==e||i.projectId!==e)return{found:!1,distance:-1,symbols:[],edges:[]};if(t===o)return{found:!0,distance:0,symbols:[s],edges:[]};let a=this.graph.allEdges(e).filter(m=>we.has(m.type)),c=new Map;for(let m of a){let u=c.get(m.from)??[];u.push(m),c.set(m.from,u)}let l=[{id:t,depth:0}],d=new Set([t]),f=new Map;for(;l.length>0;){let m=l.shift();if(!(m.depth>=n)){for(let u of c.get(m.id)??[])if(!d.has(u.to)){if(d.add(u.to),f.set(u.to,{node:m.id,edge:u}),u.to===o)return this.buildPath(t,o,f);l.push({id:u.to,depth:m.depth+1})}}}return{found:!1,distance:-1,symbols:[],edges:[]}}buildPath(e,t,o){let n=[t],s=[],i=t;for(;i!==e;){let c=o.get(i);if(!c)return{found:!1,distance:-1,symbols:[],edges:[]};s.push(c.edge),i=c.node,n.push(i)}n.reverse(),s.reverse();let a=n.map(c=>this.graph.getSymbol(c)).filter(c=>!!c);return{found:!0,distance:s.length,symbols:a,edges:s}}walk(e,t,o,n){let s=this.graph.allEdges(e).filter(l=>we.has(l.type)),i=[{id:t,depth:0}],a=new Set([t]),c=[];for(;i.length>0;){let l=i.shift();if(!(l.depth>=n))for(let d of s){if(!(o==="incoming"?d.to===l.id:d.from===l.id))continue;let m=o==="incoming"?d.from:d.to;if(a.has(m))continue;let u=this.graph.getSymbol(m);u&&(a.add(m),c.push({symbol:u,depth:l.depth+1,via:d}),i.push({id:m,depth:l.depth+1}))}}return c}relatedIncoming(e,t,o){return[...new Set(this.graph.allEdges(e).filter(s=>s.to===t&&o.has(s.type)).map(s=>s.from))].map(s=>this.graph.getSymbol(s)).filter(s=>!!s)}relatedOutgoing(e,t,o){return[...new Set(this.graph.allEdges(e).filter(s=>s.from===t&&o.has(s.type)).map(s=>s.to))].map(s=>this.graph.getSymbol(s)).filter(s=>!!s)}};var ft=new Set(["CALLS","CALL_REFERENCE","IMPORTS","USES_TYPE","WRITES","INHERITS","IMPLEMENTS","ROUTE","TESTS"]);function De(r){return r.replaceAll("\\","/").toLowerCase()}function yo(r){let e=De(r);return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}function bo(r){let e=De(r.filePath);return e.startsWith("bin/")||/(^|\/)index\.[^.]+$/.test(e)||/(^|\/)(main|server|cli)\.[^.]+$/.test(e)}var B=class{constructor(e){this.graph=e}graph;analyze(e){let t=this.graph.allSymbols(e),o=this.graph.allEdges(e),n=new Set(new U(this.graph).detect(e).map(i=>i.symbolId)),s=[];for(let i of t){if(!["function","method","class","interface","property"].includes(i.type)||yo(i.filePath)||n.has(i.id)||bo(i)||o.filter(u=>u.to===i.id&&ft.has(u.type)).length>0)continue;let c=o.filter(u=>u.from===i.id&&ft.has(u.type)),l=["no incoming usage edge"],d=50;(i.type==="function"||i.type==="method")&&(d+=20,l.push("callable symbol")),i.type==="property"&&(d-=15),c.length===0&&(d+=10,l.push("no outgoing dependency")),De(i.filePath).includes("/internal/")&&(d+=10,l.push("internal implementation")),i.name.startsWith("_")&&(d+=5);let m=d>=75?"high":d>=55?"medium":"low";s.push({symbolId:i.id,name:i.name,qualifiedName:i.qualifiedName,type:i.type,filePath:i.filePath,startLine:i.startLine,confidence:m,score:d,reasons:l})}return s.sort((i,a)=>a.score-i.score||i.filePath.localeCompare(a.filePath)||i.name.localeCompare(a.name))}};var So=new Set(["CALLS","CALL_REFERENCE","IMPORTS","USES_TYPE","WRITES","INHERITS","IMPLEMENTS","ROUTE"]),z=class{constructor(e){this.graph=e}graph;analyze(e){let t=this.graph.allSymbols(e),o=this.graph.allEdges(e).filter(i=>So.has(i.type)),n=new Map(t.map(i=>[i.id,i]));return[...new Set(t.map(i=>i.filePath))].sort().map(i=>{let a=new Set,c=new Set,l=0,d=0;for(let f of o){let m=n.get(f.from),u=n.get(f.to);!m||!u||m.filePath===u.filePath||(m.filePath===i&&(a.add(u.filePath),l++),u.filePath===i&&(c.add(m.filePath),d++))}return{filePath:i,dependencies:[...a].sort(),dependents:[...c].sort(),outgoingEdges:l,incomingEdges:d}})}};import{homedir as Uo}from"node:os";import{join as Bo}from"node:path";import{DeleteObjectCommand as Eo,GetObjectCommand as Co,HeadObjectCommand as xo,ListObjectsV2Command as vo,PutObjectCommand as wo,S3Client as Po}from"@aws-sdk/client-s3";import{getSignedUrl as Ao}from"@aws-sdk/s3-request-presigner";var Pe=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Po({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new wo({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Ao(this.client,new Co({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new xo({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Eo({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new vo({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as ut,mkdir as Ro,readFile as Lo,readdir as jo,rm as Mo,stat as gt,writeFile as To}from"node:fs/promises";import{dirname as Io,join as _o,relative as ht,resolve as ko}from"node:path";var q=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ko(this.root,t)}async put(e,t){let o=this.path(e);await Ro(Io(o),{recursive:!0}),await To(o,t)}async get(e){try{return await Lo(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await ut(this.path(e)),!0}catch{return!1}}async delete(e){await Mo(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ut(t)}catch{return o}let n=async i=>{let a=await jo(i,{withFileTypes:!0});for(let c of a){let l=_o(i,c.name);if(c.isDirectory()){await n(l);continue}let d=await gt(l);o.push({key:ht(this.root,l),size:d.size,updatedAt:d.mtime.toISOString()})}},s=await gt(t);return s.isDirectory()?await n(t):o.push({key:ht(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),o}};import{DeleteObjectCommand as No,GetObjectCommand as Oo,HeadObjectCommand as Do,ListObjectsV2Command as Fo,PutObjectCommand as Ko,S3Client as Go}from"@aws-sdk/client-s3";import{getSignedUrl as $o}from"@aws-sdk/s3-request-presigner";var H=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Go({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ko({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await $o(this.client,new Oo({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`${this.name} download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Do({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new No({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Fo({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};function Fe(r,e){return console.warn(e),new q(r)}function yt(r){let e=r.localRoot??Bo(Uo(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new H({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Fe(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new H({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Fe(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new Pe({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Fe(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new q(e)}var Ae=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};function zo(r){return new Promise(e=>setTimeout(e,r))}async function bt(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await r()}catch(a){if(s=a,i>=t)break;let c=Math.min(n,o*2**(i-1)),l=Math.floor(Math.random()*Math.max(1,c*.2));await zo(c+l)}throw s}var qo=new Set(["put","get","getText","delete","list"]);function St(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:qo.has(o)?(...s)=>bt(()=>Promise.resolve(n.apply(t,s)),e):n.bind(t)}})}function Et(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Ct(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var Re=class{constructor(e,t,o,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=Et(n??o),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),o=t,n=await this.provider.getText(e);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(o=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
7
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Ct(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{McpServer as Xo}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as en}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as xt}from"zod";var vt={query:xt.string(),limit:xt.number().int().min(1).max(20).optional()};async function wt(r,e){return r.retrieval.search(r.project.id,e.query,{topK:e.limit??8}).map(o=>({id:o.memory.id,type:o.memory.type,content:o.memory.content,importance:o.memory.importance,score:o.score,tags:o.memory.tags}))}import{z as V}from"zod";var Pt={type:V.enum(["activity","decision","rule","todo","summary"]),content:V.string().min(1),tags:V.array(V.string()).optional(),importance:V.enum(["critical","high","normal","temporary"]).optional()};async function At(r,e){let t=r.memory.remember({projectId:r.project.id,type:e.type,content:e.content,tags:e.tags,importance:e.importance,source:"mcp"});return r.memoryStore&&await r.memoryStore.save(r.project.id,r.memory.exportProject(r.project.id)),t}import{z as Ho}from"zod";var Rt={id:Ho.string().min(1)};async function Lt(r,e){let t=r.memory.delete(e.id);return t&&r.memoryStore&&await r.memoryStore.save(r.project.id,r.memory.exportProject(r.project.id)),{deleted:t}}import{z as Vo}from"zod";var jt={name:Vo.string().min(1)};async function Mt(r,e){return r.graph.findByName(r.project.id,e.name)}import{z as Wo}from"zod";function L(r,e){let t=r.graph.getSymbol(e);if(t&&t.projectId===r.project.id)return t;let o=new w(r.graph),n=o.findSymbols(r.project.id,e).find(s=>s.name===e||s.qualifiedName===e);return n||(o.findSymbols(r.project.id,e)[0]??null)}function v(r){return{id:r.id,name:r.name,qualifiedName:r.qualifiedName,type:r.type,filePath:r.filePath,startLine:r.startLine,endLine:r.endLine}}var Tt={symbolId:Wo.string().min(1)};async function It(r,e){let t=L(r,e.symbolId);if(!t)return{found:!1,query:e.symbolId,callers:[]};let n=new w(r.graph).callers(r.project.id,t.id);return{found:!0,symbol:v(t),count:n.length,callers:n.map(v)}}import{z as _t}from"zod";var kt={query:_t.string().min(1),limit:_t.number().int().min(1).max(50).optional()};async function Nt(r,e){let t=e.query.toLowerCase(),o=e.limit??20;return r.graph.allSymbols(r.project.id).filter(n=>n.name.toLowerCase().includes(t)||n.qualifiedName?.toLowerCase().includes(t)||n.filePath.toLowerCase().includes(t)).slice(0,o)}import{z as Ot}from"zod";var Dt={query:Ot.string().optional(),memoryLimit:Ot.number().int().min(1).max(20).optional()};async function Ft(r,e){let t=me(r.graph,r.project.id),o=r.memory.recent(r.project.id,5),n=e.query?r.retrieval.search(r.project.id,e.query,{topK:e.memoryLimit??5}):[];return{project:{id:r.project.id,name:r.project.name,rootPath:r.project.rootPath},architecture:t,recent:o,relevant:n.map(s=>s.memory)}}import{z as Jo}from"zod";var Yo=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],M=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),s=n.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,s),c=[];for(let d of Yo){let f=`${i}/${d}`,m=await this.storage.get(f);m&&(await this.storage.put(`${a}/${d}`,m,"application/json"),c.push(d))}if(c.length===0)return null;let l={version:1,id:s,projectId:e,createdAt:n,reason:t,objects:c,metadata:o};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(l,null,2),"application/json"),l}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),s=[];for(let i of n){let a=await this.storage.getText(i.key);if(a)try{s.push(JSON.parse(a))}catch{}}return s.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let s=JSON.parse(n);if(s.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of s.objects){let l=await this.storage.get(`${o}/${c}`);l&&(await this.storage.put(`${i}/${c}`,l,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let s of n)await this.storage.delete(s.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),s=0;for(let i of n)await this.remove(e,i.id),s++;return s}};var Kt={reason:Jo.string().optional()};async function Gt(r,e){if(!r.storage)throw new Error("Storage unavailable");return new M(r.storage).create(r.project.id,e.reason??"manual-mcp")}async function $t(r){if(!r.storage)throw new Error("Storage unavailable");return new M(r.storage).list(r.project.id)}import{z as Qo}from"zod";var Ut={snapshotId:Qo.string().min(1)};async function Bt(r,e){if(!r.storage)throw new Error("Storage unavailable");let t=new M(r.storage);return await t.create(r.project.id,"before-rollback"),t.restore(r.project.id,e.snapshotId)}import{z as Ke}from"zod";var zt={symbolId:Ke.string().min(1),direction:Ke.enum(["callers","callees"]).optional(),depth:Ke.number().int().min(1).max(10).optional()};async function qt(r,e){let t=new fe(r.graph),o=e.direction??"callees",n=e.depth??3,s=o==="callers"?t.callers(r.project.id,e.symbolId,n):t.callees(r.project.id,e.symbolId,n);return{direction:o,depth:n,results:s.map(i=>({id:i.symbol.id,name:i.symbol.name,qualifiedName:i.symbol.qualifiedName,type:i.symbol.type,filePath:i.symbol.filePath,depth:i.depth}))}}import{z as Ht}from"zod";var Vt={symbolId:Ht.string().min(1),depth:Ht.number().int().min(1).max(10).optional()};async function Wt(r,e){let t=r.graph.getSymbol(e.symbolId);if(!t)return{found:!1,impacts:[]};let n=new ge(r.graph).analyze(r.project.id,t.id,e.depth??4);return{found:!0,target:{id:t.id,name:t.name,qualifiedName:t.qualifiedName,filePath:t.filePath,type:t.type},impacts:n.map(s=>({id:s.symbol.id,name:s.symbol.name,qualifiedName:s.symbol.qualifiedName,filePath:s.symbol.filePath,type:s.symbol.type,relation:s.relation,depth:s.depth}))}}async function Yt(r){return{project:{id:r.project.id,name:r.project.name,rootPath:r.project.rootPath},architecture:me(r.graph,r.project.id)}}import{z as Jt}from"zod";var Qt={filePath:Jt.string().min(1),direction:Jt.enum(["dependencies","dependents","both"]).optional()};async function Zt(r,e){let o=new z(r.graph).analyze(r.project.id).find(c=>c.filePath===e.filePath);if(!o)return{found:!1,filePath:e.filePath,dependencies:[],dependents:[]};let n=r.graph.allSymbols(r.project.id).filter(c=>c.type==="file"),s=new Map(n.map(c=>[c.filePath,c])),i=c=>({id:s.get(c)?.id??c,filePath:c}),a=e.direction??"both";return{found:!0,filePath:o.filePath,outgoingEdges:o.outgoingEdges,incomingEdges:o.incomingEdges,dependencies:a==="dependents"?[]:o.dependencies.map(i),dependents:a==="dependencies"?[]:o.dependents.map(i)}}import{z as Xt}from"zod";var er={query:Xt.string().min(1),limit:Xt.number().int().min(1).max(20).optional()};async function tr(r,e){return r.codeSemantic?{available:!0,results:(await r.codeSemantic.search(e.query,e.limit??8)).map(o=>({id:o.chunk.id,filePath:o.chunk.filePath,symbol:o.chunk.symbolName,symbolType:o.chunk.symbolType,startLine:o.chunk.startLine,endLine:o.chunk.endLine,score:o.score,vectorScore:o.vectorScore,lexicalScore:o.lexicalScore,content:o.chunk.content}))}:{available:!1,results:[]}}import{z as Ge}from"zod";var rr={mode:Ge.enum(["git_diff","file"]).optional(),filePath:Ge.string().optional(),depth:Ge.number().int().min(1).max(10).optional()};async function or(r,e){let t=new be(r.graph);if((e.mode??(e.filePath?"file":"git_diff"))==="file"){if(!e.filePath)throw new Error("filePath is required when mode=file");return t.analyzeFile(r.project.id,e.filePath,{maxDepth:e.depth})}return t.analyzeGitDiff(r.project.id,r.project.rootPath,{maxDepth:e.depth})}import{z as Zo}from"zod";var nr={symbol:Zo.string().min(1)};async function sr(r,e){let t=L(r,e.symbol);if(!t)return{found:!1,query:e.symbol,dependents:[]};let n=new w(r.graph).dependents(r.project.id,t.id);return{found:!0,symbol:v(t),count:n.length,dependents:n.map(v)}}import{z as $e}from"zod";var ir={from:$e.string().min(1),to:$e.string().min(1),maxDepth:$e.number().int().min(1).max(30).optional()};async function ar(r,e){let t=L(r,e.from),o=L(r,e.to);if(!t||!o)return{found:!1,fromFound:!!t,toFound:!!o,path:[],edges:[]};let s=new w(r.graph).shortestPath(r.project.id,t.id,o.id,e.maxDepth??12);return{found:s.found,distance:s.distance,from:v(t),to:v(o),path:s.symbols.map(v),edges:s.edges.map(i=>({id:i.id,type:i.type,from:i.from,to:i.to,metadata:i.metadata}))}}import{z as Ue}from"zod";var cr={symbol:Ue.string().min(1),depth:Ue.number().int().min(1).max(5).optional(),limit:Ue.number().int().min(1).max(200).optional()};async function lr(r,e){let t=L(r,e.symbol);if(!t)return{found:!1,query:e.symbol};let n=new w(r.graph).neighborhood(r.project.id,t.id,e.depth??1);if(!n)return{found:!1,query:e.symbol};let s=e.limit??50;return{found:!0,center:v(n.center),incomingCount:n.incoming.length,outgoingCount:n.outgoing.length,incoming:n.incoming.slice(0,s).map(i=>({depth:i.depth,via:i.via?.type,symbol:v(i.symbol)})),outgoing:n.outgoing.slice(0,s).map(i=>({depth:i.depth,via:i.via?.type,symbol:v(i.symbol)}))}}import{z as Be}from"zod";var pr={confidence:Be.enum(["high","medium","low","all"]).optional(),filePath:Be.string().min(1).optional(),limit:Be.number().int().min(1).max(500).optional()},dr={high:3,medium:2,low:1};async function mr(r,e){let o=new B(r.graph).analyze(r.project.id);if(e.confidence&&e.confidence!=="all"){let i=dr[e.confidence];o=o.filter(a=>dr[a.confidence]>=i)}e.filePath&&(o=o.filter(i=>i.filePath===e.filePath));let n=o.length,s=e.limit??100;return{total:n,high:o.filter(i=>i.confidence==="high").length,medium:o.filter(i=>i.confidence==="medium").length,low:o.filter(i=>i.confidence==="low").length,warning:"Dead-code results are candidates only. Verify before deleting code.",candidates:o.slice(0,s)}}function y(r){return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}function tn(r){let e=new Xo({name:"toolnet-memory",version:"0.1.0"});return e.tool("memory_search","Search relevant long-term memory for the current project.",vt,async t=>y(await wt(r,t))),e.tool("memory_save","Save an important memory, decision, rule, TODO or summary.",Pt,async t=>y(await At(r,t))),e.tool("memory_forget","Delete a memory by id.",Rt,async t=>y(await Lt(r,t))),e.tool("find_symbol","Find code symbols by exact name.",jt,async t=>y(await Mt(r,t))),e.tool("find_callers","Find functions or methods calling a symbol.",Tt,async t=>y(await It(r,t))),e.tool("code_search","Search indexed code symbols and files.",kt,async t=>y(await Nt(r,t))),e.tool("project_context","Get compact project architecture, recent memory and relevant context.",Dt,async t=>y(await Ft(r,t))),e.tool("trace_calls","Trace callers or callees through the code call graph.",zt,async t=>y(await qt(r,t))),e.tool("analyze_impact","Analyze what code can be affected if a symbol changes.",Vt,async t=>y(await Wt(r,t))),e.tool("get_architecture","Get compact architecture statistics for the indexed project.",{},async()=>y(await Yt(r))),e.tool("find_dependencies","Find direct file dependencies and reverse dependents.",Qt,async t=>y(await Zt(r,t))),e.tool("semantic_code_search","Search source code by semantic meaning, not only exact symbol names.",er,async t=>y(await tr(r,t))),e.tool("snapshot_create","Create a safe versioned snapshot of project memory, vectors and graph.",Kt,async t=>y(await Gt(r,t))),e.tool("snapshot_list","List available ToolNet Memory snapshots.",{},async()=>y(await $t(r))),e.tool("snapshot_restore","Restore a previous ToolNet Memory snapshot. A safety snapshot is created first.",Ut,async t=>y(await Bt(r,t))),e.tool("impact_guard","Analyze blast radius before or after code changes. Maps changed files/lines to symbols, follows reverse dependencies, assigns risk and suggests verification targets.",rr,async t=>y(await or(r,t))),e.tool("graph_dependents","Find code symbols that depend on a symbol through calls, imports, type usage, writes, inheritance or implementation relationships.",nr,async t=>y(await sr(r,t))),e.tool("graph_path","Find the shortest dependency path between two code symbols.",ir,async t=>y(await ar(r,t))),e.tool("graph_neighborhood","Explore incoming and outgoing dependency relationships around a code symbol.",cr,async t=>y(await lr(r,t))),e.tool("dead_code","Find likely unused code. Results are candidates and must be verified before deletion.",pr,async t=>y(await mr(r,t))),e}async function fr(r){let e=tn(r),t=new en;await e.connect(t)}import{closeSync as rn,mkdirSync as on,openSync as nn,readFileSync as sn,unlinkSync as ur,writeFileSync as an}from"node:fs";import{tmpdir as cn}from"node:os";import{join as gr}from"node:path";function ln(r){try{return process.kill(r,0),!0}catch(e){return e?.code==="EPERM"}}var Le=class{acquired=!1;path;exitHandler=()=>{this.releaseSync()};constructor(e){let t=gr(cn(),"toolnet-memory-locks");on(t,{recursive:!0});let o=e.replace(/[^A-Za-z0-9_.-]/g,"_");this.path=gr(t,`${o}.lock`)}async acquire(){if(!this.acquired){for(let e=0;e<2;e++)try{let t=nn(this.path,"wx");an(t,JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()})),rn(t),this.acquired=!0,process.once("exit",this.exitHandler);return}catch(t){if(t?.code!=="EEXIST")throw t;let o=!0;try{let n=JSON.parse(sn(this.path,"utf8"));Number.isInteger(n.pid)&&ln(n.pid)&&(o=!1)}catch{o=!0}if(!o)throw new Error("ToolNet Memory is already running for this project");try{ur(this.path)}catch{}}throw new Error("Unable to acquire ToolNet Memory project lock")}}async release(){this.releaseSync()}releaseSync(){if(this.acquired){try{ur(this.path)}catch{}this.acquired=!1,process.off("exit",this.exitHandler)}}};async function dn(){let r=qe(),e=new J().detect(),t=yt({provider:r.storage.provider,huggingface:r.storage.huggingface,localRoot:r.storage.localRoot}),o=St(t,{attempts:Number(process.env.TOOLNET_STORAGE_RETRIES??3)}),n=new Re(o,e.id,e.name,e.remote??e.name),s=new Le(e.id);await s.acquire();let i=()=>{s.release().finally(()=>process.exit(0))};process.once("SIGINT",i),process.once("SIGTERM",i);let a=new ee,c=new Ae(n);a.importRecords(await c.load(e.id));let l=new se(a),d=new O,f=await new $(n).load(e.id);f&&d.import(f.symbols,f.edges);let m=new ue(d),u=new ve({projectId:e.id,rootPath:e.rootPath,model:process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",storage:n,embeddings:at(),graph:d});await u.initialize(),await fr({project:e,memory:a,retrieval:l,graph:d,references:m,codeSemantic:u,memoryStore:c,storage:n})}dn().catch(r=>{console.error(r),process.exit(1)});
1
+ import"dotenv/config";import{existsSync as Gr,readFileSync as Ur}from"node:fs";import{homedir as Br}from"node:os";import{join as zr}from"node:path";function qr(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Wr(){let r=process.env.TOOLNET_GLOBAL_ENV??zr(Br(),".config","toolnet-memory",".env");if(!Gr(r))return;let e=Ur(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let i=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=qr(o.slice(n+1)))}}Wr();function F(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function K(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function nt(){return{memory:{autoCapture:F(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:F(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:F(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:F(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:K(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:K(process.env.MEMORY_RERANK_TOP,10),finalContext:K(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:K(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:F(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:K(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}var Hr={critical:100,high:75,normal:50,temporary:20};function st(r){return Hr[r]}function it(r,e){let t=e.toLowerCase();return t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c")||t.includes("must not")||t.includes("critical")?"critical":r==="rule"||r==="decision"?"high":r==="todo"?"normal":r==="activity"||r==="summary"?"temporary":"normal"}import{createHash as Vr}from"node:crypto";import{existsSync as Be,mkdirSync as Yr,readFileSync as Jr,renameSync as Qr,writeFileSync as Zr}from"node:fs";import{basename as Xr,dirname as re,join as ne,parse as lt,resolve as G}from"node:path";var dt=".toolnet",eo="project.json";function to(r){return Vr("sha256").update(r).digest("hex").slice(0,16)}function ze(r){return ne(r,dt,eo)}function ro(r){return Be(ze(r))}function oo(r,e){let t=G(r),o=lt(t).root;for(;;){if(ro(t))return t;if(t===o||e&&t===G(e))break;let n=re(t);if(n===t)break;t=n}return null}function no(r){let e=G(r),t=lt(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>Be(ne(e,i))))return e;if(e===t)break;let n=re(e);if(n===e)break;e=n}return G(r)}function so(r){let e;try{e=JSON.parse(Jr(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let o=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:re(re(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function at(r,e){let t=ne(r,dt);Yr(t,{recursive:!0});let o=ze(r),n=`${o}.tmp-${process.pid}`;Zr(n,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Qr(n,o)}function ct(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var oe=class{detect(e=process.cwd()){let t=G(e),o=no(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>Be(ne(o,l))),s=oo(t,i?o:void 0);if(s){let l=ze(s),u=so(l);return u.rootPath!==s&&(u.rootPath=s,u.updatedAt=new Date().toISOString(),at(s,u)),ct(u,s)}let a=new Date().toISOString(),c=Xr(o),d={version:1,id:to(o),name:c,remote:c,rootPath:o,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return at(o,d),ct(d,o)}};import{randomUUID as fo}from"node:crypto";var io=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],se=class{scan(e){let t=[];for(let o of io){let n=new RegExp(o.regex.source,o.regex.flags);for(let i of e.matchAll(n))t.push({type:o.type,value:i[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var N=class{scanner=new se;sanitize(e){let t=e,o=this.scanner.scan(e),n=new Set;for(let i of o)n.add(i.type),t=t.split(i.value).join(`[REDACTED:${i.type}]`);return{text:t,redacted:o.length,secretTypes:[...n]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[o,n]of Object.entries(e)){let i=o.toLowerCase();i.includes("password")||i.includes("secret")||i.includes("token")||i.includes("cookie")||i.includes("authorization")?t[o]="[REDACTED]":t[o]=this.sanitizeValue(n)}return t}return e}};var ao=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),co=new Set(["d\xF9ng","s\u1EED","d\u1EE5ng","use","using","the","a","an","cho","v\xE0","l\xE0","c\u1EE7a","to","for","with","quy\u1EBFt","\u0111\u1ECBnh"]);function pt(r){return new Set(r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!co.has(e)))}function lo(r,e){let t=pt(r),o=pt(e);if(t.size===0||o.size===0)return 0;let n=0;for(let s of t)o.has(s)&&n++;let i=new Set([...t,...o]).size;return n/i}function mt(r){return new Set(r.tags.filter(e=>!ao.has(e.toLowerCase())))}var ie=class{findSuperseded(e,t){if(e.type!=="rule"&&e.type!=="decision")return[];let o=typeof e.metadata?.topic=="string"?e.metadata.topic:void 0,n=mt(e);return t.filter(i=>{if(i.id===e.id||i.projectId!==e.projectId||i.type!==e.type||i.metadata?.supersededBy)return!1;let s=typeof i.metadata?.topic=="string"?i.metadata.topic:void 0;if(o&&s&&o===s)return!0;let a=mt(i);for(let c of n)if(a.has(c))return!0;return lo(e.content,i.content)>=.6})}};var po={critical:100,high:75,normal:50,temporary:20},mo={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function ut(r,e,t=new Date){let o;if(e==="temporary"&&(o=30),r==="activity"&&(o=Math.min(o??14,14)),r==="summary"&&(o=Math.min(o??30,30)),!!o)return new Date(t.getTime()+o*864e5).toISOString()}function qe(r,e=Date.now()){return r.expiresAt?new Date(r.expiresAt).getTime()<=e:!1}function uo(r){return!!r.metadata?.supersededBy}function We(r,e=Date.now()){return!qe(r,e)&&!uo(r)}function U(r,e=Date.now()){if(!We(r,e))return 0;let t=po[r.importance];if(r.importance==="critical")return t;let o=mo[r.type]??180,i=Math.max(0,e-new Date(r.updatedAt).getTime())/864e5,s=Math.pow(.5,i/o);return t*s}var ae=class{memories=new Map;sanitizer=new N;conflicts=new ie;remember(e){let t=new Date().toISOString(),o=this.sanitizer.sanitize(e.content.trim()).text,n=e.importance??it(e.type,o),i={id:fo(),projectId:e.projectId,type:e.type,content:o,importance:n,importanceScore:st(n),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??ut(e.type,n,new Date(t)),metadata:this.sanitizer.sanitizeValue(e.metadata)},s=this.conflicts.findSuperseded(i,this.list(e.projectId));if(s.length){i.metadata={...i.metadata??{},supersedes:s.map(a=>a.id)};for(let a of s)a.updatedAt=t,a.metadata={...a.metadata??{},supersededBy:i.id,supersededAt:t},this.memories.set(a.id,a)}return this.memories.set(i.id,i),i}importRecords(e){let t=0;for(let o of e)o?.id&&(this.memories.set(o.id,o),t++);return t}exportProject(e){return this.listAll(e)}get(e){return this.memories.get(e)}delete(e){return this.memories.delete(e)}listAll(e){return[...this.memories.values()].filter(t=>t.projectId===e).sort((t,o)=>o.createdAt.localeCompare(t.createdAt))}list(e){return this.listAll(e).filter(t=>We(t))}recent(e,t=10){return this.list(e).slice(0,t)}byType(e,t){return this.list(e).filter(o=>o.type===t)}search(e){let t=e.query.trim().toLowerCase(),o=e.limit??10,n=t.split(/\s+/).filter(Boolean);return this.list(e.projectId).filter(i=>{if(e.types&&!e.types.includes(i.type))return!1;let s=U(i);return!(e.minImportanceScore&&s<e.minImportanceScore||e.tags?.length&&!e.tags.some(c=>i.tags.includes(c)))}).map(i=>{let s=i.content.toLowerCase(),a=n.filter(l=>s.includes(l)).length,c=n.length===0?0:a/n.length,d=U(i)/500;return{memory:i,score:c+d,source:"memory"}}).filter(i=>t.length===0||i.score>0).sort((i,s)=>s.score-i.score).slice(0,o)}pruneExpired(e,t=Date.now()){let o=0;for(let[n,i]of this.memories)i.projectId===e&&qe(i,t)&&(this.memories.delete(n),o++);return o}pruneSuperseded(e,t=30,o=Date.now()){let n=0,i=t*864e5;for(let[s,a]of this.memories){if(a.projectId!==e)continue;let c=a.metadata?.supersededAt;if(typeof c!="string")continue;o-new Date(c).getTime()>=i&&(this.memories.delete(s),n++)}return n}clearProject(e){let t=0;for(let[o,n]of this.memories)n.projectId===e&&(this.memories.delete(o),t++);return t}};function O(r){return r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}var ce=class{score(e,t){let o=O(e),n=O([t.content,...t.tags??[],t.type].join(" "));if(o.length===0||n.length===0)return 0;let i=new Map;for(let a of n)i.set(a,(i.get(a)??0)+1);let s=0;for(let a of o){let c=i.get(a)??0;c!==0&&(s+=1+Math.log(1+c))}return s/o.length}};function ft(r,e=Date.now()){let t=r.updatedAt??r.createdAt,o=new Date(t).getTime();if(!Number.isFinite(o))return 0;let n=Math.max(0,e-o)/864e5;return Math.exp(-Math.LN2*n/30)}function gt(r){return U(r)/100}var go={rule:1,decision:.9,todo:.8,summary:.6,activity:.3};function ht(r){return go[r]??.4}var le=class{analyze(e){let t=e.toLowerCase(),o=[];return(t.includes("quy\u1EBFt \u0111\u1ECBnh")||t.includes("decision")||t.includes("\u0111\xE3 ch\u1ECDn"))&&o.push("decision"),(t.includes("todo")||t.includes("c\u1EA7n l\xE0m")||t.includes("ti\u1EBFp theo")||t.includes("ch\u01B0a xong"))&&o.push("todo"),(t.includes("quy t\u1EAFc")||t.includes("rule")||t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c"))&&o.push("rule"),(t.includes("t\xF3m t\u1EAFt")||t.includes("summary")||t.includes("\u0111\xE3 l\xE0m"))&&o.push("summary"),{query:e,preferredTypes:o}}};var de=class{bm25=new ce;analyzer=new le;search(e,t,o={}){let n=o.topK??8,i=o.minScore??.05,s=this.analyzer.analyze(e),a=[];for(let c of t){if(o.types?.length&&!o.types.includes(c.type))continue;let d=this.bm25.score(e,c),l=ft(c),u=gt(c),m=ht(c.type);s.preferredTypes.includes(c.type)&&(m=Math.min(1,m+.25));let f=d*.55+u*.2+l*.15+m*.1;d<=0||f<i||a.push({memory:c,score:f,scores:{keyword:d,recency:l,importance:u,type:m}})}return a.sort((c,d)=>d.score-c.score).slice(0,n)}};var pe=class{build(e,t=6e3){let o=[],n=0;for(let i of e){let s=i.memory,a=[`[${s.type.toUpperCase()}]`,s.content].join(" ");if(n+a.length>t)break;o.push(a),n+=a.length}return o.join(`
4
+ `)}};var me=class{constructor(e){this.memory=e}memory;searcher=new de;contextBuilder=new pe;search(e,t,o={}){return this.searcher.search(t,this.memory.list(e),o)}context(e,t,o={}){let n=this.search(e,t,o);return this.contextBuilder.build(n)}};var yt=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function I(r){let e=yt.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function B(r){return yt.some(e=>e.id===r)}function p(r){return process.env[r]?.trim()||void 0}function g(...r){return r.find(e=>!!e?.trim())}function bt(){if(p("GROQ_API_KEY"))return"groq";if(p("DEEPSEEK_API_KEY"))return"deepseek";if(p("NVIDIA_API_KEY")||p("NVIDIA_NIM_API_KEY"))return"nvidia";if(p("OPENROUTER_API_KEY"))return"openrouter";if(p("ALIBABA_API_KEY")||p("DASHSCOPE_API_KEY"))return"alibaba";if(p("GEMINI_API_KEY")||p("GOOGLE_API_KEY"))return"gemini";if(p("CLOUDFLARE_API_TOKEN")&&p("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(p("HF_TOKEN"))return"huggingface";if(p("OLLAMA_MODEL")||p("OLLAMA_BASE_URL"))return"ollama"}function St(){let r=p("TOOLNET_LLM_PROVIDER");return r&&B(r)?r:bt()??"openai-compatible"}function ue(r){let e=I(r);switch(r){case"alibaba":return{provider:r,apiKey:g(p("ALIBABA_API_KEY"),p("DASHSCOPE_API_KEY")),baseUrl:g(p("ALIBABA_BASE_URL"),p("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:g(p("ALIBABA_MODEL"),p("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:p("OPENROUTER_API_KEY"),baseUrl:g(p("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:p("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:p("GROQ_API_KEY"),baseUrl:g(p("GROQ_BASE_URL"),e.defaultBaseUrl),model:p("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:p("DEEPSEEK_API_KEY"),baseUrl:g(p("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:g(p("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:g(p("NVIDIA_API_KEY"),p("NVIDIA_NIM_API_KEY")),baseUrl:g(p("NVIDIA_BASE_URL"),p("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:g(p("NVIDIA_MODEL"),p("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:g(p("GEMINI_API_KEY"),p("GOOGLE_API_KEY")),baseUrl:g(p("GEMINI_BASE_URL"),e.defaultBaseUrl),model:p("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:p("HF_TOKEN"),baseUrl:g(p("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:g(p("HF_LLM_MODEL"),p("HF_MODEL"))};case"ollama":return{provider:r,apiKey:p("OLLAMA_API_KEY"),baseUrl:g(p("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:p("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:p("CLOUDFLARE_ACCOUNT_ID"),apiKey:p("CLOUDFLARE_API_TOKEN"),baseUrl:p("CLOUDFLARE_AI_BASE_URL"),model:p("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:p("CUSTOM_AI_API_KEY"),baseUrl:p("CUSTOM_AI_BASE_URL"),model:p("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:g(p("OPENAI_API_KEY"),p("MODEL_API_KEY")),baseUrl:g(p("OPENAI_BASE_URL"),p("MODEL_BASE_URL")),model:g(p("OPENAI_MODEL"),p("MODEL_NAME"))}}}function ho(){let r=p("TOOLNET_LLM_PROVIDER"),e=r&&B(r)?r:St(),t=I(e),o=ue(e);return{provider:e,apiKey:g(p("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:g(p("TOOLNET_LLM_BASE_URL"),o.baseUrl,t.defaultBaseUrl),model:g(p("TOOLNET_LLM_MODEL"),o.model,t.defaultModel),accountId:g(p("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function yo(){let r=p("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&B(r)?r:p("HF_TOKEN")||p("HF_EMBEDDING_MODEL")?"huggingface":"local"}function bo(){let r=yo();if(r==="local")return{provider:"local",model:g(p("TOOLNET_EMBEDDING_MODEL"),p("LOCAL_EMBEDDING_MODEL"))};let e=I(r),t,o,n,i;switch(r){case"huggingface":t=p("HF_TOKEN"),o=p("HF_INFERENCE_BASE_URL"),n=p("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=p("OPENAI_API_KEY"),o=p("OPENAI_BASE_URL"),n=p("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=p("CLOUDFLARE_API_TOKEN"),o=p("CLOUDFLARE_AI_BASE_URL"),n=p("CLOUDFLARE_EMBEDDING_MODEL"),i=p("CLOUDFLARE_ACCOUNT_ID");break;default:t=ue(r).apiKey,o=ue(r).baseUrl,n=p(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let s=g(p("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),a=g(p("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),c=r==="cloudflare"&&!a&&s?`https://api.cloudflare.com/client/v4/accounts/${s}/ai/v1`:a;return{provider:r,apiKey:g(p("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:c,model:g(p("TOOLNET_EMBEDDING_MODEL"),n),accountId:s}}function q(){let r=ho(),e=bo();return{llm:r,embedding:e,legacy:{llm:!p("TOOLNET_LLM_PROVIDER")&&!!bt(),embedding:!p("TOOLNET_EMBEDDING_PROVIDER")&&!!(p("HF_TOKEN")||p("HF_EMBEDDING_MODEL"))}}}function vt(r=St()){let e=q().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=ue(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function z(r,e){return p(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function xt(){let r=[];for(let e of[1,2]){let t=z(e,"PROVIDER");if(!t||!B(t))continue;let o=I(t);r.push({slot:e,config:{provider:t,apiKey:z(e,"API_KEY"),baseUrl:g(z(e,"BASE_URL"),o.defaultBaseUrl),model:g(z(e,"MODEL"),o.defaultModel),accountId:z(e,"ACCOUNT_ID")}})}return r}function wt(){let r=p("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=p("TOOLNET_LLM_MAX_RETRIES"),t=Number(r??6e4),o=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(o)&&o>=0?Math.floor(o):1}}var fe=class{constructor(e){this.options=e}options;name="gemini";async embed(e){let t=this.options.model.replace(/^models\//,""),n=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(t)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,i=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${t}`,content:{parts:[{text:e}]}})});if(!i.ok)throw new Error(`Gemini embedding failed: ${i.status} ${await i.text()}`);let a=(await i.json()).embedding?.values;if(!Array.isArray(a)||a.length===0)throw new Error("Gemini embedding returned invalid response");return a}async embedMany(e){let t=[];for(let o of e)t.push(await this.embed(o));return t}};import{createHash as So}from"node:crypto";var ge=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),o=e.toLowerCase().split(/\s+/).filter(Boolean);for(let n of o){let s=So("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[s]+=1}return vo(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function vo(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var he=class{constructor(e){this.options=e;this.dimensions=e.dimensions}options;name="openai-compatible";dimensions;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=this.options.baseUrl.replace(/\/+$/,""),o=await fetch(`${t}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:e})});if(!o.ok)throw new Error(`Embedding failed: ${o.status} ${await o.text()}`);let i=(await o.json()).data?.sort((s,a)=>(s.index??0)-(a.index??0)).map(s=>s.embedding);if(!i||i.length!==e.length||i.some(s=>!Array.isArray(s)))throw new Error("Embedding provider returned invalid response");return i}};var ye=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,o=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!o.ok)throw new Error(`HF embedding failed: ${o.status} ${await o.text()}`);let n=await o.json();if(!Array.isArray(n))throw new Error("HF embedding returned invalid response");return n.map(i=>xo(i))}};function xo(r){if(!Array.isArray(r))throw new Error("Invalid embedding");if(r.length>0&&typeof r[0]=="number")return r;if(r.length>0&&Array.isArray(r[0])){let e=r;if(e.length===0)return[];let t=e[0].length,o=new Array(t).fill(0);for(let n of e)for(let i=0;i<t;i++)o[i]+=n[i]??0;for(let n=0;n<t;n++)o[n]/=e.length;return o}throw new Error("Unsupported embedding shape")}var He=class{constructor(e,t=new ge){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function wo(r){return`https://api.cloudflare.com/client/v4/accounts/${r}/ai/v1`}function Eo(){let r=q().embedding;if(r.provider==="local")return null;if(r.provider==="huggingface")return!r.apiKey||!r.model?null:new ye({token:r.apiKey,model:r.model});if(r.provider==="gemini")return!r.apiKey||!r.model?null:new fe({apiKey:r.apiKey,model:r.model,baseUrl:r.baseUrl});let e=r.baseUrl;return r.provider==="cloudflare"&&!e&&r.accountId&&(e=wo(r.accountId)),e&&r.model?new he({apiKey:r.apiKey,baseUrl:e,model:r.model}):null}function Et(){return new He(Eo())}import*as x from"typescript";var D=class{symbols=new Map;edges=new Map;addSymbol(e){this.symbols.set(e.id,e)}addEdge(e){this.edges.set(e.id,e)}getSymbol(e){return this.symbols.get(e)}findByName(e,t){return[...this.symbols.values()].filter(o=>o.projectId===e&&(o.name===t||o.qualifiedName===t))}allSymbols(e){return[...this.symbols.values()].filter(t=>t.projectId===e)}allEdges(e){return[...this.edges.values()].filter(t=>t.projectId===e)}import(e,t){for(let o of e)this.addSymbol(o);for(let o of t)this.addEdge(o)}clearProject(e){for(let[t,o]of this.symbols)o.projectId===e&&this.symbols.delete(t);for(let[t,o]of this.edges)o.projectId===e&&this.edges.delete(t)}};function be(r,e){let t=r.allSymbols(e),o=r.allEdges(e),n=s=>t.filter(a=>a.type===s).length,i=s=>o.filter(a=>a.type===s).length;return{files:n("file"),classes:n("class"),interfaces:n("interface"),functions:n("function"),methods:n("method"),properties:n("property"),routes:n("route"),symbols:t.length,edges:o.length,calls:i("CALLS"),callReferences:i("CALL_REFERENCE"),imports:i("IMPORTS"),inherits:i("INHERITS"),implements:i("IMPLEMENTS"),usesType:i("USES_TYPE"),tests:i("TESTS"),routeEdges:i("ROUTE"),writes:i("WRITES")}}var Se=class{constructor(e){this.graph=e}graph;callees(e,t,o=3){return this.walk(e,t,"out",o)}callers(e,t,o=3){return this.walk(e,t,"in",o)}walk(e,t,o,n){let i=[],s=new Set([t]),a=[{id:t,depth:0}],c=this.graph.allEdges(e).filter(d=>d.type==="CALLS"||d.type==="CALL_REFERENCE");for(;a.length;){let d=a.shift();if(d.depth>=n)continue;let l=o==="out"?c.filter(u=>u.from===d.id):c.filter(u=>u.to===d.id);for(let u of l){let m=o==="out"?u.to:u.from;if(s.has(m))continue;s.add(m);let f=this.graph.getSymbol(m);if(!f)continue;let b=d.depth+1;i.push({symbol:f,depth:b}),a.push({id:m,depth:b})}}return i}};var ve=class{constructor(e){this.graph=e}graph;findSymbol(e,t){return this.graph.findByName(e,t)}findCallers(e,t){return this.graph.allEdges(e).filter(n=>n.type==="CALLS"&&n.to===t).map(n=>n.from).map(n=>this.graph.getSymbol(n)).filter(n=>!!n)}};var xe=class{constructor(e){this.graph=e}graph;analyze(e,t,o=4){let n=this.graph.allEdges(e),i=new Set([t]),s=[{id:t,depth:0}],a=[];for(;s.length;){let c=s.shift();if(c.depth>=o)continue;let d=n.filter(l=>l.to===c.id&&["CALLS","IMPORTS","INHERITS","IMPLEMENTS"].includes(l.type));for(let l of d){if(i.has(l.from))continue;i.add(l.from);let u=this.graph.getSymbol(l.from);if(!u)continue;let m=c.depth+1;a.push({symbol:u,depth:m,relation:l.type}),s.push({id:l.from,depth:m})}}return a}};function Ao(r,e){return e.ranges.length===0?!0:typeof r.startLine!="number"||typeof r.endLine!="number"?!1:e.ranges.some(t=>r.startLine<=t.endLine&&r.endLine>=t.startLine)}var we=class{constructor(e){this.graph=e}graph;map(e,t){let o=this.graph.allSymbols(e),n=[];for(let i of t){let s=o.filter(d=>d.filePath===i.filePath),c=s.filter(d=>d.type!=="file").filter(d=>Ao(d,i));if(c.length===0){let d=s.find(l=>l.type==="file");d&&n.push({symbol:d,fileStatus:i.status,direct:!0});continue}for(let d of c)n.push({symbol:d,fileStatus:i.status,direct:!0})}return n}mapFile(e,t){return this.map(e,[{filePath:t,status:"modified",ranges:[]}])}};var To={CALLS:4,CALL_REFERENCE:6,USES_TYPE:4,TESTS:2,ROUTE:4,WRITES:3,IMPORTS:3,INHERITS:5,IMPLEMENTS:5,DEFINES:1};function Mo(r){return r>=30?"CRITICAL":r>=16?"HIGH":r>=6?"MEDIUM":"LOW"}function Ct(r){let e=r.toLowerCase().replaceAll("\\","/");return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}var Ee=class{constructor(e){this.graph=e}graph;analyze(e,t,o=4){let n=this.graph.allEdges(e),i=new Map,s=0;for(let l of t){l.fileStatus==="deleted"?s+=8:l.fileStatus==="renamed"?s+=5:s+=2,l.symbol.type==="interface"&&(s+=5),l.symbol.type==="class"&&(s+=3);let u=new Set([l.symbol.id]),m=[{id:l.symbol.id,depth:0}];for(;m.length;){let f=m.shift();if(f.depth>=o)continue;let b=n.filter(S=>S.to===f.id&&["CALLS","CALL_REFERENCE","USES_TYPE","TESTS","ROUTE","WRITES","IMPORTS","INHERITS","IMPLEMENTS","DEFINES"].includes(S.type));for(let S of b){if(u.has(S.from))continue;u.add(S.from);let k=this.graph.getSymbol(S.from);if(!k)continue;let A=f.depth+1,te=`${l.symbol.id}:${k.id}`;i.set(te,{symbol:k,relation:S.type,depth:A,sourceSymbolId:l.symbol.id});let j=To[S.type]??1;s+=Math.max(1,j-(A-1)),m.push({id:k.id,depth:A})}}}let a=[...i.values()].sort((l,u)=>l.depth-u.depth),c=[...new Set(a.map(l=>l.symbol.filePath))],d=c.filter(Ct);return d.length===0&&d.push(...c.filter(l=>!Ct(l)).slice(0,10)),{risk:Mo(s),riskScore:s,changedSymbols:t,impacted:a,impactedFiles:c,suggestedTests:d}}};import{execFile as Ro}from"node:child_process";import{promisify as jo}from"node:util";var Ve=jo(Ro);function Io(r){let e=[],t=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm;for(let o of r.matchAll(t)){let n=Number(o[1]),i=Number(o[2]??1);e.push({startLine:n,endLine:Math.max(n,n+i-1)})}return e}function Lo(r){return r.startsWith("A")?"added":r.startsWith("D")?"deleted":r.startsWith("R")?"renamed":"modified"}async function Pt(r){let e="";try{e=(await Ve("git",["diff","HEAD","--name-status","--no-renames"],{cwd:r,maxBuffer:10485760})).stdout}catch{return[]}let t=[];for(let o of e.split(/\r?\n/).filter(Boolean)){let[n,...i]=o.split(" "),s=i.at(-1);if(!s)continue;let a="";try{a=(await Ve("git",["diff","HEAD","--unified=0","--",s],{cwd:r,maxBuffer:20971520})).stdout}catch{a=""}t.push({filePath:s,status:Lo(n),ranges:Io(a)})}try{let o=await Ve("git",["ls-files","--others","--exclude-standard"],{cwd:r});for(let n of o.stdout.split(/\r?\n/).filter(Boolean))t.some(i=>i.filePath===n)||t.push({filePath:n,status:"added",ranges:[]})}catch{}return t}var Ce=class{constructor(e){this.graph=e;this.mapper=new we(e),this.blast=new Ee(e)}graph;mapper;blast;async analyzeGitDiff(e,t,o={}){let n=await Pt(t),i=this.mapper.map(e,n),s=this.blast.analyze(e,i,o.maxDepth??4);return{mode:"git_diff",changes:n,...s}}analyzeFile(e,t,o={}){let n=this.mapper.mapFile(e,t);return{mode:"planned_file",filePath:t,...this.blast.analyze(e,n,o.maxDepth??4)}}};var W=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};import{createHash as _o}from"node:crypto";import{readFile as No}from"node:fs/promises";import{join as Oo}from"node:path";function kt(r){return _o("sha256").update(r).digest("hex")}var Pe=class{sanitizer=new N;async build(e,t,o,n={}){let i=n.maxLines??80,s=n.overlapLines??10,a=new Map;for(let d of o){let l=a.get(d.filePath)??[];l.push(d),a.set(d.filePath,l)}let c=[];for(let[d,l]of a){let u;try{u=await No(Oo(t,d),"utf8")}catch{continue}let m=u.split(/\r?\n/),f=l.filter(b=>b.type!=="file"&&typeof b.startLine=="number"&&typeof b.endLine=="number");if(f.length>0)for(let b of f)c.push(...this.chunkRange({projectId:e,filePath:d,lines:m,symbol:b,startLine:b.startLine,endLine:b.endLine,maxLines:i,overlapLines:s}));else c.push(...this.chunkRange({projectId:e,filePath:d,lines:m,startLine:1,endLine:Math.max(1,m.length),maxLines:i,overlapLines:s}))}return c}chunkRange(e){let{projectId:t,filePath:o,lines:n,symbol:i,maxLines:s}=e,a=Math.min(e.overlapLines,Math.max(0,s-1)),c=Math.max(1,e.startLine),d=Math.min(n.length,Math.max(c,e.endLine)),l=[],u=c,m=0;for(;u<=d;){let f=Math.min(d,u+s-1),b=n.slice(u-1,f).join(`
5
+ `).trim();if(b){let S=this.sanitizer.sanitize(b).text,k=kt(S),A=[t,o,i?.id??"file",String(m),k].join(":");l.push({id:kt(A).slice(0,32),projectId:t,filePath:o,symbolId:i?.id,symbolName:i?.qualifiedName??i?.name,symbolType:i?.type,startLine:u,endLine:f,content:S,contentHash:k})}if(f>=d)break;u=f-a+1,m++}return l}};var ke=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var Ae=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var Te=class{records=new Map;upsert(e){this.records.set(e.id,e)}get(e){return this.records.get(e)}has(e){return this.records.has(e)}remove(e){return this.records.delete(e)}clearProject(e){let t=0;for(let[o,n]of this.records)n.projectId===e&&(this.records.delete(o),t++);return t}exportProject(e){return[...this.records.values()].filter(t=>t.projectId===e)}importRecords(e){let t=0;for(let o of e)!o?.id||!o?.projectId||!Array.isArray(o.vector)||(this.records.set(o.id,o),t++);return t}search(e,t,o=10){let n=[];for(let i of this.records.values()){if(i.projectId!==e)continue;let s=Do(t,i.vector);n.push({id:i.id,score:s,metadata:i.metadata})}return n.sort((i,s)=>s.score-i.score).slice(0,o)}size(){return this.records.size}};function Do(r,e){if(r.length===0||e.length===0||r.length!==e.length)return 0;let t=0,o=0,n=0;for(let i=0;i<r.length;i++){let s=r[i]??0,a=e[i]??0;t+=s*a,o+=s*s,n+=a*a}return o===0||n===0?0:t/(Math.sqrt(o)*Math.sqrt(n))}function At(r,e){let t=r.toLowerCase().replaceAll("\\","/"),o=e.toLowerCase(),n=/\b(test|tests|spec|fixture|mock)\b/.test(o);return(t.startsWith("tests/")||t.includes("/tests/")||t.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(t))&&!n?.35:t.includes("/generated/")||t.includes(".generated.")?.25:1}var Me=class{constructor(e){this.options=e}options;vectors=new Te;chunks=new Map;async initialize(){let{projectId:e,rootPath:t,storage:o,embeddings:n,graph:i,model:s}=this.options,a=new ke(o),c=new Ae(o),d=await new Pe().build(e,t,i.allSymbols(e));this.chunks.clear();for(let v of d)this.chunks.set(v.id,v);let l=await a.load(e),u=!l||l.chunks.length!==d.length||l.chunks.some(v=>!this.chunks.has(v.id));u&&await a.save({version:1,projectId:e,updatedAt:new Date().toISOString(),chunks:d});let m=await c.load(e),f=0;m&&m.model===s&&(f=this.vectors.importRecords(m.records));let b=new Set(d.map(v=>v.id)),S=0;for(let v of this.vectors.exportProject(e))b.has(v.id)||this.vectors.remove(v.id)&&S++;let k=d.filter(v=>{let L=this.vectors.get(v.id);return L?L.metadata?.contentHash!==v.contentHash:!0}),A=0,te=8,j=this.vectors.exportProject(e)[0]?.vector.length;for(let v=0;v<k.length;v+=te){let L=k.slice(v,v+te),Fr=L.map(P=>[`file: ${P.filePath}`,P.symbolName?`symbol: ${P.symbolName}`:"",P.symbolType?`type: ${P.symbolType}`:"",P.content].filter(Boolean).join(`
6
+ `)),Kr=await n.embedMany(Fr);for(let P=0;P<L.length;P++){let M=L[P],_=Kr[P];if(!(!M||!_||_.length===0)){if(j===void 0&&(j=_.length),_.length!==j){console.warn(`[code-semantic] skip dimension mismatch: ${_.length} != ${j}`);continue}this.vectors.upsert({id:M.id,projectId:e,vector:_,metadata:{contentHash:M.contentHash,filePath:M.filePath,symbolName:M.symbolName,symbolType:M.symbolType,startLine:M.startLine,endLine:M.endLine}}),A++}}}let Ue=this.vectors.exportProject(e),ot=A>0||S>0||!m||m.model!==s;return ot&&await c.save({version:1,projectId:e,model:s,dimensions:Ue[0]?.vector.length??j??0,updatedAt:new Date().toISOString(),records:Ue}),{chunks:d.length,vectorsLoaded:f,vectorsIndexed:A,vectorsRemoved:S,totalVectors:Ue.length,savedChunks:u,savedVectors:ot}}async search(e,t=8){let o=await this.options.embeddings.embed(e),n=this.vectors.search(this.options.projectId,o,Math.max(t*4,20)),i=new Set(O(e)),s=[];for(let a of n){let c=this.chunks.get(a.id);if(!c)continue;let d=new Set(O([c.filePath,c.symbolName??"",c.symbolType??"",c.content].join(" "))),l=0;for(let S of i)d.has(S)&&l++;let u=i.size===0?0:l/i.size,m=Math.max(0,a.score),f=At(c.filePath,e),b=(m*.75+u*.25)*f;s.push({chunk:c,score:b,vectorScore:m,lexicalScore:u})}return s.sort((a,c)=>c.score-a.score).slice(0,t)}size(){return this.chunks.size}};import*as w from"typescript";import*as h from"typescript";var Oa=new Set([h.SyntaxKind.EqualsToken,h.SyntaxKind.PlusEqualsToken,h.SyntaxKind.MinusEqualsToken,h.SyntaxKind.AsteriskEqualsToken,h.SyntaxKind.SlashEqualsToken,h.SyntaxKind.PercentEqualsToken,h.SyntaxKind.QuestionQuestionEqualsToken,h.SyntaxKind.AmpersandAmpersandEqualsToken,h.SyntaxKind.BarBarEqualsToken]);function $o(r){return r.replaceAll("\\","/").toLowerCase()}var H=class{constructor(e){this.graph=e}graph;detect(e){let t=this.graph.allSymbols(e),o=this.graph.allEdges(e),n=[];for(let s of t){if(s.type!=="route"&&s.type!=="file")continue;let a=this.classify(s,o);a&&n.push({symbolId:s.id,filePath:s.filePath,name:s.name,kind:a.kind,score:a.score,reasons:a.reasons})}let i=new Map;for(let s of n){let a=s.kind==="route"?s.symbolId:s.filePath,c=i.get(a);(!c||s.score>c.score)&&i.set(a,s)}return[...i.values()].sort((s,a)=>a.score-s.score||s.filePath.localeCompare(a.filePath))}classify(e,t){let o=$o(e.filePath),n=[];if(e.type==="route")return{kind:"route",score:100,reasons:["HTTP route"]};let i=null,s=0;if(o.startsWith("bin/"))i="cli",s=100,n.push("bin executable");else if(/(^|\/)(cli)\.[^.]+$/.test(o))i="cli",s=90,n.push("CLI entry file");else if(/(^|\/)(main|server)\.[^.]+$/.test(o))i="main",s=90,n.push("main/server file");else if(o.includes("/runtime/")&&/(^|\/)(bootstrap|index)\.[^.]+$/.test(o))i="runtime",s=75,n.push("runtime bootstrap");else if(/(^|\/)index\.[^.]+$/.test(o)){let c=t.filter(l=>l.to===e.id&&l.type!=="DEFINES").length,d=t.filter(l=>l.from===e.id&&l.type!=="DEFINES").length;(o.startsWith("packages/")||c===0||d>0)&&(i="package",s=o.startsWith("packages/")?70:55,n.push("package/public index"))}return i?(t.filter(c=>c.to===e.id&&c.type!=="DEFINES").length===0&&(s+=10,n.push("no incoming dependency")),{kind:i,score:s,reasons:n}):null}};var Re=new Set(["CALLS","CALL_REFERENCE","IMPORTS","USES_TYPE","WRITES","INHERITS","IMPLEMENTS","ROUTE"]),Tt=new Set(["CALLS","CALL_REFERENCE"]),C=class{constructor(e){this.graph=e}graph;findSymbols(e,t){let o=t.trim().toLowerCase();return o?this.graph.allSymbols(e).filter(n=>n.name.toLowerCase().includes(o)||(n.qualifiedName?.toLowerCase().includes(o)??!1)||n.filePath.toLowerCase().includes(o)).sort((n,i)=>{let s=n.name.toLowerCase()===o,a=i.name.toLowerCase()===o;return s!==a?s?-1:1:n.filePath.localeCompare(i.filePath)}):[]}callers(e,t){return this.relatedIncoming(e,t,Tt)}callees(e,t){return this.relatedOutgoing(e,t,Tt)}dependents(e,t){return this.relatedIncoming(e,t,Re)}dependencies(e,t){return this.relatedOutgoing(e,t,Re)}neighborhood(e,t,o=1){let n=this.graph.getSymbol(t);return!n||n.projectId!==e?null:{center:n,incoming:this.walk(e,t,"incoming",o),outgoing:this.walk(e,t,"outgoing",o)}}shortestPath(e,t,o,n=12){let i=this.graph.getSymbol(t),s=this.graph.getSymbol(o);if(!i||!s||i.projectId!==e||s.projectId!==e)return{found:!1,distance:-1,symbols:[],edges:[]};if(t===o)return{found:!0,distance:0,symbols:[i],edges:[]};let a=this.graph.allEdges(e).filter(m=>Re.has(m.type)),c=new Map;for(let m of a){let f=c.get(m.from)??[];f.push(m),c.set(m.from,f)}let d=[{id:t,depth:0}],l=new Set([t]),u=new Map;for(;d.length>0;){let m=d.shift();if(!(m.depth>=n)){for(let f of c.get(m.id)??[])if(!l.has(f.to)){if(l.add(f.to),u.set(f.to,{node:m.id,edge:f}),f.to===o)return this.buildPath(t,o,u);d.push({id:f.to,depth:m.depth+1})}}}return{found:!1,distance:-1,symbols:[],edges:[]}}buildPath(e,t,o){let n=[t],i=[],s=t;for(;s!==e;){let c=o.get(s);if(!c)return{found:!1,distance:-1,symbols:[],edges:[]};i.push(c.edge),s=c.node,n.push(s)}n.reverse(),i.reverse();let a=n.map(c=>this.graph.getSymbol(c)).filter(c=>!!c);return{found:!0,distance:i.length,symbols:a,edges:i}}walk(e,t,o,n){let i=this.graph.allEdges(e).filter(d=>Re.has(d.type)),s=[{id:t,depth:0}],a=new Set([t]),c=[];for(;s.length>0;){let d=s.shift();if(!(d.depth>=n))for(let l of i){if(!(o==="incoming"?l.to===d.id:l.from===d.id))continue;let m=o==="incoming"?l.from:l.to;if(a.has(m))continue;let f=this.graph.getSymbol(m);f&&(a.add(m),c.push({symbol:f,depth:d.depth+1,via:l}),s.push({id:m,depth:d.depth+1}))}}return c}relatedIncoming(e,t,o){return[...new Set(this.graph.allEdges(e).filter(i=>i.to===t&&o.has(i.type)).map(i=>i.from))].map(i=>this.graph.getSymbol(i)).filter(i=>!!i)}relatedOutgoing(e,t,o){return[...new Set(this.graph.allEdges(e).filter(i=>i.from===t&&o.has(i.type)).map(i=>i.to))].map(i=>this.graph.getSymbol(i)).filter(i=>!!i)}};var Mt=new Set(["CALLS","CALL_REFERENCE","IMPORTS","USES_TYPE","WRITES","INHERITS","IMPLEMENTS","ROUTE","TESTS"]);function Ye(r){return r.replaceAll("\\","/").toLowerCase()}function Fo(r){let e=Ye(r);return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}function Ko(r){let e=Ye(r.filePath);return e.startsWith("bin/")||/(^|\/)index\.[^.]+$/.test(e)||/(^|\/)(main|server|cli)\.[^.]+$/.test(e)}var V=class{constructor(e){this.graph=e}graph;analyze(e){let t=this.graph.allSymbols(e),o=this.graph.allEdges(e),n=new Set(new H(this.graph).detect(e).map(s=>s.symbolId)),i=[];for(let s of t){if(!["function","method","class","interface","property"].includes(s.type)||Fo(s.filePath)||n.has(s.id)||Ko(s)||o.filter(f=>f.to===s.id&&Mt.has(f.type)).length>0)continue;let c=o.filter(f=>f.from===s.id&&Mt.has(f.type)),d=["no incoming usage edge"],l=50;(s.type==="function"||s.type==="method")&&(l+=20,d.push("callable symbol")),s.type==="property"&&(l-=15),c.length===0&&(l+=10,d.push("no outgoing dependency")),Ye(s.filePath).includes("/internal/")&&(l+=10,d.push("internal implementation")),s.name.startsWith("_")&&(l+=5);let m=l>=75?"high":l>=55?"medium":"low";i.push({symbolId:s.id,name:s.name,qualifiedName:s.qualifiedName,type:s.type,filePath:s.filePath,startLine:s.startLine,confidence:m,score:l,reasons:d})}return i.sort((s,a)=>a.score-s.score||s.filePath.localeCompare(a.filePath)||s.name.localeCompare(a.name))}};var Go=new Set(["CALLS","CALL_REFERENCE","IMPORTS","USES_TYPE","WRITES","INHERITS","IMPLEMENTS","ROUTE"]),Y=class{constructor(e){this.graph=e}graph;analyze(e){let t=this.graph.allSymbols(e),o=this.graph.allEdges(e).filter(s=>Go.has(s.type)),n=new Map(t.map(s=>[s.id,s]));return[...new Set(t.map(s=>s.filePath))].sort().map(s=>{let a=new Set,c=new Set,d=0,l=0;for(let u of o){let m=n.get(u.from),f=n.get(u.to);!m||!f||m.filePath===f.filePath||(m.filePath===s&&(a.add(f.filePath),d++),f.filePath===s&&(c.add(m.filePath),l++))}return{filePath:s,dependencies:[...a].sort(),dependents:[...c].sort(),outgoingEdges:d,incomingEdges:l}})}};import{homedir as pn}from"node:os";import{join as mn}from"node:path";import{DeleteObjectCommand as Uo,GetObjectCommand as Bo,HeadObjectCommand as zo,ListObjectsV2Command as qo,PutObjectCommand as Wo,S3Client as Ho}from"@aws-sdk/client-s3";import{getSignedUrl as Vo}from"@aws-sdk/s3-request-presigner";var je=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ho({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Wo({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Vo(this.client,new Bo({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new zo({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Uo({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new qo({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as Rt,mkdir as Yo,readFile as Jo,readdir as Qo,rm as Zo,stat as jt,writeFile as Xo}from"node:fs/promises";import{dirname as en,join as tn,relative as It,resolve as rn}from"node:path";var J=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return rn(this.root,t)}async put(e,t){let o=this.path(e);await Yo(en(o),{recursive:!0}),await Xo(o,t)}async get(e){try{return await Jo(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await Rt(this.path(e)),!0}catch{return!1}}async delete(e){await Zo(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await Rt(t)}catch{return o}let n=async s=>{let a=await Qo(s,{withFileTypes:!0});for(let c of a){let d=tn(s,c.name);if(c.isDirectory()){await n(d);continue}let l=await jt(d);o.push({key:It(this.root,d),size:l.size,updatedAt:l.mtime.toISOString()})}},i=await jt(t);return i.isDirectory()?await n(t):o.push({key:It(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as on,GetObjectCommand as nn,HeadObjectCommand as sn,ListObjectsV2Command as an,PutObjectCommand as cn,S3Client as ln}from"@aws-sdk/client-s3";import{getSignedUrl as dn}from"@aws-sdk/s3-request-presigner";var Q=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ln({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new cn({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await dn(this.client,new nn({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`${this.name} download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new sn({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new on({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new an({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};function Je(r,e){return console.warn(e),new J(r)}function Lt(r){let e=r.localRoot??mn(pn(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new Q({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Je(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new Q({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Je(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new je({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Je(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new J(e)}var Ie=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};function un(r){return new Promise(e=>setTimeout(e,r))}async function _t(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let s=1;s<=t;s++)try{return await r()}catch(a){if(i=a,s>=t)break;let c=Math.min(n,o*2**(s-1)),d=Math.floor(Math.random()*Math.max(1,c*.2));await un(c+d)}throw i}var fn=new Set(["put","get","getText","delete","list"]);function Nt(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:fn.has(o)?(...i)=>_t(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}function Ot(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Dt(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var Le=class{constructor(e,t,o,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=Ot(n??o),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),o=t,n=await this.provider.getText(e);if(n){let s;try{s=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof s.id=="string"&&s.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${s.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof s.createdAt=="string"&&(o=s.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
7
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Dt(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{McpServer as Gn}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as Un}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as $t}from"zod";var Ft={query:$t.string(),limit:$t.number().int().min(1).max(20).optional()};async function Kt(r,e){return r.retrieval.search(r.project.id,e.query,{topK:e.limit??8}).map(o=>({id:o.memory.id,type:o.memory.type,content:o.memory.content,importance:o.memory.importance,score:o.score,tags:o.memory.tags}))}import{z as Z}from"zod";var Gt={type:Z.enum(["activity","decision","rule","todo","summary"]),content:Z.string().min(1),tags:Z.array(Z.string()).optional(),importance:Z.enum(["critical","high","normal","temporary"]).optional()};async function Ut(r,e){let t=r.memory.remember({projectId:r.project.id,type:e.type,content:e.content,tags:e.tags,importance:e.importance,source:"mcp"});return r.memoryStore&&await r.memoryStore.save(r.project.id,r.memory.exportProject(r.project.id)),t}import{z as gn}from"zod";var Bt={id:gn.string().min(1)};async function zt(r,e){let t=r.memory.delete(e.id);return t&&r.memoryStore&&await r.memoryStore.save(r.project.id,r.memory.exportProject(r.project.id)),{deleted:t}}import{z as hn}from"zod";var qt={name:hn.string().min(1)};async function Wt(r,e){return r.graph.findByName(r.project.id,e.name)}import{z as yn}from"zod";function T(r,e){let t=r.graph.getSymbol(e);if(t&&t.projectId===r.project.id)return t;let o=new C(r.graph),n=o.findSymbols(r.project.id,e).find(i=>i.name===e||i.qualifiedName===e);return n||(o.findSymbols(r.project.id,e)[0]??null)}function E(r){return{id:r.id,name:r.name,qualifiedName:r.qualifiedName,type:r.type,filePath:r.filePath,startLine:r.startLine,endLine:r.endLine}}var Ht={symbolId:yn.string().min(1)};async function Vt(r,e){let t=T(r,e.symbolId);if(!t)return{found:!1,query:e.symbolId,callers:[]};let n=new C(r.graph).callers(r.project.id,t.id);return{found:!0,symbol:E(t),count:n.length,callers:n.map(E)}}import{z as Yt}from"zod";var Jt={query:Yt.string().min(1),limit:Yt.number().int().min(1).max(50).optional()};async function Qt(r,e){let t=e.query.toLowerCase(),o=e.limit??20;return r.graph.allSymbols(r.project.id).filter(n=>n.name.toLowerCase().includes(t)||n.qualifiedName?.toLowerCase().includes(t)||n.filePath.toLowerCase().includes(t)).slice(0,o)}import{z as Zt}from"zod";var Xt={query:Zt.string().optional(),memoryLimit:Zt.number().int().min(1).max(20).optional()};async function er(r,e){let t=be(r.graph,r.project.id),o=r.memory.recent(r.project.id,5),n=e.query?r.retrieval.search(r.project.id,e.query,{topK:e.memoryLimit??5}):[];return{project:{id:r.project.id,name:r.project.name,rootPath:r.project.rootPath},architecture:t,recent:o,relevant:n.map(i=>i.memory)}}import{z as Sn}from"zod";var bn=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],R=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),i=n.replace(/[:.]/g,"-"),s=this.projectPrefix(e),a=this.snapshotPrefix(e,i),c=[];for(let l of bn){let u=`${s}/${l}`,m=await this.storage.get(u);m&&(await this.storage.put(`${a}/${l}`,m,"application/json"),c.push(l))}if(c.length===0)return null;let d={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:c,metadata:o};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(d,null,2),"application/json"),d}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(s=>s.key.endsWith("/snapshot.json")),i=[];for(let s of n){let a=await this.storage.getText(s.key);if(a)try{i.push(JSON.parse(a))}catch{}}return i.sort((s,a)=>a.createdAt.localeCompare(s.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let i=JSON.parse(n);if(i.projectId!==e)throw new Error("Snapshot project mismatch");let s=this.projectPrefix(e),a=[];for(let c of i.objects){let d=await this.storage.get(`${o}/${c}`);d&&(await this.storage.put(`${s}/${c}`,d,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let i of n)await this.storage.delete(i.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),i=0;for(let s of n)await this.remove(e,s.id),i++;return i}};var tr={reason:Sn.string().optional()};async function rr(r,e){if(!r.storage)throw new Error("Storage unavailable");return new R(r.storage).create(r.project.id,e.reason??"manual-mcp")}async function or(r){if(!r.storage)throw new Error("Storage unavailable");return new R(r.storage).list(r.project.id)}import{z as vn}from"zod";var nr={snapshotId:vn.string().min(1)};async function sr(r,e){if(!r.storage)throw new Error("Storage unavailable");let t=new R(r.storage);return await t.create(r.project.id,"before-rollback"),t.restore(r.project.id,e.snapshotId)}import{z as Qe}from"zod";var ir={symbolId:Qe.string().min(1),direction:Qe.enum(["callers","callees"]).optional(),depth:Qe.number().int().min(1).max(10).optional()};async function ar(r,e){let t=new Se(r.graph),o=e.direction??"callees",n=e.depth??3,i=o==="callers"?t.callers(r.project.id,e.symbolId,n):t.callees(r.project.id,e.symbolId,n);return{direction:o,depth:n,results:i.map(s=>({id:s.symbol.id,name:s.symbol.name,qualifiedName:s.symbol.qualifiedName,type:s.symbol.type,filePath:s.symbol.filePath,depth:s.depth}))}}import{z as cr}from"zod";var lr={symbolId:cr.string().min(1),depth:cr.number().int().min(1).max(10).optional()};async function dr(r,e){let t=r.graph.getSymbol(e.symbolId);if(!t)return{found:!1,impacts:[]};let n=new xe(r.graph).analyze(r.project.id,t.id,e.depth??4);return{found:!0,target:{id:t.id,name:t.name,qualifiedName:t.qualifiedName,filePath:t.filePath,type:t.type},impacts:n.map(i=>({id:i.symbol.id,name:i.symbol.name,qualifiedName:i.symbol.qualifiedName,filePath:i.symbol.filePath,type:i.symbol.type,relation:i.relation,depth:i.depth}))}}async function pr(r){return{project:{id:r.project.id,name:r.project.name,rootPath:r.project.rootPath},architecture:be(r.graph,r.project.id)}}import{z as mr}from"zod";var ur={filePath:mr.string().min(1),direction:mr.enum(["dependencies","dependents","both"]).optional()};async function fr(r,e){let o=new Y(r.graph).analyze(r.project.id).find(c=>c.filePath===e.filePath);if(!o)return{found:!1,filePath:e.filePath,dependencies:[],dependents:[]};let n=r.graph.allSymbols(r.project.id).filter(c=>c.type==="file"),i=new Map(n.map(c=>[c.filePath,c])),s=c=>({id:i.get(c)?.id??c,filePath:c}),a=e.direction??"both";return{found:!0,filePath:o.filePath,outgoingEdges:o.outgoingEdges,incomingEdges:o.incomingEdges,dependencies:a==="dependents"?[]:o.dependencies.map(s),dependents:a==="dependencies"?[]:o.dependents.map(s)}}import{z as gr}from"zod";var hr={query:gr.string().min(1),limit:gr.number().int().min(1).max(20).optional()};async function yr(r,e){return r.codeSemantic?{available:!0,results:(await r.codeSemantic.search(e.query,e.limit??8)).map(o=>({id:o.chunk.id,filePath:o.chunk.filePath,symbol:o.chunk.symbolName,symbolType:o.chunk.symbolType,startLine:o.chunk.startLine,endLine:o.chunk.endLine,score:o.score,vectorScore:o.vectorScore,lexicalScore:o.lexicalScore,content:o.chunk.content}))}:{available:!1,results:[]}}import{z as Ze}from"zod";var br={mode:Ze.enum(["git_diff","file"]).optional(),filePath:Ze.string().optional(),depth:Ze.number().int().min(1).max(10).optional()};async function Sr(r,e){let t=new Ce(r.graph);if((e.mode??(e.filePath?"file":"git_diff"))==="file"){if(!e.filePath)throw new Error("filePath is required when mode=file");return t.analyzeFile(r.project.id,e.filePath,{maxDepth:e.depth})}return t.analyzeGitDiff(r.project.id,r.project.rootPath,{maxDepth:e.depth})}import{z as xn}from"zod";var vr={symbol:xn.string().min(1)};async function xr(r,e){let t=T(r,e.symbol);if(!t)return{found:!1,query:e.symbol,dependents:[]};let n=new C(r.graph).dependents(r.project.id,t.id);return{found:!0,symbol:E(t),count:n.length,dependents:n.map(E)}}import{z as Xe}from"zod";var wr={from:Xe.string().min(1),to:Xe.string().min(1),maxDepth:Xe.number().int().min(1).max(30).optional()};async function Er(r,e){let t=T(r,e.from),o=T(r,e.to);if(!t||!o)return{found:!1,fromFound:!!t,toFound:!!o,path:[],edges:[]};let i=new C(r.graph).shortestPath(r.project.id,t.id,o.id,e.maxDepth??12);return{found:i.found,distance:i.distance,from:E(t),to:E(o),path:i.symbols.map(E),edges:i.edges.map(s=>({id:s.id,type:s.type,from:s.from,to:s.to,metadata:s.metadata}))}}import{z as et}from"zod";var Cr={symbol:et.string().min(1),depth:et.number().int().min(1).max(5).optional(),limit:et.number().int().min(1).max(200).optional()};async function Pr(r,e){let t=T(r,e.symbol);if(!t)return{found:!1,query:e.symbol};let n=new C(r.graph).neighborhood(r.project.id,t.id,e.depth??1);if(!n)return{found:!1,query:e.symbol};let i=e.limit??50;return{found:!0,center:E(n.center),incomingCount:n.incoming.length,outgoingCount:n.outgoing.length,incoming:n.incoming.slice(0,i).map(s=>({depth:s.depth,via:s.via?.type,symbol:E(s.symbol)})),outgoing:n.outgoing.slice(0,i).map(s=>({depth:s.depth,via:s.via?.type,symbol:E(s.symbol)}))}}import{z as tt}from"zod";var Ar={confidence:tt.enum(["high","medium","low","all"]).optional(),filePath:tt.string().min(1).optional(),limit:tt.number().int().min(1).max(500).optional()},kr={high:3,medium:2,low:1};async function Tr(r,e){let o=new V(r.graph).analyze(r.project.id);if(e.confidence&&e.confidence!=="all"){let s=kr[e.confidence];o=o.filter(a=>kr[a.confidence]>=s)}e.filePath&&(o=o.filter(s=>s.filePath===e.filePath));let n=o.length,i=e.limit??100;return{total:n,high:o.filter(s=>s.confidence==="high").length,medium:o.filter(s=>s.confidence==="medium").length,low:o.filter(s=>s.confidence==="low").length,warning:"Dead-code results are candidates only. Verify before deleting code.",candidates:o.slice(0,i)}}import{z as Lr}from"zod";import{existsSync as Rn,readFileSync as jn}from"node:fs";import{join as In}from"node:path";import{existsSync as wn,mkdirSync as ip,readFileSync as En,renameSync as ap,writeFileSync as cp}from"node:fs";import{dirname as dp,join as Cn}from"node:path";function Pn(r){return Cn(r.rootPath,".toolnet","work","current.json")}function _e(r){let e=Pn(r);if(!wn(e))return null;try{let t=JSON.parse(En(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as kn,mkdirSync as up,readFileSync as An,renameSync as fp,writeFileSync as gp}from"node:fs";import{dirname as yp,join as Tn}from"node:path";function Mn(r){return Tn(r.rootPath,".toolnet","context","session-origin.json")}function Ne(r){let e=Mn(r);if(!kn(e))return null;try{let t=JSON.parse(An(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function Ln(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function _n(r){let e=Ln(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),o=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return t&&o?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}function Nn(r){let e=In(r.rootPath,".toolnet","context","handoff.md");if(!Rn(e))return null;try{let t=jn(e,"utf8").trim();return t||null}catch{return null}}function On(r,e=5){return r.slice(0,e).map(t=>`- ${t}`).join(`
8
+ `)}function X(r,e){let t=_n(e),o=Ne(r),n=_e(r);switch(t){case"previous_agent":{if(o)return{intent:t,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${o.agent}. Session: ${o.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(o?.currentTask){let s=[`Task hi\u1EC7n t\u1EA1i: ${o.currentTask}.`];return o.lastTouchedFile&&s.push(`File g\u1EA7n nh\u1EA5t: ${o.lastTouchedFile}.`),o.latestNextAction&&s.push(`Ti\u1EBFp theo: ${o.latestNextAction}.`),{intent:t,answer:s.join(" "),source:"session-origin"}}if(n?.currentTask)return{intent:t,answer:`Task hi\u1EC7n t\u1EA1i: ${n.currentTask.title} (${n.currentTask.status}).`,source:"work-state"};break}case"next_action":{let s=o?.latestNextAction??n?.nextActions?.[0];if(s)return{intent:t,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${s}.`,source:o?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let s=o?.lastTouchedFile??n?.filesTouched?.at(-1);if(s)return{intent:t,answer:`File g\u1EA7n nh\u1EA5t \u0111\u01B0\u1EE3c nh\u1EAFc ho\u1EB7c s\u1EEDa: ${s}.`,source:o?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let s=o?.latestBlocker??n?.blockers?.at(-1);return s?{intent:t,answer:`Blocker hi\u1EC7n t\u1EA1i: ${s}.`,source:o?.latestBlocker?"session-origin":"work-state"}:{intent:t,answer:"Hi\u1EC7n ToolNet ch\u01B0a ghi nh\u1EADn blocker n\xE0o.",source:n?"work-state":"none"}}case"decision":{let s=o?.latestDecision??n?.decisions?.at(-1);if(s)return{intent:t,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${s}.`,source:o?.latestDecision?"session-origin":"work-state"};break}case"completed":{let s=n?.tasks?.filter(a=>a.status==="completed").map(a=>a.title)??[];if(s.length)return{intent:t,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
9
+ ${On(s,8)}`,source:"work-state"};break}case"status":{if(n){let s=[`Progress: ${n.progress.tasksCompleted}/${n.progress.tasksTotal} task ho\xE0n th\xE0nh.`];return n.currentTask&&s.push(`\u0110ang l\xE0m: ${n.currentTask.title}.`),n.progress.blocked>0&&s.push(`Blocked: ${n.progress.blocked}.`),{intent:t,answer:s.join(" "),source:"work-state"}}break}case"summary":{if(o||n){let s=[];o&&s.push(`Agent tr\u01B0\u1EDBc: ${o.agent}.`);let a=o?.currentTask??n?.currentTask?.title;a&&s.push(`Task hi\u1EC7n t\u1EA1i: ${a}.`);let c=o?.lastTouchedFile??n?.filesTouched?.at(-1);c&&s.push(`File g\u1EA7n nh\u1EA5t: ${c}.`);let d=o?.latestNextAction??n?.nextActions?.[0];d&&s.push(`Ti\u1EBFp theo: ${d}.`);let l=o?.latestBlocker??n?.blockers?.at(-1);l&&s.push(`Blocker: ${l}.`);let u=o?.latestDecision??n?.decisions?.at(-1);return u&&s.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${u}.`),{intent:t,answer:s.join(" "),source:o?"session-origin":"work-state"}}break}}let i=Nn(r);if(i){let s=i.length>900?`${i.slice(0,900)}
10
+ [truncated]`:i;return{intent:t,answer:s,source:"handoff"}}return{intent:t,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}var ee=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function $(r,e,t=3e4){let o=new AbortController,n=setTimeout(()=>o.abort(),t);n.unref?.();try{let i=await fetch(r,{...e,signal:o.signal}),s=await i.text();if(!i.ok){let a=s;try{let c=JSON.parse(s);a=c.error?.message??c.message??s}catch{}throw new ee(a||`HTTP ${i.status}`,i.status)}return s.trim()?JSON.parse(s):{}}finally{clearTimeout(n)}}function Oe(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var De=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),o=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!o)throw new Error("cloudflare: API TOKEN is not configured");let n=this.model(),s=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${n}`,a=await $(s,{method:"POST",headers:{authorization:`Bearer ${o}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),c=a.result?.response?.trim();if(!c)throw new Error(a.errors?.[0]?.message??"cloudflare: empty model response");return{text:c,provider:"cloudflare",model:n}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var $e=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let o=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",n=this.model(),i=e.messages.filter(l=>l.role==="system"),s=e.messages.filter(l=>l.role!=="system").map(l=>({role:l.role==="assistant"?"model":"user",parts:[{text:l.content}]})),a=`${Oe(o,`models/${encodeURIComponent(n)}:generateContent`)}?key=${encodeURIComponent(t)}`,c=await $(a,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(l=>l.content).join(`
11
+
12
+ `)}]}}:{},contents:s,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),d=c.candidates?.[0]?.content?.parts?.map(l=>l.text??"").join("").trim();if(!d)throw new Error("gemini: empty model response");return{text:d,provider:"gemini",model:n,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var Fe=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),o=await $(Oe(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),n=o.choices?.[0]?.message?.content?.trim();if(!n)throw new Error(`${this.id}: empty model response`);return{text:n,provider:this.id,model:t,usage:o.usage?{inputTokens:o.usage.prompt_tokens,outputTokens:o.usage.completion_tokens,totalTokens:o.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function Mr(r=vt()){switch(I(r.id).transport){case"gemini":return new $e(r);case"cloudflare":return new De(r);default:return new Fe(r)}}function Dn(r){return new Promise(e=>{setTimeout(e,r)})}function $n(r){if(r instanceof ee){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var Ke=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],o={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=o.cooldownMs??6e4,this.maxRetries=Math.max(0,o.maxRetries??1),this.providers=[e,...t].map(n=>({provider:Mr(n.config),label:n.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),o=this.states.get(t);return o||(o={failures:0,cooldownUntil:0},this.states.set(t,o)),o}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let o=this.state(e);o.failures+=1,o.lastError=t instanceof Error?t.message:String(t),o.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let o=0;o<this.providers.length;o+=1){if(!this.available(o)){t.push(`${this.providers[o].label}: cooldown`);continue}let n=this.providers[o];for(let i=0;i<=this.maxRetries;i+=1)try{let s=await n.provider.generate(e);return this.success(o),s}catch(s){let a=s instanceof Error?s.message:String(s),c=$n(s);if(t.push(`${n.label}: ${a}`),!c)throw s;if(i<this.maxRetries){await Dn(Math.min(250*2**i,2e3));continue}this.fail(o,s)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:t.provider,model:t.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,t)=>{let o=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:o.cooldownUntil>Date.now(),cooldownUntil:o.cooldownUntil||void 0,failures:o.failures,lastError:o.lastError}})}};function Rr(){let r=q(),e=xt();return new Ke({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),wt())}var rt=class{constructor(e=Rr()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function jr(){return new rt(Rr())}function Fn(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
13
+ [truncated]`}function Kn(r,e){let t=X(r,e),o=Ne(r),n=_e(r),i={project:{id:r.id,name:r.name},directAnswer:t.answer,previousSession:o,workState:n?{goal:n.goal,plan:n.plan,currentPhase:n.currentPhase,currentTask:n.currentTask,tasks:n.tasks,blockers:n.blockers,decisions:n.decisions,nextActions:n.nextActions,filesTouched:n.filesTouched,tests:n.tests,progress:n.progress,lastSession:n.lastSession}:null};return Fn(i,7e3)}async function Ir(r,e){let t=X(r,e),o=Kn(r,e),n=jr();try{let i=await n.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
14
+ You are ToolNet Memory Agent.
15
+
16
+ You are NOT the coding agent.
17
+
18
+ Your job is to help another coding AI continue work from previous sessions.
19
+
20
+ Rules:
21
+
22
+ 1. Answer only from the supplied ToolNet project memory.
23
+ 2. Never invent completed work, files, blockers, decisions, or test results.
24
+ 3. Prefer the latest session/work state over old information.
25
+ 4. Be concise.
26
+ 5. Do not dump raw JSON or full memory files.
27
+ 6. Tell the coding agent exactly:
28
+ - what the previous agent was doing,
29
+ - what is already completed,
30
+ - what remains unfinished,
31
+ - what file was last touched,
32
+ - what should be done next,
33
+ when those facts are available.
34
+ 7. If information is missing, say it is not recorded.
35
+ 8. Do not explain ToolNet internals unless asked.
36
+ 9. Do not repeat irrelevant history.
37
+ 10. Respond in the same language as the question.
38
+
39
+ Think of yourself as the project's memory coworker talking directly to another AI.
40
+ `.trim()},{role:"user",content:`
41
+ Question from coding agent:
42
+
43
+ ${e}
44
+
45
+ ToolNet selected memory:
46
+
47
+ ${o}
48
+
49
+ Answer the coding agent directly.
50
+ `.trim()}]}),s=i.text.trim();return s?{answer:s,provider:i.provider,model:i.model,usedAi:!0}:{answer:t.answer,usedAi:!1}}catch{return{answer:t.answer,usedAi:!1}}}var _r={question:Lr.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:Lr.enum(["ai","local"]).optional().describe("ai uses ToolNet Memory Agent with configured LLM fallback chain. local returns deterministic local memory only.")};async function Nr(r,e){if(e.mode==="local"){let o=X(r.project,e.question);return{answer:o.answer,mode:"local",usedAi:!1,source:o.source,intent:o.intent}}let t=await Ir(r.project,e.question);return{answer:t.answer,mode:"ai",usedAi:t.usedAi,provider:t.provider,model:t.model}}function y(r){return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}function Bn(r){let e=new Gn({name:"toolnet-memory",version:"0.1.0"});return e.tool("memory_search","Search relevant long-term memory for the current project.",Ft,async t=>y(await Kt(r,t))),e.tool("memory_save","Save an important memory, decision, rule, TODO or summary.",Gt,async t=>y(await Ut(r,t))),e.tool("memory_forget","Delete a memory by id.",Bt,async t=>y(await zt(r,t))),e.tool("find_symbol","Find code symbols by exact name.",qt,async t=>y(await Wt(r,t))),e.tool("find_callers","Find functions or methods calling a symbol.",Ht,async t=>y(await Vt(r,t))),e.tool("code_search","Search indexed code symbols and files.",Jt,async t=>y(await Qt(r,t))),e.tool("project_context","Get compact project architecture, recent memory and relevant context.",Xt,async t=>y(await er(r,t))),e.tool("trace_calls","Trace callers or callees through the code call graph.",ir,async t=>y(await ar(r,t))),e.tool("analyze_impact","Analyze what code can be affected if a symbol changes.",lr,async t=>y(await dr(r,t))),e.tool("get_architecture","Get compact architecture statistics for the indexed project.",{},async()=>y(await pr(r))),e.tool("find_dependencies","Find direct file dependencies and reverse dependents.",ur,async t=>y(await fr(r,t))),e.tool("semantic_code_search","Search source code by semantic meaning, not only exact symbol names.",hr,async t=>y(await yr(r,t))),e.tool("snapshot_create","Create a safe versioned snapshot of project memory, vectors and graph.",tr,async t=>y(await rr(r,t))),e.tool("snapshot_list","List available ToolNet Memory snapshots.",{},async()=>y(await or(r))),e.tool("snapshot_restore","Restore a previous ToolNet Memory snapshot. A safety snapshot is created first.",nr,async t=>y(await sr(r,t))),e.tool("impact_guard","Analyze blast radius before or after code changes. Maps changed files/lines to symbols, follows reverse dependencies, assigns risk and suggests verification targets.",br,async t=>y(await Sr(r,t))),e.tool("graph_dependents","Find code symbols that depend on a symbol through calls, imports, type usage, writes, inheritance or implementation relationships.",vr,async t=>y(await xr(r,t))),e.tool("graph_path","Find the shortest dependency path between two code symbols.",wr,async t=>y(await Er(r,t))),e.tool("graph_neighborhood","Explore incoming and outgoing dependency relationships around a code symbol.",Cr,async t=>y(await Pr(r,t))),e.tool("dead_code","Find likely unused code. Results are candidates and must be verified before deletion.",Ar,async t=>y(await Tr(r,t))),e.tool("memory_agent_ask",["Ask ToolNet Memory Agent about previous project work.","CALL THIS TOOL before guessing when the user asks to continue/resume previous work,","mentions a previous agent/session, asks what was unfinished, what file was last touched,","which TODOs are complete, blockers, decisions, or what should happen next.","Use mode=local for direct state facts and mode=ai for composite or ambiguous continuity questions.","Do not use it for unrelated coding questions when current repository context is already sufficient.","Returns concise selected memory instead of raw transcripts or full memory dumps."].join(" "),_r,async t=>y(await Nr(r,t))),e}async function Or(r){let e=Bn(r),t=new Un;await e.connect(t)}import{closeSync as zn,mkdirSync as qn,openSync as Wn,readFileSync as Hn,unlinkSync as Dr,writeFileSync as Vn}from"node:fs";import{tmpdir as Yn}from"node:os";import{join as $r}from"node:path";function Jn(r){try{return process.kill(r,0),!0}catch(e){return e?.code==="EPERM"}}var Ge=class{acquired=!1;path;exitHandler=()=>{this.releaseSync()};constructor(e){let t=$r(Yn(),"toolnet-memory-locks");qn(t,{recursive:!0});let o=e.replace(/[^A-Za-z0-9_.-]/g,"_");this.path=$r(t,`${o}.lock`)}async acquire(){if(!this.acquired){for(let e=0;e<2;e++)try{let t=Wn(this.path,"wx");Vn(t,JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()})),zn(t),this.acquired=!0,process.once("exit",this.exitHandler);return}catch(t){if(t?.code!=="EEXIST")throw t;let o=!0;try{let n=JSON.parse(Hn(this.path,"utf8"));Number.isInteger(n.pid)&&Jn(n.pid)&&(o=!1)}catch{o=!0}if(!o)throw new Error("ToolNet Memory is already running for this project");try{Dr(this.path)}catch{}}throw new Error("Unable to acquire ToolNet Memory project lock")}}async release(){this.releaseSync()}releaseSync(){if(this.acquired){try{Dr(this.path)}catch{}this.acquired=!1,process.off("exit",this.exitHandler)}}};async function Qn(){let r=nt(),e=new oe().detect(),t=Lt({provider:r.storage.provider,huggingface:r.storage.huggingface,localRoot:r.storage.localRoot}),o=Nt(t,{attempts:Number(process.env.TOOLNET_STORAGE_RETRIES??3)}),n=new Le(o,e.id,e.name,e.remote??e.name),i=new Ge(e.id);await i.acquire();let s=()=>{i.release().finally(()=>process.exit(0))};process.once("SIGINT",s),process.once("SIGTERM",s);let a=new ae,c=new Ie(n);a.importRecords(await c.load(e.id));let d=new me(a),l=new D,u=await new W(n).load(e.id);u&&l.import(u.symbols,u.edges);let m=new ve(l),f=new Me({projectId:e.id,rootPath:e.rootPath,model:process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",storage:n,embeddings:Et(),graph:l});await f.initialize(),await Or({project:e,memory:a,retrieval:d,graph:l,references:m,codeSemantic:f,memoryStore:c,storage:n})}Qn().catch(r=>{console.error(r),process.exit(1)});
@@ -0,0 +1,49 @@
1
+ import*as h from"fs";import*as f from"path";function j(r){let e=f.resolve(r),t=f.parse(e).root;for(;e!==t;){let n=f.join(e,".toolnet");if(h.existsSync(n)&&h.statSync(n).isDirectory())return e;e=f.dirname(e)}return null}var K=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function g(r){let e=K.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function A(r){return K.some(e=>e.id===r)}function o(r){return process.env[r]?.trim()||void 0}function c(...r){return r.find(e=>!!e?.trim())}function F(){if(o("GROQ_API_KEY"))return"groq";if(o("DEEPSEEK_API_KEY"))return"deepseek";if(o("NVIDIA_API_KEY")||o("NVIDIA_NIM_API_KEY"))return"nvidia";if(o("OPENROUTER_API_KEY"))return"openrouter";if(o("ALIBABA_API_KEY")||o("DASHSCOPE_API_KEY"))return"alibaba";if(o("GEMINI_API_KEY")||o("GOOGLE_API_KEY"))return"gemini";if(o("CLOUDFLARE_API_TOKEN")&&o("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(o("HF_TOKEN"))return"huggingface";if(o("OLLAMA_MODEL")||o("OLLAMA_BASE_URL"))return"ollama"}function B(){let r=o("TOOLNET_LLM_PROVIDER");return r&&A(r)?r:F()??"openai-compatible"}function v(r){let e=g(r);switch(r){case"alibaba":return{provider:r,apiKey:c(o("ALIBABA_API_KEY"),o("DASHSCOPE_API_KEY")),baseUrl:c(o("ALIBABA_BASE_URL"),o("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(o("ALIBABA_MODEL"),o("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:o("OPENROUTER_API_KEY"),baseUrl:c(o("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:o("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:o("GROQ_API_KEY"),baseUrl:c(o("GROQ_BASE_URL"),e.defaultBaseUrl),model:o("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:o("DEEPSEEK_API_KEY"),baseUrl:c(o("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(o("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:c(o("NVIDIA_API_KEY"),o("NVIDIA_NIM_API_KEY")),baseUrl:c(o("NVIDIA_BASE_URL"),o("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(o("NVIDIA_MODEL"),o("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:c(o("GEMINI_API_KEY"),o("GOOGLE_API_KEY")),baseUrl:c(o("GEMINI_BASE_URL"),e.defaultBaseUrl),model:o("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:o("HF_TOKEN"),baseUrl:c(o("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(o("HF_LLM_MODEL"),o("HF_MODEL"))};case"ollama":return{provider:r,apiKey:o("OLLAMA_API_KEY"),baseUrl:c(o("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:o("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:o("CLOUDFLARE_ACCOUNT_ID"),apiKey:o("CLOUDFLARE_API_TOKEN"),baseUrl:o("CLOUDFLARE_AI_BASE_URL"),model:o("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:o("CUSTOM_AI_API_KEY"),baseUrl:o("CUSTOM_AI_BASE_URL"),model:o("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(o("OPENAI_API_KEY"),o("MODEL_API_KEY")),baseUrl:c(o("OPENAI_BASE_URL"),o("MODEL_BASE_URL")),model:c(o("OPENAI_MODEL"),o("MODEL_NAME"))}}}function X(){let r=o("TOOLNET_LLM_PROVIDER"),e=r&&A(r)?r:B(),t=g(e),n=v(e);return{provider:e,apiKey:c(o("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:c(o("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:c(o("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:c(o("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function ee(){let r=o("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&A(r)?r:o("HF_TOKEN")||o("HF_EMBEDDING_MODEL")?"huggingface":"local"}function te(){let r=ee();if(r==="local")return{provider:"local",model:c(o("TOOLNET_EMBEDDING_MODEL"),o("LOCAL_EMBEDDING_MODEL"))};let e=g(r),t,n,s,a;switch(r){case"huggingface":t=o("HF_TOKEN"),n=o("HF_INFERENCE_BASE_URL"),s=o("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=o("OPENAI_API_KEY"),n=o("OPENAI_BASE_URL"),s=o("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=o("CLOUDFLARE_API_TOKEN"),n=o("CLOUDFLARE_AI_BASE_URL"),s=o("CLOUDFLARE_EMBEDDING_MODEL"),a=o("CLOUDFLARE_ACCOUNT_ID");break;default:t=v(r).apiKey,n=v(r).baseUrl,s=o(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let i=c(o("TOOLNET_EMBEDDING_ACCOUNT_ID"),a),l=c(o("TOOLNET_EMBEDDING_BASE_URL"),n,e.defaultBaseUrl),u=r==="cloudflare"&&!l&&i?`https://api.cloudflare.com/client/v4/accounts/${i}/ai/v1`:l;return{provider:r,apiKey:c(o("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:u,model:c(o("TOOLNET_EMBEDDING_MODEL"),s),accountId:i}}function C(){let r=X(),e=te();return{llm:r,embedding:e,legacy:{llm:!o("TOOLNET_LLM_PROVIDER")&&!!F(),embedding:!o("TOOLNET_EMBEDDING_PROVIDER")&&!!(o("HF_TOKEN")||o("HF_EMBEDDING_MODEL"))}}}function $(r=B()){let e=C().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=v(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function k(r,e){return o(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function G(){let r=[];for(let e of[1,2]){let t=k(e,"PROVIDER");if(!t||!A(t))continue;let n=g(t);r.push({slot:e,config:{provider:t,apiKey:k(e,"API_KEY"),baseUrl:c(k(e,"BASE_URL"),n.defaultBaseUrl),model:c(k(e,"MODEL"),n.defaultModel),accountId:k(e,"ACCOUNT_ID")}})}return r}function Y(){let r=o("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=o("TOOLNET_LLM_MAX_RETRIES"),t=Number(r??6e4),n=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(n)&&n>=0?Math.floor(n):1}}var E=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(r,e,t=3e4){let n=new AbortController,s=setTimeout(()=>n.abort(),t);s.unref?.();try{let a=await fetch(r,{...e,signal:n.signal}),i=await a.text();if(!a.ok){let l=i;try{let u=JSON.parse(i);l=u.error?.message??u.message??i}catch{}throw new E(l||`HTTP ${a.status}`,a.status)}return i.trim()?JSON.parse(i):{}}finally{clearTimeout(s)}}function _(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var O=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),n=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!n)throw new Error("cloudflare: API TOKEN is not configured");let s=this.model(),i=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${s}`,l=await y(i,{method:"POST",headers:{authorization:`Bearer ${n}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),u=l.result?.response?.trim();if(!u)throw new Error(l.errors?.[0]?.message??"cloudflare: empty model response");return{text:u,provider:"cloudflare",model:s}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var w=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let n=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",s=this.model(),a=e.messages.filter(d=>d.role==="system"),i=e.messages.filter(d=>d.role!=="system").map(d=>({role:d.role==="assistant"?"model":"user",parts:[{text:d.content}]})),l=`${_(n,`models/${encodeURIComponent(s)}:generateContent`)}?key=${encodeURIComponent(t)}`,u=await y(l,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...a.length?{systemInstruction:{parts:[{text:a.map(d=>d.content).join(`
2
+
3
+ `)}]}}:{},contents:i,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),p=u.candidates?.[0]?.content?.parts?.map(d=>d.text??"").join("").trim();if(!p)throw new Error("gemini: empty model response");return{text:p,provider:"gemini",model:s,usage:u.usageMetadata?{inputTokens:u.usageMetadata.promptTokenCount,outputTokens:u.usageMetadata.candidatesTokenCount,totalTokens:u.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var T=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),n=await y(_(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),s=n.choices?.[0]?.message?.content?.trim();if(!s)throw new Error(`${this.id}: empty model response`);return{text:s,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function H(r=$()){switch(g(r.id).transport){case"gemini":return new w(r);case"cloudflare":return new O(r);default:return new T(r)}}function re(r){return new Promise(e=>{setTimeout(e,r)})}function ne(r){if(r instanceof E){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var S=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],n={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=n.cooldownMs??6e4,this.maxRetries=Math.max(0,n.maxRetries??1),this.providers=[e,...t].map(s=>({provider:H(s.config),label:s.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),n=this.states.get(t);return n||(n={failures:0,cooldownUntil:0},this.states.set(t,n)),n}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let n=this.state(e);n.failures+=1,n.lastError=t instanceof Error?t.message:String(t),n.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let n=0;n<this.providers.length;n+=1){if(!this.available(n)){t.push(`${this.providers[n].label}: cooldown`);continue}let s=this.providers[n];for(let a=0;a<=this.maxRetries;a+=1)try{let i=await s.provider.generate(e);return this.success(n),i}catch(i){let l=i instanceof Error?i.message:String(i),u=ne(i);if(t.push(`${s.label}: ${l}`),!u)throw i;if(a<this.maxRetries){await re(Math.min(250*2**a,2e3));continue}this.fail(n,i)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:t.provider,model:t.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,t)=>{let n=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:n.cooldownUntil>Date.now(),cooldownUntil:n.cooldownUntil||void 0,failures:n.failures,lastError:n.lastError}})}};function W(){let r=C(),e=G();return new S({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),Y())}var L=class{constructor(e=W()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function V(){return new L(W())}import{existsSync as pe,readFileSync as me}from"node:fs";import{join as fe}from"node:path";import{existsSync as oe,mkdirSync as _t,readFileSync as se,renameSync as Ot,writeFileSync as wt}from"node:fs";import{dirname as St,join as ie}from"node:path";function ae(r){return ie(r.rootPath,".toolnet","work","current.json")}function I(r){let e=ae(r);if(!oe(e))return null;try{let t=JSON.parse(se(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as ce,mkdirSync as Mt,readFileSync as le,renameSync as Pt,writeFileSync as Rt}from"node:fs";import{dirname as Lt,join as ue}from"node:path";function de(r){return ue(r.rootPath,".toolnet","context","session-origin.json")}function x(r){let e=de(r);if(!ce(e))return null;try{let t=JSON.parse(le(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ge(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function he(r){let e=ge(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),n=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return t&&n?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}function ye(r){let e=fe(r.rootPath,".toolnet","context","handoff.md");if(!pe(e))return null;try{let t=me(e,"utf8").trim();return t||null}catch{return null}}function Ae(r,e=5){return r.slice(0,e).map(t=>`- ${t}`).join(`
4
+ `)}function N(r,e){let t=he(e),n=x(r),s=I(r);switch(t){case"previous_agent":{if(n)return{intent:t,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${n.agent}. Session: ${n.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(n?.currentTask){let i=[`Task hi\u1EC7n t\u1EA1i: ${n.currentTask}.`];return n.lastTouchedFile&&i.push(`File g\u1EA7n nh\u1EA5t: ${n.lastTouchedFile}.`),n.latestNextAction&&i.push(`Ti\u1EBFp theo: ${n.latestNextAction}.`),{intent:t,answer:i.join(" "),source:"session-origin"}}if(s?.currentTask)return{intent:t,answer:`Task hi\u1EC7n t\u1EA1i: ${s.currentTask.title} (${s.currentTask.status}).`,source:"work-state"};break}case"next_action":{let i=n?.latestNextAction??s?.nextActions?.[0];if(i)return{intent:t,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${i}.`,source:n?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let i=n?.lastTouchedFile??s?.filesTouched?.at(-1);if(i)return{intent:t,answer:`File g\u1EA7n nh\u1EA5t \u0111\u01B0\u1EE3c nh\u1EAFc ho\u1EB7c s\u1EEDa: ${i}.`,source:n?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let i=n?.latestBlocker??s?.blockers?.at(-1);return i?{intent:t,answer:`Blocker hi\u1EC7n t\u1EA1i: ${i}.`,source:n?.latestBlocker?"session-origin":"work-state"}:{intent:t,answer:"Hi\u1EC7n ToolNet ch\u01B0a ghi nh\u1EADn blocker n\xE0o.",source:s?"work-state":"none"}}case"decision":{let i=n?.latestDecision??s?.decisions?.at(-1);if(i)return{intent:t,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${i}.`,source:n?.latestDecision?"session-origin":"work-state"};break}case"completed":{let i=s?.tasks?.filter(l=>l.status==="completed").map(l=>l.title)??[];if(i.length)return{intent:t,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
5
+ ${Ae(i,8)}`,source:"work-state"};break}case"status":{if(s){let i=[`Progress: ${s.progress.tasksCompleted}/${s.progress.tasksTotal} task ho\xE0n th\xE0nh.`];return s.currentTask&&i.push(`\u0110ang l\xE0m: ${s.currentTask.title}.`),s.progress.blocked>0&&i.push(`Blocked: ${s.progress.blocked}.`),{intent:t,answer:i.join(" "),source:"work-state"}}break}case"summary":{if(n||s){let i=[];n&&i.push(`Agent tr\u01B0\u1EDBc: ${n.agent}.`);let l=n?.currentTask??s?.currentTask?.title;l&&i.push(`Task hi\u1EC7n t\u1EA1i: ${l}.`);let u=n?.lastTouchedFile??s?.filesTouched?.at(-1);u&&i.push(`File g\u1EA7n nh\u1EA5t: ${u}.`);let p=n?.latestNextAction??s?.nextActions?.[0];p&&i.push(`Ti\u1EBFp theo: ${p}.`);let d=n?.latestBlocker??s?.blockers?.at(-1);d&&i.push(`Blocker: ${d}.`);let m=n?.latestDecision??s?.decisions?.at(-1);return m&&i.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${m}.`),{intent:t,answer:i.join(" "),source:n?"session-origin":"work-state"}}break}}let a=ye(r);if(a){let i=a.length>900?`${a.slice(0,900)}
6
+ [truncated]`:a;return{intent:t,answer:i,source:"handoff"}}return{intent:t,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}function ke(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
7
+ [truncated]`}function Ee(r,e){let t=N(r,e),n=x(r),s=I(r),a={project:{id:r.id,name:r.name},directAnswer:t.answer,previousSession:n,workState:s?{goal:s.goal,plan:s.plan,currentPhase:s.currentPhase,currentTask:s.currentTask,tasks:s.tasks,blockers:s.blockers,decisions:s.decisions,nextActions:s.nextActions,filesTouched:s.filesTouched,tests:s.tests,progress:s.progress,lastSession:s.lastSession}:null};return ke(a,7e3)}async function z(r,e){let t=N(r,e),n=Ee(r,e),s=V();try{let a=await s.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
8
+ You are ToolNet Memory Agent.
9
+
10
+ You are NOT the coding agent.
11
+
12
+ Your job is to help another coding AI continue work from previous sessions.
13
+
14
+ Rules:
15
+
16
+ 1. Answer only from the supplied ToolNet project memory.
17
+ 2. Never invent completed work, files, blockers, decisions, or test results.
18
+ 3. Prefer the latest session/work state over old information.
19
+ 4. Be concise.
20
+ 5. Do not dump raw JSON or full memory files.
21
+ 6. Tell the coding agent exactly:
22
+ - what the previous agent was doing,
23
+ - what is already completed,
24
+ - what remains unfinished,
25
+ - what file was last touched,
26
+ - what should be done next,
27
+ when those facts are available.
28
+ 7. If information is missing, say it is not recorded.
29
+ 8. Do not explain ToolNet internals unless asked.
30
+ 9. Do not repeat irrelevant history.
31
+ 10. Respond in the same language as the question.
32
+
33
+ Think of yourself as the project's memory coworker talking directly to another AI.
34
+ `.trim()},{role:"user",content:`
35
+ Question from coding agent:
36
+
37
+ ${e}
38
+
39
+ ToolNet selected memory:
40
+
41
+ ${n}
42
+
43
+ Answer the coding agent directly.
44
+ `.trim()}]}),i=a.text.trim();return i?{answer:i,provider:a.provider,model:a.model,usedAi:!0}:{answer:t.answer,usedAi:!1}}catch{return{answer:t.answer,usedAi:!1}}}import{existsSync as be,readFileSync as ve}from"node:fs";import{homedir as _e}from"node:os";import{join as Oe}from"node:path";function we(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
45
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Te(){let r=process.env.TOOLNET_GLOBAL_ENV??Oe(_e(),".config","toolnet-memory",".env");if(!be(r))return;let e=ve(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let a=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=we(n.slice(s+1)))}}Te();import{createHash as Se}from"node:crypto";import{existsSync as D,mkdirSync as Ie,readFileSync as xe,renameSync as Me,writeFileSync as Pe}from"node:fs";import{basename as Re,dirname as M,join as R,parse as Q,resolve as b}from"node:path";var Z=".toolnet",Ce="project.json";function Le(r){return Se("sha256").update(r).digest("hex").slice(0,16)}function U(r){return R(r,Z,Ce)}function Ne(r){return D(U(r))}function De(r,e){let t=b(r),n=Q(t).root;for(;;){if(Ne(t))return t;if(t===n||e&&t===b(e))break;let s=M(t);if(s===t)break;t=s}return null}function Ue(r){let e=b(r),t=Q(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(a=>D(R(e,a))))return e;if(e===t)break;let s=M(e);if(s===e)break;e=s}return b(r)}function je(r){let e;try{e=JSON.parse(xe(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:M(M(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function J(r,e){let t=R(r,Z);Ie(t,{recursive:!0});let n=U(r),s=`${n}.tmp-${process.pid}`;Pe(s,JSON.stringify(e,null,2)+`
46
+ `,{encoding:"utf8",mode:384}),Me(s,n)}function q(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var P=class{detect(e=process.cwd()){let t=b(e),n=Ue(t),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>D(R(n,d))),i=De(t,a?n:void 0);if(i){let d=U(i),m=je(d);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),J(i,m)),q(m,i)}let l=new Date().toISOString(),u=Re(n),p={version:1,id:Le(n),name:u,remote:u,rootPath:n,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return J(n,p),q(p,n)}};async function Ke(){let r=process.argv.slice(2).join(" ").trim();if(!r){console.error('Usage: toolnet-memory ask-ai "<question>"'),process.exitCode=1;return}let e=j(process.cwd());if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new P().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=await z(t,r);process.stdout.write(`${n.answer}
47
+ `),process.env.TOOLNET_MEMORY_AGENT_DEBUG==="1"&&process.stderr.write(["",`[ToolNet Memory Agent] AI: ${n.usedAi?"yes":"fallback"}`,n.provider?`Provider: ${n.provider}`:"",n.model?`Model: ${n.model}`:""].filter(Boolean).join(`
48
+ `)+`
49
+ `)}Ke().catch(r=>{console.error(r instanceof Error?r.message:String(r)),process.exitCode=1});