toolnet-memory 0.2.15 → 0.2.16

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/README.md CHANGED
@@ -546,3 +546,77 @@ See [CHANGELOG.md](CHANGELOG.md) for release history.
546
546
  ## License
547
547
 
548
548
  MIT © 2026 LBT-AI. See [LICENSE](LICENSE).
549
+
550
+ ## Multi-provider AI setup
551
+
552
+ Run:
553
+
554
+ ```bash
555
+ toolnet-memory setup
556
+
557
+ ToolNet Memory separates AI configuration into independent roles:
558
+
559
+ * LLM — reasoning, summarization, classification, and memory intelligence.
560
+ * Embedding — semantic indexing and retrieval.
561
+ * LLM Fallbacks — optional secondary providers for transient failures.
562
+
563
+ Supported LLM providers include:
564
+
565
+ * OpenAI-compatible
566
+ * Alibaba / DashScope
567
+ * OpenRouter
568
+ * Groq
569
+ * DeepSeek
570
+ * NVIDIA NIM
571
+ * Gemini
572
+ * Hugging Face
573
+ * Ollama / Local
574
+ * Cloudflare Workers AI
575
+ * Custom endpoints
576
+
577
+ Canonical configuration:
578
+
579
+ TOOLNET_LLM_PROVIDER=
580
+ TOOLNET_LLM_API_KEY=
581
+ TOOLNET_LLM_BASE_URL=
582
+ TOOLNET_LLM_MODEL=
583
+ TOOLNET_EMBEDDING_PROVIDER=
584
+ TOOLNET_EMBEDDING_API_KEY=
585
+ TOOLNET_EMBEDDING_BASE_URL=
586
+ TOOLNET_EMBEDDING_MODEL=
587
+
588
+ Optional resilient LLM chain:
589
+
590
+ TOOLNET_LLM_FALLBACK_1_PROVIDER=
591
+ TOOLNET_LLM_FALLBACK_1_API_KEY=
592
+ TOOLNET_LLM_FALLBACK_1_BASE_URL=
593
+ TOOLNET_LLM_FALLBACK_1_MODEL=
594
+ TOOLNET_LLM_FALLBACK_2_PROVIDER=
595
+ TOOLNET_LLM_FALLBACK_2_API_KEY=
596
+ TOOLNET_LLM_FALLBACK_2_BASE_URL=
597
+ TOOLNET_LLM_FALLBACK_2_MODEL=
598
+ TOOLNET_LLM_FALLBACK_COOLDOWN_MS=60000
599
+ TOOLNET_LLM_MAX_RETRIES=1
600
+
601
+ Fallback is used only for transient failures such as:
602
+
603
+ * timeout / network failure
604
+ * HTTP 408
605
+ * HTTP 429
606
+ * HTTP 5xx
607
+
608
+ HTTP 400, 401, and 403 are surfaced instead of silently switching providers.
609
+
610
+ Legacy provider environment variables remain readable for backward compatibility. The setup wizard can migrate recognized legacy values into canonical TOOLNET_* configuration without deleting the original variables.
611
+
612
+ Diagnostics:
613
+
614
+ toolnet-memory provider:list
615
+ toolnet-memory provider:status
616
+ toolnet-memory provider:test
617
+ toolnet-memory provider:test llm
618
+ toolnet-memory provider:test embedding
619
+ toolnet-memory doctor
620
+
621
+ Provider status masks API keys and secrets.
622
+ ```
@@ -68,6 +68,21 @@ case "$COMMAND" in
68
68
  run bundle/doctor.js src/production/doctor.ts "$@"
69
69
  ;;
70
70
 
71
+ provider:list)
72
+ shift
73
+ run bundle/provider.js src/ai/provider-cli.ts list "$@"
74
+ ;;
75
+
76
+ provider:status)
77
+ shift
78
+ run bundle/provider.js src/ai/provider-cli.ts status "$@"
79
+ ;;
80
+
81
+ provider:test)
82
+ shift
83
+ run bundle/provider.js src/ai/provider-cli.ts test "$@"
84
+ ;;
85
+
71
86
  run)
72
87
  run bundle/runtime.js src/index.ts
73
88
  ;;
@@ -521,6 +536,9 @@ CODE INTELLIGENCE:
521
536
  SETUP & INTEGRATION:
522
537
  toolnet-memory --version
523
538
  toolnet-memory doctor
539
+ toolnet-memory provider:list
540
+ toolnet-memory provider:status
541
+ toolnet-memory provider:test [llm|embedding]
524
542
  toolnet-memory setup
525
543
  toolnet-memory update
526
544
  toolnet-memory config get KEY
package/bundle/doctor.js CHANGED
@@ -1,3 +1,5 @@
1
- import"dotenv/config";import{existsSync as ae,readFileSync as ce}from"node:fs";import{homedir as de}from"node:os";import{join as pe}from"node:path";function le(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 me(){let r=process.env.TOOLNET_GLOBAL_ENV??pe(de(),".config","toolnet-memory",".env");if(!ae(r))return;let e=ce(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]=le(o.slice(n+1)))}}me();function f(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function y(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function V(){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:y(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:y(process.env.MEMORY_RERANK_TOP,10),finalContext:y(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:y(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:y(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ue}from"node:crypto";import{existsSync as K,mkdirSync as ge,readFileSync as fe,renameSync as ye,writeFileSync as he}from"node:fs";import{basename as Ee,dirname as v,join as A,parse as H,resolve as h}from"node:path";var G=".toolnet",be="project.json";function ve(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function N(r){return A(r,G,be)}function Se(r){return K(N(r))}function Ae(r,e){let t=h(r),o=H(t).root;for(;;){if(Se(t))return t;if(t===o||e&&t===h(e))break;let n=v(t);if(n===t)break;t=n}return null}function _e(r){let e=h(r),t=H(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>K(A(e,i))))return e;if(e===t)break;let n=v(e);if(n===e)break;e=n}return h(r)}function Pe(r){let e;try{e=JSON.parse(fe(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:v(v(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 F(r,e){let t=A(r,G);ge(t,{recursive:!0});let o=N(r),n=`${o}.tmp-${process.pid}`;he(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ye(n,o)}function Y(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 S=class{detect(e=process.cwd()){let t=h(e),o=_e(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>K(A(o,m))),a=Ae(t,i?o:void 0);if(a){let m=N(a),u=Pe(m);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),F(a,u)),Y(u,a)}let d=new Date().toISOString(),p=Ee(o),l={version:1,id:ve(o),name:p,remote:p,rootPath:o,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return F(o,l),Y(l,o)}};import{homedir as ze}from"node:os";import{join as Je}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as je,HeadObjectCommand as Ie,ListObjectsV2Command as Oe,PutObjectCommand as xe,S3Client as ke}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var _=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ke({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 xe({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Re(this.client,new je({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 Ie({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 we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Oe({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 z,mkdir as Me,readFile as Ce,readdir as Te,rm as De,stat as J,writeFile as Ke}from"node:fs/promises";import{dirname as Ne,join as Le,relative as q,resolve as Ue}from"node:path";var E=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ue(this.root,t)}async put(e,t){let o=this.path(e);await Me(Ne(o),{recursive:!0}),await Ke(o,t)}async get(e){try{return await Ce(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 z(this.path(e)),!0}catch{return!1}}async delete(e){await De(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await z(t)}catch{return o}let n=async a=>{let d=await Te(a,{withFileTypes:!0});for(let p of d){let l=Le(a,p.name);if(p.isDirectory()){await n(l);continue}let m=await J(l);o.push({key:q(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},i=await J(t);return i.isDirectory()?await n(t):o.push({key:q(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as Be,GetObjectCommand as $e,HeadObjectCommand as Ve,ListObjectsV2Command as Fe,PutObjectCommand as Ye,S3Client as He}from"@aws-sdk/client-s3";import{getSignedUrl as Ge}from"@aws-sdk/s3-request-presigner";var b=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new He({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 Ye({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Ge(this.client,new $e({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 Ve({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 Be({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Fe({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 L(r,e){return console.warn(e),new E(r)}function W(r){let e=r.localRoot??Je(ze(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new b({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(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 b({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(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 _({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new E(e)}var P=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")}};var w=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let o=JSON.parse(t);if(o.version!==1||o.projectId!==e||!Array.isArray(o.records))throw new Error("Invalid vector snapshot");return o}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var j=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")}};var I=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 O=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")}};function qe(r){return new Promise(e=>setTimeout(e,r))}async function Z(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(d){if(i=d,a>=t)break;let p=Math.min(n,o*2**(a-1)),l=Math.floor(Math.random()*Math.max(1,p*.2));await qe(p+l)}throw i}var We=new Set(["put","get","getText","delete","list"]);function Q(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:We.has(o)?(...i)=>Z(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}var X=[{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 x(r){let e=X.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function k(r){return X.some(e=>e.id===r)}function s(r){return process.env[r]?.trim()||void 0}function c(...r){return r.find(e=>!!e?.trim())}function ee(){if(s("GROQ_API_KEY"))return"groq";if(s("DEEPSEEK_API_KEY"))return"deepseek";if(s("NVIDIA_API_KEY")||s("NVIDIA_NIM_API_KEY"))return"nvidia";if(s("OPENROUTER_API_KEY"))return"openrouter";if(s("ALIBABA_API_KEY")||s("DASHSCOPE_API_KEY"))return"alibaba";if(s("GEMINI_API_KEY")||s("GOOGLE_API_KEY"))return"gemini";if(s("CLOUDFLARE_API_TOKEN")&&s("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(s("HF_TOKEN"))return"huggingface";if(s("OLLAMA_MODEL")||s("OLLAMA_BASE_URL"))return"ollama"}function Ze(){let r=s("TOOLNET_LLM_PROVIDER");return r&&k(r)?r:ee()??"openai-compatible"}function U(r){let e=x(r);switch(r){case"alibaba":return{provider:r,apiKey:c(s("ALIBABA_API_KEY"),s("DASHSCOPE_API_KEY")),baseUrl:c(s("ALIBABA_BASE_URL"),s("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(s("ALIBABA_MODEL"),s("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:s("OPENROUTER_API_KEY"),baseUrl:c(s("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:s("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:s("GROQ_API_KEY"),baseUrl:c(s("GROQ_BASE_URL"),e.defaultBaseUrl),model:s("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:s("DEEPSEEK_API_KEY"),baseUrl:c(s("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(s("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:c(s("NVIDIA_API_KEY"),s("NVIDIA_NIM_API_KEY")),baseUrl:c(s("NVIDIA_BASE_URL"),s("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(s("NVIDIA_MODEL"),s("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:c(s("GEMINI_API_KEY"),s("GOOGLE_API_KEY")),baseUrl:c(s("GEMINI_BASE_URL"),e.defaultBaseUrl),model:s("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:s("HF_TOKEN"),baseUrl:c(s("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(s("HF_LLM_MODEL"),s("HF_MODEL"))};case"ollama":return{provider:r,apiKey:s("OLLAMA_API_KEY"),baseUrl:c(s("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:s("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:s("CLOUDFLARE_ACCOUNT_ID"),apiKey:s("CLOUDFLARE_API_TOKEN"),baseUrl:s("CLOUDFLARE_AI_BASE_URL"),model:s("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:s("CUSTOM_AI_API_KEY"),baseUrl:s("CUSTOM_AI_BASE_URL"),model:s("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(s("OPENAI_API_KEY"),s("MODEL_API_KEY")),baseUrl:c(s("OPENAI_BASE_URL"),s("MODEL_BASE_URL")),model:c(s("OPENAI_MODEL"),s("MODEL_NAME"))}}}function Qe(){let r=s("TOOLNET_LLM_PROVIDER"),e=r&&k(r)?r:Ze(),t=x(e),o=U(e);return{provider:e,apiKey:c(s("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:c(s("TOOLNET_LLM_BASE_URL"),o.baseUrl,t.defaultBaseUrl),model:c(s("TOOLNET_LLM_MODEL"),o.model,t.defaultModel),accountId:c(s("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function Xe(){let r=s("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&k(r)?r:s("HF_TOKEN")||s("HF_EMBEDDING_MODEL")?"huggingface":"local"}function et(){let r=Xe();if(r==="local")return{provider:"local",model:c(s("TOOLNET_EMBEDDING_MODEL"),s("LOCAL_EMBEDDING_MODEL"))};let e=x(r),t,o,n,i;switch(r){case"huggingface":t=s("HF_TOKEN"),o=s("HF_INFERENCE_BASE_URL"),n=s("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=s("OPENAI_API_KEY"),o=s("OPENAI_BASE_URL"),n=s("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=s("CLOUDFLARE_API_TOKEN"),o=s("CLOUDFLARE_AI_BASE_URL"),n=s("CLOUDFLARE_EMBEDDING_MODEL"),i=s("CLOUDFLARE_ACCOUNT_ID");break;default:t=U(r).apiKey,o=U(r).baseUrl,n=s(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}return{provider:r,apiKey:c(s("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:c(s("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),model:c(s("TOOLNET_EMBEDDING_MODEL"),n),accountId:c(s("TOOLNET_EMBEDDING_ACCOUNT_ID"),i)}}function te(){let r=Qe(),e=et();return{llm:r,embedding:e,legacy:{llm:!s("TOOLNET_LLM_PROVIDER")&&!!ee(),embedding:!s("TOOLNET_EMBEDDING_PROVIDER")&&!!(s("HF_TOKEN")||s("HF_EMBEDDING_MODEL"))}}}var R=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=>tt(i))}};function tt(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")}import{createHash as rt}from"node:crypto";var M=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 a=rt("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[a]+=1}return ot(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function ot(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var C=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((a,d)=>(a.index??0)-(d.index??0)).map(a=>a.embedding);if(!i||i.length!==e.length||i.some(a=>!Array.isArray(a)))throw new Error("Embedding provider returned invalid response");return i}};var B=class{constructor(e,t=new M){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 nt(){let r=te().embedding;return r.provider==="local"?null:r.provider==="huggingface"?!r.apiKey||!r.model?null:new R({token:r.apiKey,model:r.model}):r.baseUrl&&r.model?new C({apiKey:r.apiKey,baseUrl:r.baseUrl,model:r.model}):null}function re(){return new B(nt())}var st=["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"],T=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,"-"),a=this.projectPrefix(e),d=this.snapshotPrefix(e,i),p=[];for(let m of st){let u=`${a}/${m}`,g=await this.storage.get(u);g&&(await this.storage.put(`${d}/${m}`,g,"application/json"),p.push(m))}if(p.length===0)return null;let l={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:p,metadata:o};return await this.storage.put(`${d}/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(a=>a.key.endsWith("/snapshot.json")),i=[];for(let a of n){let d=await this.storage.getText(a.key);if(d)try{i.push(JSON.parse(d))}catch{}}return i.sort((a,d)=>d.createdAt.localeCompare(a.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 a=this.projectPrefix(e),d=[];for(let p of i.objects){let l=await this.storage.get(`${o}/${p}`);l&&(await this.storage.put(`${a}/${p}`,l,"application/json"),d.push(p))}return{restored:d}}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 a of n)await this.remove(e,a.id),i++;return i}};function $(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function oe(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?$(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?$(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?$(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback"),process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as it}from"node:crypto";var D=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${it()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let n=null;if(this.embeddings)try{let i=await this.embeddings.embed("ToolNet Memory production health check");n={ok:i.length>0,dimensions:i.length,mode:i.length===384?"huggingface":"fallback-or-custom"}}catch{n={ok:!1,dimensions:0,mode:"failed"}}return{ok:o&&(n===null||n.ok),storage:{ok:o,provider:this.storage.name},embedding:n}}};function se(){return process.argv.includes("--json")}function at(r){if(console.log(""),console.log("ToolNet Memory Doctor"),console.log("====================="),console.log(""),r.project&&(console.log(`Project: ${r.project}`),console.log("")),r.storage)if(r.storage.ok){let n=typeof r.storage.provider=="string"?` (${r.storage.provider})`:"";console.log(`\u2713 Storage${n}`)}else console.log("\u2717 Storage");if(r.embedding)if(r.embedding.ok){let n=[];typeof r.embedding.mode=="string"&&n.push(r.embedding.mode),typeof r.embedding.dimensions=="number"&&n.push(`${r.embedding.dimensions} dimensions`),console.log(`\u2713 Embedding${n.length?` (${n.join(", ")})`:""}`)}else console.log("\u2717 Embedding");(r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(""),console.log("Project data:"),r.memory!==void 0&&console.log(` Memories ${r.memory}`),r.graphSymbols!==void 0&&console.log(` Graph symbols ${r.graphSymbols}`),r.graphEdges!==void 0&&console.log(` Graph edges ${r.graphEdges}`),r.memoryVectors!==void 0&&console.log(` Memory vectors ${r.memoryVectors}`),r.codeChunks!==void 0&&console.log(` Code chunks ${r.codeChunks}`),r.codeVectors!==void 0&&console.log(` Code vectors ${r.codeVectors}`),r.snapshots!==void 0&&console.log(` Snapshots ${r.snapshots}`));let e=r.config?.errors??[];if(e.length>0){console.log(""),console.log("Configuration required:");for(let n of e)console.log(` - ${n}`)}let t=[...r.config?.warnings??[],...r.warnings??[]],o=[...new Set(t)];if(o.length>0){console.log(""),console.log("Warnings:");for(let n of o)console.log(` - ${n}`)}console.log(""),r.ok?console.log("\u2713 ToolNet Memory is ready"):(console.log("\u2717 ToolNet Memory requires attention"),e.length>0&&(console.log(""),console.log("Run:"),console.log(" toolnet-memory setup"))),console.log("")}function ne(r){se()?console.log(JSON.stringify(r,null,2)):at(r)}async function ct(){let r=oe();if(!r.ok){let ie={ok:!1,config:r,warnings:r.warnings};ne(ie),process.exitCode=1;return}let e=V(),t=new S().detect(),o=Q(W({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=re(),i=await new D(o,n).run(),a=await new P(o).load(t.id),d=await new j(o).load(t.id),p=await new w(o).load(t.id),l=await new I(o).load(t.id),m=await new O(o).load(t.id),u=await new T(o).list(t.id),g={ok:i.ok,project:t.name,storage:i.storage,embedding:i.embedding,memory:a.length,graphSymbols:d?.symbols.length??0,graphEdges:d?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:l?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:u.length,warnings:r.warnings};ne(g),process.exitCode=g.ok?0:1}ct().catch(r=>{let e=r instanceof Error?r.message:String(r);se()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
1
+ import"dotenv/config";import{existsSync as ve,readFileSync as Ae}from"node:fs";import{homedir as Se}from"node:os";import{join as we}from"node:path";function _e(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 Pe(){let r=process.env.TOOLNET_GLOBAL_ENV??we(Se(),".config","toolnet-memory",".env");if(!ve(r))return;let e=Ae(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]=_e(o.slice(n+1)))}}Pe();function b(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function E(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function X(){return{memory:{autoCapture:b(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:b(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:b(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:b(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:E(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:E(process.env.MEMORY_RERANK_TOP,10),finalContext:E(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:E(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:b(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:E(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Oe}from"node:crypto";import{existsSync as Y,mkdirSync as Ie,readFileSync as ke,renameSync as je,writeFileSync as xe}from"node:fs";import{basename as Re,dirname as P,join as I,parse as re,resolve as v}from"node:path";var oe=".toolnet",Ce="project.json";function Me(r){return Oe("sha256").update(r).digest("hex").slice(0,16)}function z(r){return I(r,oe,Ce)}function Te(r){return Y(z(r))}function Le(r,e){let t=v(r),o=re(t).root;for(;;){if(Te(t))return t;if(t===o||e&&t===v(e))break;let n=P(t);if(n===t)break;t=n}return null}function De(r){let e=v(r),t=re(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>Y(I(e,i))))return e;if(e===t)break;let n=P(e);if(n===e)break;e=n}return v(r)}function Ke(r){let e;try{e=JSON.parse(ke(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:P(P(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 ee(r,e){let t=I(r,oe);Ie(t,{recursive:!0});let o=z(r),n=`${o}.tmp-${process.pid}`;xe(n,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),je(n,o)}function te(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 O=class{detect(e=process.cwd()){let t=v(e),o=De(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>Y(I(o,p))),a=Le(t,i?o:void 0);if(a){let p=z(a),u=Ke(p);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),ee(a,u)),te(u,a)}let c=new Date().toISOString(),d=Re(o),m={version:1,id:Me(o),name:d,remote:d,rootPath:o,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return ee(o,m),te(m,o)}};import{homedir as it}from"node:os";import{join as at}from"node:path";import{DeleteObjectCommand as Ne,GetObjectCommand as Ue,HeadObjectCommand as $e,ListObjectsV2Command as Be,PutObjectCommand as Fe,S3Client as Ge}from"@aws-sdk/client-s3";import{getSignedUrl as Ve}from"@aws-sdk/s3-request-presigner";var k=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ge({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 Fe({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Ve(this.client,new Ue({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 $e({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 Ne({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Be({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 ne,mkdir as He,readFile as Ye,readdir as ze,rm as Je,stat as se,writeFile as qe}from"node:fs/promises";import{dirname as We,join as Ze,relative as ie,resolve as Qe}from"node:path";var A=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Qe(this.root,t)}async put(e,t){let o=this.path(e);await He(We(o),{recursive:!0}),await qe(o,t)}async get(e){try{return await Ye(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 ne(this.path(e)),!0}catch{return!1}}async delete(e){await Je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ne(t)}catch{return o}let n=async a=>{let c=await ze(a,{withFileTypes:!0});for(let d of c){let m=Ze(a,d.name);if(d.isDirectory()){await n(m);continue}let p=await se(m);o.push({key:ie(this.root,m),size:p.size,updatedAt:p.mtime.toISOString()})}},i=await se(t);return i.isDirectory()?await n(t):o.push({key:ie(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as Xe,GetObjectCommand as et,HeadObjectCommand as tt,ListObjectsV2Command as rt,PutObjectCommand as ot,S3Client as nt}from"@aws-sdk/client-s3";import{getSignedUrl as st}from"@aws-sdk/s3-request-presigner";var S=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new nt({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 ot({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await st(this.client,new et({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 tt({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 Xe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new rt({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 J(r,e){return console.warn(e),new A(r)}function ae(r){let e=r.localRoot??at(it(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new S({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(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 S({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(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 k({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new A(e)}var j=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")}};var x=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let o=JSON.parse(t);if(o.version!==1||o.projectId!==e||!Array.isArray(o.records))throw new Error("Invalid vector snapshot");return o}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var R=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")}};var C=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 M=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")}};function ct(r){return new Promise(e=>setTimeout(e,r))}async function ce(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let d=Math.min(n,o*2**(a-1)),m=Math.floor(Math.random()*Math.max(1,d*.2));await ct(d+m)}throw i}var dt=new Set(["put","get","getText","delete","list"]);function de(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:dt.has(o)?(...i)=>ce(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}var le=[{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 f(r){let e=le.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function T(r){return le.some(e=>e.id===r)}function s(r){return process.env[r]?.trim()||void 0}function l(...r){return r.find(e=>!!e?.trim())}function pe(){if(s("GROQ_API_KEY"))return"groq";if(s("DEEPSEEK_API_KEY"))return"deepseek";if(s("NVIDIA_API_KEY")||s("NVIDIA_NIM_API_KEY"))return"nvidia";if(s("OPENROUTER_API_KEY"))return"openrouter";if(s("ALIBABA_API_KEY")||s("DASHSCOPE_API_KEY"))return"alibaba";if(s("GEMINI_API_KEY")||s("GOOGLE_API_KEY"))return"gemini";if(s("CLOUDFLARE_API_TOKEN")&&s("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(s("HF_TOKEN"))return"huggingface";if(s("OLLAMA_MODEL")||s("OLLAMA_BASE_URL"))return"ollama"}function me(){let r=s("TOOLNET_LLM_PROVIDER");return r&&T(r)?r:pe()??"openai-compatible"}function L(r){let e=f(r);switch(r){case"alibaba":return{provider:r,apiKey:l(s("ALIBABA_API_KEY"),s("DASHSCOPE_API_KEY")),baseUrl:l(s("ALIBABA_BASE_URL"),s("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:l(s("ALIBABA_MODEL"),s("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:s("OPENROUTER_API_KEY"),baseUrl:l(s("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:s("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:s("GROQ_API_KEY"),baseUrl:l(s("GROQ_BASE_URL"),e.defaultBaseUrl),model:s("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:s("DEEPSEEK_API_KEY"),baseUrl:l(s("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:l(s("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:l(s("NVIDIA_API_KEY"),s("NVIDIA_NIM_API_KEY")),baseUrl:l(s("NVIDIA_BASE_URL"),s("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:l(s("NVIDIA_MODEL"),s("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:l(s("GEMINI_API_KEY"),s("GOOGLE_API_KEY")),baseUrl:l(s("GEMINI_BASE_URL"),e.defaultBaseUrl),model:s("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:s("HF_TOKEN"),baseUrl:l(s("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:l(s("HF_LLM_MODEL"),s("HF_MODEL"))};case"ollama":return{provider:r,apiKey:s("OLLAMA_API_KEY"),baseUrl:l(s("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:s("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:s("CLOUDFLARE_ACCOUNT_ID"),apiKey:s("CLOUDFLARE_API_TOKEN"),baseUrl:s("CLOUDFLARE_AI_BASE_URL"),model:s("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:s("CUSTOM_AI_API_KEY"),baseUrl:s("CUSTOM_AI_BASE_URL"),model:s("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:l(s("OPENAI_API_KEY"),s("MODEL_API_KEY")),baseUrl:l(s("OPENAI_BASE_URL"),s("MODEL_BASE_URL")),model:l(s("OPENAI_MODEL"),s("MODEL_NAME"))}}}function lt(){let r=s("TOOLNET_LLM_PROVIDER"),e=r&&T(r)?r:me(),t=f(e),o=L(e);return{provider:e,apiKey:l(s("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:l(s("TOOLNET_LLM_BASE_URL"),o.baseUrl,t.defaultBaseUrl),model:l(s("TOOLNET_LLM_MODEL"),o.model,t.defaultModel),accountId:l(s("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function pt(){let r=s("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&T(r)?r:s("HF_TOKEN")||s("HF_EMBEDDING_MODEL")?"huggingface":"local"}function mt(){let r=pt();if(r==="local")return{provider:"local",model:l(s("TOOLNET_EMBEDDING_MODEL"),s("LOCAL_EMBEDDING_MODEL"))};let e=f(r),t,o,n,i;switch(r){case"huggingface":t=s("HF_TOKEN"),o=s("HF_INFERENCE_BASE_URL"),n=s("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=s("OPENAI_API_KEY"),o=s("OPENAI_BASE_URL"),n=s("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=s("CLOUDFLARE_API_TOKEN"),o=s("CLOUDFLARE_AI_BASE_URL"),n=s("CLOUDFLARE_EMBEDDING_MODEL"),i=s("CLOUDFLARE_ACCOUNT_ID");break;default:t=L(r).apiKey,o=L(r).baseUrl,n=s(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=l(s("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),c=l(s("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),d=r==="cloudflare"&&!c&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:c;return{provider:r,apiKey:l(s("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:d,model:l(s("TOOLNET_EMBEDDING_MODEL"),n),accountId:a}}function w(){let r=lt(),e=mt();return{llm:r,embedding:e,legacy:{llm:!s("TOOLNET_LLM_PROVIDER")&&!!pe(),embedding:!s("TOOLNET_EMBEDDING_PROVIDER")&&!!(s("HF_TOKEN")||s("HF_EMBEDDING_MODEL"))}}}function ue(r=me()){let e=w().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=L(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}var D=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 c=(await i.json()).embedding?.values;if(!Array.isArray(c)||c.length===0)throw new Error("Gemini embedding returned invalid response");return c}async embedMany(e){let t=[];for(let o of e)t.push(await this.embed(o));return t}};import{createHash as ut}from"node:crypto";var K=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 a=ut("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[a]+=1}return gt(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function gt(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var N=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((a,c)=>(a.index??0)-(c.index??0)).map(a=>a.embedding);if(!i||i.length!==e.length||i.some(a=>!Array.isArray(a)))throw new Error("Embedding provider returned invalid response");return i}};var U=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=>ft(i))}};function ft(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 q=class{constructor(e,t=new K){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 yt(r){return`https://api.cloudflare.com/client/v4/accounts/${r}/ai/v1`}function ht(){let r=w().embedding;if(r.provider==="local")return null;if(r.provider==="huggingface")return!r.apiKey||!r.model?null:new U({token:r.apiKey,model:r.model});if(r.provider==="gemini")return!r.apiKey||!r.model?null:new D({apiKey:r.apiKey,model:r.model,baseUrl:r.baseUrl});let e=r.baseUrl;return r.provider==="cloudflare"&&!e&&r.accountId&&(e=yt(r.accountId)),e&&r.model?new N({apiKey:r.apiKey,baseUrl:e,model:r.model}):null}function ge(){return new q(ht())}var W=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(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}),a=await i.text();if(!i.ok){let c=a;try{let d=JSON.parse(a);c=d.error?.message??d.message??a}catch{}throw new W(c||`HTTP ${i.status}`,i.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(n)}}function $(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var B=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(),a=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${n}`,c=await y(a,{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})}),d=c.result?.response?.trim();if(!d)throw new Error(c.errors?.[0]?.message??"cloudflare: empty model response");return{text:d,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 F=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(p=>p.role==="system"),a=e.messages.filter(p=>p.role!=="system").map(p=>({role:p.role==="assistant"?"model":"user",parts:[{text:p.content}]})),c=`${$(o,`models/${encodeURIComponent(n)}:generateContent`)}?key=${encodeURIComponent(t)}`,d=await y(c,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(p=>p.content).join(`
4
+
5
+ `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),m=d.candidates?.[0]?.content?.parts?.map(p=>p.text??"").join("").trim();if(!m)throw new Error("gemini: empty model response");return{text:m,provider:"gemini",model:n,usage:d.usageMetadata?{inputTokens:d.usageMetadata.promptTokenCount,outputTokens:d.usageMetadata.candidatesTokenCount,totalTokens:d.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 G=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 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})}),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 fe(r=ue()){switch(f(r.id).transport){case"gemini":return new F(r);case"cloudflare":return new B(r);default:return new G(r)}}var bt=["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"],V=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,"-"),a=this.projectPrefix(e),c=this.snapshotPrefix(e,i),d=[];for(let p of bt){let u=`${a}/${p}`,_=await this.storage.get(u);_&&(await this.storage.put(`${c}/${p}`,_,"application/json"),d.push(p))}if(d.length===0)return null;let m={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:d,metadata:o};return await this.storage.put(`${c}/snapshot.json`,JSON.stringify(m,null,2),"application/json"),m}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(a=>a.key.endsWith("/snapshot.json")),i=[];for(let a of n){let c=await this.storage.getText(a.key);if(c)try{i.push(JSON.parse(c))}catch{}}return i.sort((a,c)=>c.createdAt.localeCompare(a.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 a=this.projectPrefix(e),c=[];for(let d of i.objects){let m=await this.storage.get(`${o}/${d}`);m&&(await this.storage.put(`${a}/${d}`,m,"application/json"),c.push(d))}return{restored:c}}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 a of n)await this.remove(e,a.id),i++;return i}};function Z(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function ye(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?Z(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?Z(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?Z(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback"),process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Et}from"node:crypto";var H=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${Et()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let n=null;if(this.embeddings)try{let i=await this.embeddings.embed("ToolNet Memory production health check");n={ok:i.length>0,dimensions:i.length,mode:i.length===384?"huggingface":"fallback-or-custom"}}catch{n={ok:!1,dimensions:0,mode:"failed"}}return{ok:o&&(n===null||n.ok),storage:{ok:o,provider:this.storage.name},embedding:n}}};function be(){return process.argv.includes("--json")}function vt(r){if(console.log(""),console.log("ToolNet Memory Doctor"),console.log("====================="),console.log(""),r.project&&(console.log(`Project: ${r.project}`),console.log("")),r.storage)if(r.storage.ok){let n=typeof r.storage.provider=="string"?` (${r.storage.provider})`:"";console.log(`\u2713 Storage${n}`)}else console.log("\u2717 Storage");if(r.llm)if(r.llm.ok){let n=[];r.llm.provider&&n.push(r.llm.provider),r.llm.model&&n.push(r.llm.model),typeof r.llm.latencyMs=="number"&&n.push(`${r.llm.latencyMs} ms`),console.log(`\u2713 LLM${n.length?` (${n.join(", ")})`:""}`)}else console.log(`\u2717 LLM${r.llm.error?` (${r.llm.error})`:""}`);if(r.embedding)if(r.embedding.ok){let n=[];typeof r.embedding.mode=="string"&&n.push(r.embedding.mode),typeof r.embedding.dimensions=="number"&&n.push(`${r.embedding.dimensions} dimensions`),console.log(`\u2713 Embedding${n.length?` (${n.join(", ")})`:""}`)}else console.log("\u2717 Embedding");(r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(""),console.log("Project data:"),r.memory!==void 0&&console.log(` Memories ${r.memory}`),r.graphSymbols!==void 0&&console.log(` Graph symbols ${r.graphSymbols}`),r.graphEdges!==void 0&&console.log(` Graph edges ${r.graphEdges}`),r.memoryVectors!==void 0&&console.log(` Memory vectors ${r.memoryVectors}`),r.codeChunks!==void 0&&console.log(` Code chunks ${r.codeChunks}`),r.codeVectors!==void 0&&console.log(` Code vectors ${r.codeVectors}`),r.snapshots!==void 0&&console.log(` Snapshots ${r.snapshots}`));let e=r.config?.errors??[];if(e.length>0){console.log(""),console.log("Configuration required:");for(let n of e)console.log(` - ${n}`)}let t=[...r.config?.warnings??[],...r.warnings??[]],o=[...new Set(t)];if(o.length>0){console.log(""),console.log("Warnings:");for(let n of o)console.log(` - ${n}`)}console.log(""),r.ok?console.log("\u2713 ToolNet Memory is ready"):(console.log("\u2717 ToolNet Memory requires attention"),e.length>0&&(console.log(""),console.log("Run:"),console.log(" toolnet-memory setup"))),console.log("")}function he(r){be()?console.log(JSON.stringify(r,null,2)):vt(r)}async function At(){let r=ye();if(!r.ok){let g={ok:!1,config:r,warnings:r.warnings};he(g),process.exitCode=1;return}let e=X(),t=new O().detect(),o=de(ae({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=ge(),i=w(),a;try{let h=await fe({id:i.llm.provider,apiKey:i.llm.apiKey,baseUrl:i.llm.baseUrl,model:i.llm.model,accountId:i.llm.accountId}).healthCheck();a={ok:h.ok,provider:i.llm.provider,model:h.model??i.llm.model,latencyMs:h.latencyMs,error:h.ok?void 0:h.message}}catch(g){a={ok:!1,provider:i.llm.provider,model:i.llm.model,error:g instanceof Error?g.message:String(g)}}let c=await new H(o,n).run(),d=await new j(o).load(t.id),m=await new R(o).load(t.id),p=await new x(o).load(t.id),u=await new C(o).load(t.id),_=await new M(o).load(t.id),Ee=await new V(o).list(t.id),Q={ok:c.ok&&!!a?.ok,project:t.name,storage:c.storage,llm:a,embedding:c.embedding,memory:d.length,graphSymbols:m?.symbols.length??0,graphEdges:m?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:u?.chunks.length??0,codeVectors:_?.records.length??0,snapshots:Ee.length,warnings:r.warnings};he(Q),process.exitCode=Q.ok?0:1}At().catch(r=>{let e=r instanceof Error?r.message:String(r);be()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});