toolnet-memory 0.3.3 → 0.3.5

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.
@@ -1,7 +1,7 @@
1
1
  import{readFileSync as Ue}from"node:fs";import{existsSync as Y,readFileSync as H}from"node:fs";import{homedir as G}from"node:os";import{join as W}from"node:path";function Q(o){let t=o.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
2
2
  `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function Z(){let o=process.env.TOOLNET_GLOBAL_ENV??W(G(),".config","toolnet-memory",".env");if(!Y(o))return;let t=H(o,"utf8");for(let e of t.split(/\r?\n/)){let r=e.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let n=r.indexOf("=");if(n<=0)continue;let s=r.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Q(r.slice(n+1)))}}Z();function l(o,t){return o===void 0?t:["1","true","yes","on"].includes(o.toLowerCase())}function m(o,t){if(!o)return t;let e=Number(o);return Number.isFinite(e)?e:t}function M(){return{memory:{autoCapture:l(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:l(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:l(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:l(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:m(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:m(process.env.MEMORY_RERANK_TOP,10),finalContext:m(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:m(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:l(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:m(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as X}from"node:crypto";import{existsSync as x,mkdirSync as q,readFileSync as ee,renameSync as te,writeFileSync as re}from"node:fs";import{basename as oe,dirname as h,join as w,parse as I,resolve as g}from"node:path";var E=".toolnet",ne="project.json";function se(o){return X("sha256").update(o).digest("hex").slice(0,16)}function b(o){return w(o,E,ne)}function ie(o){return x(b(o))}function ae(o,t){let e=g(o),r=I(e).root;for(;;){if(ie(e))return e;if(e===r||t&&e===g(t))break;let n=h(e);if(n===e)break;e=n}return null}function ce(o){let t=g(o),e=I(t).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>x(w(t,s))))return t;if(t===e)break;let n=h(t);if(n===t)break;t=n}return g(o)}function ue(o){let t;try{t=JSON.parse(ee(o,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${o}: ${n instanceof Error?n.message:String(n)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${o}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${o}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${o}`);let r=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:h(h(o)),createdAt:typeof e.createdAt=="string"?e.createdAt:r,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:r,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function C(o,t){let e=w(o,E);q(e,{recursive:!0});let r=b(o),n=`${r}.tmp-${process.pid}`;re(n,JSON.stringify(t,null,2)+`
3
- `,{encoding:"utf8",mode:384}),te(n,r)}function T(o,t){return{id:o.id,name:o.name,remote:o.remote,rootPath:t,createdAt:o.createdAt,updatedAt:o.updatedAt,graphVersion:o.graphVersion,memoryVersion:o.memoryVersion,metadata:o.metadata}}var S=class{detect(t=process.cwd()){let e=g(t),r=ce(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>x(w(r,p))),i=ae(e,s?r:void 0);if(i){let p=b(i),d=ue(p);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),C(i,d)),T(d,i)}let a=new Date().toISOString(),c=oe(r),u={version:1,id:se(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return C(r,u),T(u,r)}};import{homedir as Ee}from"node:os";import{join as Oe}from"node:path";import{DeleteObjectCommand as pe,GetObjectCommand as de,HeadObjectCommand as le,ListObjectsV2Command as me,PutObjectCommand as ge,S3Client as fe}from"@aws-sdk/client-s3";import{getSignedUrl as ye}from"@aws-sdk/s3-request-presigner";var j=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new fe({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new ge({Bucket:this.bucket,Key:t,Body:n,ContentType:r}))}async get(t){let e=await ye(this.client,new de({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new le({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new pe({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let n=await this.client.send(new me({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return e}};import{access as O,mkdir as he,readFile as Se,readdir as we,rm as je,stat as _,writeFile as ve}from"node:fs/promises";import{dirname as xe,join as be,relative as N,resolve as ke}from"node:path";var f=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return ke(this.root,e)}async put(t,e){let r=this.path(t);await he(xe(r),{recursive:!0}),await ve(r,e)}async get(t){try{return await Se(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await O(this.path(t)),!0}catch{return!1}}async delete(t){await je(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),r=[];try{await O(e)}catch{return r}let n=async i=>{let a=await we(i,{withFileTypes:!0});for(let c of a){let u=be(i,c.name);if(c.isDirectory()){await n(u);continue}let p=await _(u);r.push({key:N(this.root,u),size:p.size,updatedAt:p.mtime.toISOString()})}},s=await _(e);return s.isDirectory()?await n(e):r.push({key:N(this.root,e),size:s.size,updatedAt:s.mtime.toISOString()}),r}};import{DeleteObjectCommand as Pe,GetObjectCommand as Re,HeadObjectCommand as Ae,ListObjectsV2Command as Me,PutObjectCommand as Ce,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Ie}from"@aws-sdk/s3-request-presigner";var y=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Te({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Ce({Bucket:this.bucket,Key:t,Body:n,ContentType:r}))}async get(t){let e=await Ie(this.client,new Re({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new Ae({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Pe({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let n=await this.client.send(new Me({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return e}};function k(o,t){return console.warn(t),new f(o)}function $(o){let t=o.localRoot??Oe(Ee(),".toolnet-memory","storage");if(o.provider==="r2"){let e=o.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new y({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):k(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(o.provider==="s3"){let e=o.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new y({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):k(t,"[storage] S3 credentials missing. Using local fallback.")}if(o.provider==="huggingface"){let e=o.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new j({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):k(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new f(t)}function _e(o){return new Promise(t=>setTimeout(t,o))}async function K(o,t={}){let e=Math.max(1,t.attempts??3),r=t.baseDelayMs??150,n=t.maxDelayMs??2e3,s;for(let i=1;i<=e;i++)try{return await o()}catch(a){if(s=a,i>=e)break;let c=Math.min(n,r*2**(i-1)),u=Math.floor(Math.random()*Math.max(1,c*.2));await _e(c+u)}throw s}var Ne=new Set(["put","get","getText","delete","list"]);function D(o,t={}){return new Proxy(o,{get(e,r){let n=Reflect.get(e,r,e);return typeof n!="function"?n:Ne.has(r)?(...s)=>K(()=>Promise.resolve(n.apply(e,s)),t):n.bind(e)}})}function L(o){let t=o.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function z(o){let t=o.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let n=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:t))}var v=class{constructor(t,e,r,n){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=r,this.folder=L(n??r),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),r=e,n=await this.provider.getText(t);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${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"&&(r=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:e};await this.provider.put(t,JSON.stringify(s,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=z(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,e,r){return await this.ensureRegistered(),this.provider.put(this.key(t),e,r)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};import{existsSync as F,mkdirSync as Ke,readFileSync as De,statSync as B,writeFileSync as Le}from"node:fs";import{dirname as ze,join as Be}from"node:path";import{createHash as $e}from"node:crypto";function P(o){return $e("sha256").update(o).digest("hex")}var V=64*1024,Ve=`# ToolNet Project Operating Manual
3
+ `,{encoding:"utf8",mode:384}),te(n,r)}function T(o,t){return{id:o.id,name:o.name,remote:o.remote,rootPath:t,createdAt:o.createdAt,updatedAt:o.updatedAt,graphVersion:o.graphVersion,memoryVersion:o.memoryVersion,metadata:o.metadata}}var S=class{detect(t=process.cwd()){let e=g(t),r=ce(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>x(w(r,p))),i=ae(e,s?r:void 0);if(i){let p=b(i),d=ue(p);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),C(i,d)),T(d,i)}let a=new Date().toISOString(),c=oe(r),u={version:1,id:se(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return C(r,u),T(u,r)}};import{homedir as Ee}from"node:os";import{join as Oe}from"node:path";import{DeleteObjectCommand as pe,GetObjectCommand as de,HeadObjectCommand as le,ListObjectsV2Command as me,PutObjectCommand as ge,S3Client as fe}from"@aws-sdk/client-s3";import{getSignedUrl as ye}from"@aws-sdk/s3-request-presigner";var j=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new fe({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new ge({Bucket:this.bucket,Key:t,Body:n,ContentType:r}))}async get(t){let e=await ye(this.client,new de({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new le({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new pe({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let n=await this.client.send(new me({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return e}};import{access as O,mkdir as he,readFile as Se,readdir as we,rm as je,stat as _,writeFile as ve}from"node:fs/promises";import{dirname as xe,join as be,relative as N,resolve as ke}from"node:path";var f=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return ke(this.root,e)}async put(t,e){let r=this.path(t);await he(xe(r),{recursive:!0}),await ve(r,e)}async get(t){try{return await Se(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await O(this.path(t)),!0}catch{return!1}}async delete(t){await je(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),r=[];try{await O(e)}catch{return r}let n=async i=>{let a=await we(i,{withFileTypes:!0});for(let c of a){let u=be(i,c.name);if(c.isDirectory()){await n(u);continue}let p=await _(u);r.push({key:N(this.root,u),size:p.size,updatedAt:p.mtime.toISOString()})}},s=await _(e);return s.isDirectory()?await n(e):r.push({key:N(this.root,e),size:s.size,updatedAt:s.mtime.toISOString()}),r}};import{DeleteObjectCommand as Pe,GetObjectCommand as Re,HeadObjectCommand as Ae,ListObjectsV2Command as Me,PutObjectCommand as Ce,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Ie}from"@aws-sdk/s3-request-presigner";var y=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Te({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Ce({Bucket:this.bucket,Key:t,Body:n,ContentType:r}))}async get(t){let e=await Ie(this.client,new Re({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new Ae({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Pe({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let n=await this.client.send(new Me({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return e}};function k(o,t){return console.warn(t),new f(o)}function $(o){let t=o.localRoot??Oe(Ee(),".toolnet-memory","storage");if(o.provider==="r2"){let e=o.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new y({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):k(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(o.provider==="s3"){let e=o.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new y({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):k(t,"[storage] S3 credentials missing. Using local fallback.")}if(o.provider==="huggingface"){let e=o.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new j({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):k(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new f(t)}function _e(o){return new Promise(t=>setTimeout(t,o))}async function K(o,t={}){let e=Math.max(1,t.attempts??3),r=t.baseDelayMs??150,n=t.maxDelayMs??2e3,s;for(let i=1;i<=e;i++)try{return await o()}catch(a){if(s=a,i>=e)break;let c=Math.min(n,r*2**(i-1)),u=Math.floor(Math.random()*Math.max(1,c*.2));await _e(c+u)}throw s}var Ne=new Set(["put","get","getText","delete","list"]);function D(o,t={}){return new Proxy(o,{get(e,r){let n=Reflect.get(e,r,e);return typeof n!="function"?n:Ne.has(r)?(...s)=>K(()=>Promise.resolve(n.apply(e,s)),t):n.bind(e)}})}function z(o){let t=o.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function L(o){let t=o.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let n=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:t))}var v=class{constructor(t,e,r,n){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=r,this.folder=z(n??r),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),r=e,n=await this.provider.getText(t);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${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"&&(r=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:e};await this.provider.put(t,JSON.stringify(s,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=L(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,e,r){return await this.ensureRegistered(),this.provider.put(this.key(t),e,r)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};import{existsSync as F,mkdirSync as Ke,readFileSync as De,statSync as B,writeFileSync as ze}from"node:fs";import{dirname as Le,join as Be}from"node:path";import{createHash as $e}from"node:crypto";function P(o){return $e("sha256").update(o).digest("hex")}var V=64*1024,Ve=`# ToolNet Project Operating Manual
5
5
 
6
6
  This file contains persistent instructions for AI agents working on this project.
7
7
 
@@ -44,7 +44,7 @@ Things an AI agent should always remember.
44
44
  <!--
45
45
  - [advisory] Prefer small focused files.
46
46
  -->
47
- `;function J(o){return Be(o.rootPath,".toolnet","PROJECT.md")}function Fe(o){return o.normalize("NFKC").replace(/\s+/g," ").trim()}function Je(o){let t=[],e=new Set,r=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,n;for(;n=r.exec(o);){let s=n[1].toLowerCase(),i=Fe(n[2]);if(!i)continue;let a=`${s}:${i.toLowerCase()}`;e.has(a)||(e.add(a),t.push({id:P(a).slice(0,24),mode:s,text:i,source:"manual"}))}return t}function R(o){let t=J(o);return F(t)||(Ke(ze(t),{recursive:!0}),Le(t,Ve,{encoding:"utf8",mode:384})),t}function A(o,t=!1){let e=t?R(o):J(o);if(!F(e))return null;if(B(e).size>V)throw new Error(`PROJECT.md exceeds ${V} bytes`);let n=De(e,"utf8");return{path:e,content:n,digest:P(n),rules:Je(n),bytes:Buffer.byteLength(n,"utf8"),updatedAt:new Date(B(e).mtimeMs).toISOString()}}async function U(o,t){let e=A(o,!0);if(!e)throw new Error("Project manual unavailable");let r=`projects/${o.id}/project`;return await t.put(`${r}/manual.md`,e.content,"text/markdown"),await t.put(`${r}/manual.json`,JSON.stringify({version:1,projectId:o.id,projectName:o.name,digest:e.digest,bytes:e.bytes,ruleCount:e.rules.length,enforceRules:e.rules.filter(n=>n.mode==="enforce").length,advisoryRules:e.rules.filter(n=>n.mode==="advisory").length,updatedAt:e.updatedAt},null,2)+`
47
+ `;function J(o){return Be(o.rootPath,".toolnet","PROJECT.md")}function Fe(o){return o.normalize("NFKC").replace(/\s+/g," ").trim()}function Je(o){let t=[],e=new Set,r=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,n;for(;n=r.exec(o);){let s=n[1].toLowerCase(),i=Fe(n[2]);if(!i)continue;let a=`${s}:${i.toLowerCase()}`;e.has(a)||(e.add(a),t.push({id:P(a).slice(0,24),mode:s,text:i,source:"manual"}))}return t}function R(o){let t=J(o);return F(t)||(Ke(Le(t),{recursive:!0}),ze(t,Ve,{encoding:"utf8",mode:384})),t}function A(o,t=!1){let e=t?R(o):J(o);if(!F(e))return null;if(B(e).size>V)throw new Error(`PROJECT.md exceeds ${V} bytes`);let n=De(e,"utf8");return{path:e,content:n,digest:P(n),rules:Je(n),bytes:Buffer.byteLength(n,"utf8"),updatedAt:new Date(B(e).mtimeMs).toISOString()}}async function U(o,t){let e=A(o,!0);if(!e)throw new Error("Project manual unavailable");let r=`projects/${o.id}/project`;return await t.put(`${r}/manual.md`,e.content,"text/markdown"),await t.put(`${r}/manual.json`,JSON.stringify({version:1,projectId:o.id,projectName:o.name,digest:e.digest,bytes:e.bytes,ruleCount:e.rules.length,enforceRules:e.rules.filter(n=>n.mode==="enforce").length,advisoryRules:e.rules.filter(n=>n.mode==="advisory").length,updatedAt:e.updatedAt},null,2)+`
48
48
  `,"application/json"),e}function Ye(o,t){let e=o.indexOf(t);return e>=0?o[e+1]:void 0}function He(o){let t=M(),e=D($({provider:t.storage.provider,huggingface:t.storage.huggingface,localRoot:t.storage.localRoot}),{attempts:3});return new v(e,o.id,o.name,o.remote??o.name)}async function Ge(){let[o="help",...t]=process.argv.slice(2),e=new S().detect(Ye(t,"--project")??process.cwd());if(o==="init"){let r=R(e);console.log(`\u2705 Project manual: ${r}`);return}if(o==="show"){let r=A(e,!1);if(!r){console.log("No .toolnet/PROJECT.md yet.");return}process.stdout.write(Ue(r.path,"utf8"));return}if(o==="sync"){let r=await U(e,He(e));console.log(JSON.stringify({project:e.name,path:r.path,digest:r.digest,bytes:r.bytes,rules:r.rules.length,enforce:r.rules.filter(n=>n.mode==="enforce").length,advisory:r.rules.filter(n=>n.mode==="advisory").length},null,2));return}console.log(`Project Manual
49
49
 
50
50
  Commands:
@@ -1,3 +1,6 @@
1
- import"dotenv/config";var f=[{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 u(e){let o=f.find(r=>r.id===e);if(!o)throw new Error(`Unsupported AI provider: ${e}`);return o}function E(e){return f.some(o=>o.id===e)}function n(e){return process.env[e]?.trim()||void 0}function a(...e){return e.find(o=>!!o?.trim())}function M(){if(n("GROQ_API_KEY"))return"groq";if(n("DEEPSEEK_API_KEY"))return"deepseek";if(n("NVIDIA_API_KEY")||n("NVIDIA_NIM_API_KEY"))return"nvidia";if(n("OPENROUTER_API_KEY"))return"openrouter";if(n("ALIBABA_API_KEY")||n("DASHSCOPE_API_KEY"))return"alibaba";if(n("GEMINI_API_KEY")||n("GOOGLE_API_KEY"))return"gemini";if(n("CLOUDFLARE_API_TOKEN")&&n("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(n("HF_TOKEN"))return"huggingface";if(n("OLLAMA_MODEL")||n("OLLAMA_BASE_URL"))return"ollama"}function w(){let e=n("TOOLNET_LLM_PROVIDER");return e&&E(e)?e:M()??"openai-compatible"}function b(e){let o=u(e);switch(e){case"alibaba":return{provider:e,apiKey:a(n("ALIBABA_API_KEY"),n("DASHSCOPE_API_KEY")),baseUrl:a(n("ALIBABA_BASE_URL"),n("DASHSCOPE_BASE_URL"),o.defaultBaseUrl),model:a(n("ALIBABA_MODEL"),n("DASHSCOPE_MODEL"))};case"openrouter":return{provider:e,apiKey:n("OPENROUTER_API_KEY"),baseUrl:a(n("OPENROUTER_BASE_URL"),o.defaultBaseUrl),model:n("OPENROUTER_MODEL")};case"groq":return{provider:e,apiKey:n("GROQ_API_KEY"),baseUrl:a(n("GROQ_BASE_URL"),o.defaultBaseUrl),model:n("GROQ_MODEL")};case"deepseek":return{provider:e,apiKey:n("DEEPSEEK_API_KEY"),baseUrl:a(n("DEEPSEEK_BASE_URL"),o.defaultBaseUrl),model:a(n("DEEPSEEK_MODEL"),o.defaultModel)};case"nvidia":return{provider:e,apiKey:a(n("NVIDIA_API_KEY"),n("NVIDIA_NIM_API_KEY")),baseUrl:a(n("NVIDIA_BASE_URL"),n("NVIDIA_NIM_BASE_URL"),o.defaultBaseUrl),model:a(n("NVIDIA_MODEL"),n("NVIDIA_NIM_MODEL"),o.defaultModel)};case"gemini":return{provider:e,apiKey:a(n("GEMINI_API_KEY"),n("GOOGLE_API_KEY")),baseUrl:a(n("GEMINI_BASE_URL"),o.defaultBaseUrl),model:n("GEMINI_MODEL")};case"huggingface":return{provider:e,apiKey:n("HF_TOKEN"),baseUrl:a(n("HF_INFERENCE_BASE_URL"),o.defaultBaseUrl),model:a(n("HF_LLM_MODEL"),n("HF_MODEL"))};case"ollama":return{provider:e,apiKey:n("OLLAMA_API_KEY"),baseUrl:a(n("OLLAMA_BASE_URL"),o.defaultBaseUrl),model:n("OLLAMA_MODEL")};case"cloudflare":return{provider:e,accountId:n("CLOUDFLARE_ACCOUNT_ID"),apiKey:n("CLOUDFLARE_API_TOKEN"),baseUrl:n("CLOUDFLARE_AI_BASE_URL"),model:n("CLOUDFLARE_MODEL")};case"custom":return{provider:e,apiKey:n("CUSTOM_AI_API_KEY"),baseUrl:n("CUSTOM_AI_BASE_URL"),model:n("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:a(n("OPENAI_API_KEY"),n("MODEL_API_KEY")),baseUrl:a(n("OPENAI_BASE_URL"),n("MODEL_BASE_URL")),model:a(n("OPENAI_MODEL"),n("MODEL_NAME"))}}}function k(){let e=n("TOOLNET_LLM_PROVIDER"),o=e&&E(e)?e:w(),r=u(o),t=b(o);return{provider:o,apiKey:a(n("TOOLNET_LLM_API_KEY"),t.apiKey),baseUrl:a(n("TOOLNET_LLM_BASE_URL"),t.baseUrl,r.defaultBaseUrl),model:a(n("TOOLNET_LLM_MODEL"),t.model,r.defaultModel),accountId:a(n("TOOLNET_LLM_ACCOUNT_ID"),t.accountId)}}function $(){let e=n("TOOLNET_EMBEDDING_PROVIDER");return e==="local"?"local":e&&E(e)?e:n("HF_TOKEN")||n("HF_EMBEDDING_MODEL")?"huggingface":"local"}function S(){let e=$();if(e==="local")return{provider:"local",model:a(n("TOOLNET_EMBEDDING_MODEL"),n("LOCAL_EMBEDDING_MODEL"))};let o=u(e),r,t,i,s;switch(e){case"huggingface":r=n("HF_TOKEN"),t=n("HF_INFERENCE_BASE_URL"),i=n("HF_EMBEDDING_MODEL");break;case"openai-compatible":r=n("OPENAI_API_KEY"),t=n("OPENAI_BASE_URL"),i=n("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":r=n("CLOUDFLARE_API_TOKEN"),t=n("CLOUDFLARE_AI_BASE_URL"),i=n("CLOUDFLARE_EMBEDDING_MODEL"),s=n("CLOUDFLARE_ACCOUNT_ID");break;default:r=b(e).apiKey,t=b(e).baseUrl,i=n(`${e.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let l=a(n("TOOLNET_EMBEDDING_ACCOUNT_ID"),s),d=a(n("TOOLNET_EMBEDDING_BASE_URL"),t,o.defaultBaseUrl),c=e==="cloudflare"&&!d&&l?`https://api.cloudflare.com/client/v4/accounts/${l}/ai/v1`:d;return{provider:e,apiKey:a(n("TOOLNET_EMBEDDING_API_KEY"),r),baseUrl:c,model:a(n("TOOLNET_EMBEDDING_MODEL"),i),accountId:l}}function p(){let e=k(),o=S();return{llm:e,embedding:o,legacy:{llm:!n("TOOLNET_LLM_PROVIDER")&&!!M(),embedding:!n("TOOLNET_EMBEDDING_PROVIDER")&&!!(n("HF_TOKEN")||n("HF_EMBEDDING_MODEL"))}}}function R(e=w()){let o=p().llm;if(e===o.provider)return{id:e,apiKey:o.apiKey,baseUrl:o.baseUrl,model:o.model,accountId:o.accountId};let r=b(e);return{id:e,apiKey:r.apiKey,baseUrl:r.baseUrl,model:r.model,accountId:r.accountId}}var P=class extends Error{status;constructor(o,r){super(o),this.name="AiHttpError",this.status=r}};async function g(e,o,r=3e4){let t=new AbortController,i=setTimeout(()=>t.abort(),r);i.unref?.();try{let s=await fetch(e,{...o,signal:t.signal}),l=await s.text();if(!s.ok){let d=l;try{let c=JSON.parse(l);d=c.error?.message??c.message??l}catch{}throw new P(d||`HTTP ${s.status}`,s.status)}return l.trim()?JSON.parse(l):{}}finally{clearTimeout(i)}}function A(e,o){return`${e.replace(/\/+$/,"")}/${o.replace(/^\/+/,"")}`}var y=class{constructor(o){this.config=o}config;id="cloudflare";model(){let o=this.config.model?.trim();if(!o)throw new Error("cloudflare: MODEL is not configured");return o}async generate(o){let r=this.config.accountId?.trim(),t=this.config.apiKey?.trim();if(!r)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!t)throw new Error("cloudflare: API TOKEN is not configured");let i=this.model(),l=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${r}/ai/run`).replace(/\/+$/,"")}/${i}`,d=await g(l,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens})}),c=d.result?.response?.trim();if(!c)throw new Error(d.errors?.[0]?.message??"cloudflare: empty model response");return{text:c,provider:"cloudflare",model:i}}async healthCheck(){let o=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()-o}}catch(r){return{ok:!1,provider:"cloudflare",model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};var _=class{constructor(o){this.config=o}config;id="gemini";model(){let o=this.config.model?.trim();if(!o)throw new Error("gemini: MODEL is not configured");return o.replace(/^models\//,"")}async generate(o){let r=this.config.apiKey?.trim();if(!r)throw new Error("gemini: API KEY is not configured");let t=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",i=this.model(),s=o.messages.filter(m=>m.role==="system"),l=o.messages.filter(m=>m.role!=="system").map(m=>({role:m.role==="assistant"?"model":"user",parts:[{text:m.content}]})),d=`${A(t,`models/${encodeURIComponent(i)}:generateContent`)}?key=${encodeURIComponent(r)}`,c=await g(d,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...s.length?{systemInstruction:{parts:[{text:s.map(m=>m.content).join(`
1
+ import"dotenv/config";var h=[{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(e){let r=h.find(t=>t.id===e);if(!r)throw new Error(`Unsupported AI provider: ${e}`);return r}function E(e){return h.some(r=>r.id===e)}function o(e){return process.env[e]?.trim()||void 0}function a(...e){return e.find(r=>!!r?.trim())}function T(){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 C(){let e=o("TOOLNET_LLM_PROVIDER");return e&&E(e)?e:T()??"openai-compatible"}function y(e){let r=g(e);switch(e){case"alibaba":return{provider:e,apiKey:a(o("ALIBABA_API_KEY"),o("DASHSCOPE_API_KEY")),baseUrl:a(o("ALIBABA_BASE_URL"),o("DASHSCOPE_BASE_URL"),r.defaultBaseUrl),model:a(o("ALIBABA_MODEL"),o("DASHSCOPE_MODEL"))};case"openrouter":return{provider:e,apiKey:o("OPENROUTER_API_KEY"),baseUrl:a(o("OPENROUTER_BASE_URL"),r.defaultBaseUrl),model:o("OPENROUTER_MODEL")};case"groq":return{provider:e,apiKey:o("GROQ_API_KEY"),baseUrl:a(o("GROQ_BASE_URL"),r.defaultBaseUrl),model:o("GROQ_MODEL")};case"deepseek":return{provider:e,apiKey:o("DEEPSEEK_API_KEY"),baseUrl:a(o("DEEPSEEK_BASE_URL"),r.defaultBaseUrl),model:a(o("DEEPSEEK_MODEL"),r.defaultModel)};case"nvidia":return{provider:e,apiKey:a(o("NVIDIA_API_KEY"),o("NVIDIA_NIM_API_KEY")),baseUrl:a(o("NVIDIA_BASE_URL"),o("NVIDIA_NIM_BASE_URL"),r.defaultBaseUrl),model:a(o("NVIDIA_MODEL"),o("NVIDIA_NIM_MODEL"),r.defaultModel)};case"gemini":return{provider:e,apiKey:a(o("GEMINI_API_KEY"),o("GOOGLE_API_KEY")),baseUrl:a(o("GEMINI_BASE_URL"),r.defaultBaseUrl),model:o("GEMINI_MODEL")};case"huggingface":return{provider:e,apiKey:o("HF_TOKEN"),baseUrl:a(o("HF_INFERENCE_BASE_URL"),r.defaultBaseUrl),model:a(o("HF_LLM_MODEL"),o("HF_MODEL"))};case"ollama":return{provider:e,apiKey:o("OLLAMA_API_KEY"),baseUrl:a(o("OLLAMA_BASE_URL"),r.defaultBaseUrl),model:o("OLLAMA_MODEL")};case"cloudflare":return{provider:e,accountId:o("CLOUDFLARE_ACCOUNT_ID"),apiKey:o("CLOUDFLARE_API_TOKEN"),baseUrl:o("CLOUDFLARE_AI_BASE_URL"),model:o("CLOUDFLARE_MODEL")};case"custom":return{provider:e,apiKey:o("CUSTOM_AI_API_KEY"),baseUrl:o("CUSTOM_AI_BASE_URL"),model:o("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:a(o("OPENAI_API_KEY"),o("MODEL_API_KEY")),baseUrl:a(o("OPENAI_BASE_URL"),o("MODEL_BASE_URL")),model:a(o("OPENAI_MODEL"),o("MODEL_NAME"))}}}function F(){let e=o("TOOLNET_LLM_PROVIDER"),r=e&&E(e)?e:C(),t=g(r),i=y(r);return{provider:r,apiKey:a(o("TOOLNET_LLM_API_KEY"),i.apiKey),baseUrl:a(o("TOOLNET_LLM_BASE_URL"),i.baseUrl,t.defaultBaseUrl),model:a(o("TOOLNET_LLM_MODEL"),i.model,t.defaultModel),accountId:a(o("TOOLNET_LLM_ACCOUNT_ID"),i.accountId)}}function H(){let e=o("TOOLNET_EMBEDDING_PROVIDER");return e==="local"?"local":e&&E(e)?e:o("HF_TOKEN")||o("HF_EMBEDDING_MODEL")?"huggingface":"local"}function Y(){let e=H();if(e==="local")return{provider:"local",model:a(o("TOOLNET_EMBEDDING_MODEL"),o("LOCAL_EMBEDDING_MODEL"))};let r=g(e),t,i,n,s;switch(e){case"huggingface":t=o("HF_TOKEN"),i=o("HF_INFERENCE_BASE_URL"),n=o("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=o("OPENAI_API_KEY"),i=o("OPENAI_BASE_URL"),n=o("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=o("CLOUDFLARE_API_TOKEN"),i=o("CLOUDFLARE_AI_BASE_URL"),n=o("CLOUDFLARE_EMBEDDING_MODEL"),s=o("CLOUDFLARE_ACCOUNT_ID");break;default:t=y(e).apiKey,i=y(e).baseUrl,n=o(`${e.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let l=a(o("TOOLNET_EMBEDDING_ACCOUNT_ID"),s),d=a(o("TOOLNET_EMBEDDING_BASE_URL"),i,r.defaultBaseUrl),m=e==="cloudflare"&&!d&&l?`https://api.cloudflare.com/client/v4/accounts/${l}/ai/v1`:d;return{provider:e,apiKey:a(o("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:m,model:a(o("TOOLNET_EMBEDDING_MODEL"),n),accountId:l}}function u(){let e=F(),r=Y();return{llm:e,embedding:r,legacy:{llm:!o("TOOLNET_LLM_PROVIDER")&&!!T(),embedding:!o("TOOLNET_EMBEDDING_PROVIDER")&&!!(o("HF_TOKEN")||o("HF_EMBEDDING_MODEL"))}}}function N(e=C()){let r=u().llm;if(e===r.provider)return{id:e,apiKey:r.apiKey,baseUrl:r.baseUrl,model:r.model,accountId:r.accountId};let t=y(e);return{id:e,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}var U=class extends Error{status;constructor(r,t){super(r),this.name="AiHttpError",this.status=t}};async function f(e,r,t=3e4){let i=new AbortController,n=setTimeout(()=>i.abort(),t);n.unref?.();try{let s=await fetch(e,{...r,signal:i.signal}),l=await s.text();if(!s.ok){let d=l;try{let m=JSON.parse(l);d=m.error?.message??m.message??l}catch{}throw new U(d||`HTTP ${s.status}`,s.status)}return l.trim()?JSON.parse(l):{}}finally{clearTimeout(n)}}function A(e,r){return`${e.replace(/\/+$/,"")}/${r.replace(/^\/+/,"")}`}var v=class{constructor(r){this.config=r}config;id="cloudflare";model(){let r=this.config.model?.trim();if(!r)throw new Error("cloudflare: MODEL is not configured");return r}async generate(r){let t=this.config.accountId?.trim(),i=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!i)throw new Error("cloudflare: API TOKEN is not configured");let n=this.model(),l=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${n}`,d=await f(l,{method:"POST",headers:{authorization:`Bearer ${i}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:r.messages,temperature:r.temperature,max_tokens:r.maxTokens})}),m=d.result?.response?.trim();if(!m)throw new Error(d.errors?.[0]?.message??"cloudflare: empty model response");return{text:m,provider:"cloudflare",model:n}}async healthCheck(){let r=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()-r}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-r}}}};var _=class{constructor(r){this.config=r}config;id="gemini";model(){let r=this.config.model?.trim();if(!r)throw new Error("gemini: MODEL is not configured");return r.replace(/^models\//,"")}async generate(r){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let i=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",n=this.model(),s=r.messages.filter(p=>p.role==="system"),l=r.messages.filter(p=>p.role!=="system").map(p=>({role:p.role==="assistant"?"model":"user",parts:[{text:p.content}]})),d=`${A(i,`models/${encodeURIComponent(n)}:generateContent`)}?key=${encodeURIComponent(t)}`,m=await f(d,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...s.length?{systemInstruction:{parts:[{text:s.map(p=>p.content).join(`
2
2
 
3
- `)}]}}:{},contents:l,generationConfig:{temperature:o.temperature,maxOutputTokens:o.maxTokens}})}),D=c.candidates?.[0]?.content?.parts?.map(m=>m.text??"").join("").trim();if(!D)throw new Error("gemini: empty model response");return{text:D,provider:"gemini",model:i,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let o=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()-o}}catch(r){return{ok:!1,provider:"gemini",model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};var h=class{constructor(o){this.config=o;this.id=o.id}config;id;baseUrl(){let o=this.config.baseUrl?.trim();if(!o)throw new Error(`${this.id}: BASE URL is not configured`);return o}model(){let o=this.config.model?.trim();if(!o)throw new Error(`${this.id}: MODEL is not configured`);return o}headers(){let o={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(o.authorization=`Bearer ${this.config.apiKey}`),o}async generate(o){let r=this.model(),t=await g(A(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:r,messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),i=t.choices?.[0]?.message?.content?.trim();if(!i)throw new Error(`${this.id}: empty model response`);return{text:i,provider:this.id,model:r,usage:t.usage?{inputTokens:t.usage.prompt_tokens,outputTokens:t.usage.completion_tokens,totalTokens:t.usage.total_tokens}:void 0}}async healthCheck(){let o=Date.now();try{let r=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:r.model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(r){return{ok:!1,provider:this.id,model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};function N(e=R()){switch(u(e.id).transport){case"gemini":return new _(e);case"cloudflare":return new y(e);default:return new h(e)}}var v=class{constructor(o){this.options=o}options;name="gemini";async embed(o){let r=this.options.model.replace(/^models\//,""),i=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(r)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,s=await fetch(i,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${r}`,content:{parts:[{text:o}]}})});if(!s.ok)throw new Error(`Gemini embedding failed: ${s.status} ${await s.text()}`);let d=(await s.json()).embedding?.values;if(!Array.isArray(d)||d.length===0)throw new Error("Gemini embedding returned invalid response");return d}async embedMany(o){let r=[];for(let t of o)r.push(await this.embed(t));return r}};import{createHash as x}from"node:crypto";var O=class{name="hash-fallback";dimensions=128;async embed(o){let r=new Array(this.dimensions).fill(0),t=o.toLowerCase().split(/\s+/).filter(Boolean);for(let i of t){let l=x("sha256").update(i).digest().readUInt32BE(0)%this.dimensions;r[l]+=1}return G(r)}async embedMany(o){return Promise.all(o.map(r=>this.embed(r)))}};function G(e){let o=Math.sqrt(e.reduce((r,t)=>r+t*t,0));return o===0?e:e.map(r=>r/o)}var I=class{constructor(o){this.options=o;this.dimensions=o.dimensions}options;name="openai-compatible";dimensions;async embed(o){let[r]=await this.embedMany([o]);return r}async embedMany(o){if(o.length===0)return[];let r=this.options.baseUrl.replace(/\/+$/,""),t=await fetch(`${r}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:o})});if(!t.ok)throw new Error(`Embedding failed: ${t.status} ${await t.text()}`);let s=(await t.json()).data?.sort((l,d)=>(l.index??0)-(d.index??0)).map(l=>l.embedding);if(!s||s.length!==o.length||s.some(l=>!Array.isArray(l)))throw new Error("Embedding provider returned invalid response");return s}};var L=class{constructor(o){this.options=o}options;name="huggingface";dimensions=384;async embed(o){let[r]=await this.embedMany([o]);return r}async embedMany(o){if(o.length===0)return[];let r=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,t=await fetch(r,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:o,options:{wait_for_model:!0}})});if(!t.ok)throw new Error(`HF embedding failed: ${t.status} ${await t.text()}`);let i=await t.json();if(!Array.isArray(i))throw new Error("HF embedding returned invalid response");return i.map(s=>F(s))}};function F(e){if(!Array.isArray(e))throw new Error("Invalid embedding");if(e.length>0&&typeof e[0]=="number")return e;if(e.length>0&&Array.isArray(e[0])){let o=e;if(o.length===0)return[];let r=o[0].length,t=new Array(r).fill(0);for(let i of o)for(let s=0;s<r;s++)t[s]+=i[s]??0;for(let i=0;i<r;i++)t[i]/=o.length;return t}throw new Error("Unsupported embedding shape")}var U=class{constructor(o,r=new O){this.primary=o;this.fallback=r}primary;fallback;name="resilient";async embed(o){if(this.primary)try{return await this.primary.embed(o)}catch(r){console.warn("[embedding] primary failed, fallback enabled:",r instanceof Error?r.message:r)}return this.fallback.embed(o)}async embedMany(o){if(this.primary)try{return await this.primary.embedMany(o)}catch(r){console.warn("[embedding] primary failed, fallback enabled:",r instanceof Error?r.message:r)}return this.fallback.embedMany(o)}};function H(e){return`https://api.cloudflare.com/client/v4/accounts/${e}/ai/v1`}function Y(){let e=p().embedding;if(e.provider==="local")return null;if(e.provider==="huggingface")return!e.apiKey||!e.model?null:new L({token:e.apiKey,model:e.model});if(e.provider==="gemini")return!e.apiKey||!e.model?null:new v({apiKey:e.apiKey,model:e.model,baseUrl:e.baseUrl});let o=e.baseUrl;return e.provider==="cloudflare"&&!o&&e.accountId&&(o=H(e.accountId)),o&&e.model?new I({apiKey:e.apiKey,baseUrl:o,model:e.model}):null}function T(){return new U(Y())}function K(e){return e?e.length<=8?"********":`${e.slice(0,4)}...${e.slice(-4)}`:"not configured"}function j(){console.log(""),console.log("ToolNet AI Providers"),console.log("===================="),console.log("");for(let e of f)console.log(`- ${e.label}`),console.log(` id : ${e.id}`),console.log(` protocol : ${e.transport}`),e.defaultBaseUrl&&console.log(` base URL : ${e.defaultBaseUrl}`),e.defaultModel&&console.log(` model : ${e.defaultModel}`),console.log("");console.log("- Local / Hash embedding"),console.log(" id : local"),console.log(" protocol : local"),console.log("")}function q(){let e=p();console.log(""),console.log("ToolNet Provider Status"),console.log("======================="),console.log(""),console.log("LLM"),console.log(` Provider : ${e.llm.provider}`),console.log(` Model : ${e.llm.model??"not configured"}`),console.log(` Base URL : ${e.llm.baseUrl??"default/provider native"}`),console.log(` API Key : ${K(e.llm.apiKey)}`),e.llm.accountId&&console.log(` Account : ${e.llm.accountId}`),console.log(` Legacy : ${e.legacy.llm?"yes":"no"}`),console.log(""),console.log("Embedding"),console.log(` Provider : ${e.embedding.provider}`),console.log(` Model : ${e.embedding.model??(e.embedding.provider==="local"?"local hash":"not configured")}`),console.log(` Base URL : ${e.embedding.baseUrl??(e.embedding.provider==="local"?"local":"default/provider native")}`),console.log(` API Key : ${e.embedding.provider==="local"?"not required":K(e.embedding.apiKey)}`),e.embedding.accountId&&console.log(` Account : ${e.embedding.accountId}`),console.log(` Legacy : ${e.legacy.embedding?"yes":"no"}`),console.log("")}async function C(){let e=p().llm;console.log(""),console.log("Testing LLM"),console.log("-----------"),console.log(`Provider : ${e.provider}`),console.log(`Model : ${e.model??"not configured"}`);try{let r=await N({id:e.provider,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId}).healthCheck();return r.ok?(console.log("\u2713 Provider reachable"),r.latencyMs!==void 0&&console.log(`\u2713 Latency: ${r.latencyMs} ms`),console.log(""),!0):(console.log(`\u2717 ${r.message}`),!1)}catch(o){return console.log(`\u2717 ${o instanceof Error?o.message:String(o)}`),console.log(""),!1}}async function B(){let e=p().embedding;console.log(""),console.log("Testing Embedding"),console.log("-----------------"),console.log(`Provider : ${e.provider}`),console.log(`Model : ${e.model??(e.provider==="local"?"local hash":"not configured")}`);try{let r=await T().embed("ToolNet Memory provider health check");if(!Array.isArray(r)||r.length===0)throw new Error("Empty embedding vector");return console.log("\u2713 Embedding ready"),console.log(`\u2713 Dimensions: ${r.length}`),console.log(""),!0}catch(o){return console.log(`\u2717 ${o instanceof Error?o.message:String(o)}`),console.log(""),!1}}async function V(){let e=await C(),o=await B();return console.log(""),console.log("Provider Test Summary"),console.log("====================="),console.log(`LLM : ${e?"READY":"FAILED"}`),console.log(`Embedding : ${o?"READY":"FAILED"}`),console.log(""),e&&o}async function J(){let e=process.argv[2]??"status";if(e==="list"){j();return}if(e==="status"){q();return}if(e==="test"){let o=process.argv[3]??"all",r=!1;o==="llm"?r=await C():o==="embedding"?r=await B():r=await V(),process.exitCode=r?0:1;return}console.error(`Unknown provider command: ${e}`),console.error(""),console.error("Usage:"),console.error(" toolnet-memory provider:list"),console.error(" toolnet-memory provider:status"),console.error(" toolnet-memory provider:test"),console.error(" toolnet-memory provider:test llm"),console.error(" toolnet-memory provider:test embedding"),process.exitCode=1}J().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});
3
+ `)}]}}:{},contents:l,generationConfig:{temperature:r.temperature,maxOutputTokens:r.maxTokens}})}),D=m.candidates?.[0]?.content?.parts?.map(p=>p.text??"").join("").trim();if(!D)throw new Error("gemini: empty model response");return{text:D,provider:"gemini",model:n,usage:m.usageMetadata?{inputTokens:m.usageMetadata.promptTokenCount,outputTokens:m.usageMetadata.candidatesTokenCount,totalTokens:m.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let r=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()-r}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-r}}}};var O=class{constructor(r){this.config=r;this.id=r.id}config;id;baseUrl(){let r=this.config.baseUrl?.trim();if(!r)throw new Error(`${this.id}: BASE URL is not configured`);return r}model(){let r=this.config.model?.trim();if(!r)throw new Error(`${this.id}: MODEL is not configured`);return r}headers(){let r={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(r.authorization=`Bearer ${this.config.apiKey}`),r}async generate(r){let t=this.model(),i=await f(A(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:r.messages,temperature:r.temperature,max_tokens:r.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),n=i.choices?.[0]?.message?.content?.trim();if(!n)throw new Error(`${this.id}: empty model response`);return{text:n,provider:this.id,model:t,usage:i.usage?{inputTokens:i.usage.prompt_tokens,outputTokens:i.usage.completion_tokens,totalTokens:i.usage.total_tokens}:void 0}}async healthCheck(){let r=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()-r}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-r}}}};function R(e=N()){switch(g(e.id).transport){case"gemini":return new _(e);case"cloudflare":return new v(e);default:return new O(e)}}var I=class{constructor(r){this.options=r}options;name="gemini";async embed(r){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:r}]}})});if(!s.ok)throw new Error(`Gemini embedding failed: ${s.status} ${await s.text()}`);let d=(await s.json()).embedding?.values;if(!Array.isArray(d)||d.length===0)throw new Error("Gemini embedding returned invalid response");return d}async embedMany(r){let t=[];for(let i of r)t.push(await this.embed(i));return t}};import{createHash as j}from"node:crypto";var L=class{name="hash-fallback";dimensions=128;async embed(r){let t=new Array(this.dimensions).fill(0),i=r.toLowerCase().split(/\s+/).filter(Boolean);for(let n of i){let l=j("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[l]+=1}return q(t)}async embedMany(r){return Promise.all(r.map(t=>this.embed(t)))}};function q(e){let r=Math.sqrt(e.reduce((t,i)=>t+i*i,0));return r===0?e:e.map(t=>t/r)}var P=class{constructor(r){this.options=r;this.dimensions=r.dimensions}options;name="openai-compatible";dimensions;async embed(r){let[t]=await this.embedMany([r]);return t}async embedMany(r){if(r.length===0)return[];let t=this.options.baseUrl.replace(/\/+$/,""),i=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:r})});if(!i.ok)throw new Error(`Embedding failed: ${i.status} ${await i.text()}`);let s=(await i.json()).data?.sort((l,d)=>(l.index??0)-(d.index??0)).map(l=>l.embedding);if(!s||s.length!==r.length||s.some(l=>!Array.isArray(l)))throw new Error("Embedding provider returned invalid response");return s}};var M=class{constructor(r){this.options=r}options;name="huggingface";dimensions=384;async embed(r){let[t]=await this.embedMany([r]);return t}async embedMany(r){if(r.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,i=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:r,options:{wait_for_model:!0}})});if(!i.ok)throw new Error(`HF embedding failed: ${i.status} ${await i.text()}`);let n=await i.json();if(!Array.isArray(n))throw new Error("HF embedding returned invalid response");return n.map(s=>V(s))}};function V(e){if(!Array.isArray(e))throw new Error("Invalid embedding");if(e.length>0&&typeof e[0]=="number")return e;if(e.length>0&&Array.isArray(e[0])){let r=e;if(r.length===0)return[];let t=r[0].length,i=new Array(t).fill(0);for(let n of r)for(let s=0;s<t;s++)i[s]+=n[s]??0;for(let n=0;n<t;n++)i[n]/=r.length;return i}throw new Error("Unsupported embedding shape")}var w=class{constructor(r,t=new L){this.primary=r;this.fallback=t}primary;fallback;name="resilient";async embed(r){if(this.primary)try{return await this.primary.embed(r)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(r)}async embedMany(r){if(this.primary)try{return await this.primary.embedMany(r)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(r)}};function J(e){return`https://api.cloudflare.com/client/v4/accounts/${e}/ai/v1`}function z(){let e=u().embedding;if(e.provider==="local")return null;if(e.provider==="huggingface")return!e.apiKey||!e.model?null:new M({token:e.apiKey,model:e.model});if(e.provider==="gemini")return!e.apiKey||!e.model?null:new I({apiKey:e.apiKey,model:e.model,baseUrl:e.baseUrl});let r=e.baseUrl;return e.provider==="cloudflare"&&!r&&e.accountId&&(r=J(e.accountId)),r&&e.model?new P({apiKey:e.apiKey,baseUrl:r,model:e.model}):null}function K(){return new w(z())}var $=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],c={clear:"\r\x1B[2K",cyan:"\x1B[36m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",amber:"\x1B[38;5;214m",dim:"\x1B[2m",reset:"\x1B[0m"};function B(e,r=16){let i=Math.max(1,r-4+1),n=e%i;return"\u2500".repeat(n)+"\u2501".repeat(4)+"\u2500".repeat(Math.max(0,r-n-4))}function k(e){let r=Date.now()-e;return r<1e3?`${r}ms`:r<1e4?`${(r/1e3).toFixed(1)}s`:`${Math.round(r/1e3)}s`}var b=class{stream;enabled;interactive;color;intervalMs;display;label;frame=0;startedAt=0;timer;active=!1;constructor(r,t={}){this.label=r,this.stream=t.stream??process.stderr,this.enabled=t.enabled??!0,this.interactive=t.interactive??this.stream.isTTY===!0,this.color=t.color??(this.interactive&&process.env.NO_COLOR===void 0),this.intervalMs=Math.max(40,t.intervalMs??80),this.display=t.display??"spinner"}start(){return!this.enabled||this.active?this:(this.active=!0,this.startedAt=Date.now(),this.interactive?(this.render(),this.timer=setInterval(()=>{this.frame=(this.frame+1)%1e4,this.render()},this.intervalMs),this.timer.unref?.(),this):(this.stream.write(`\u2192 ${this.label}
4
+ `),this))}update(r){return this.label=r,this.enabled&&this.active&&this.interactive&&this.render(),this}succeed(r){this.finish("\u2713",r??this.label,c.green)}fail(r){this.finish("\u2717",r??this.label,c.red)}warn(r){this.finish("!",r??this.label,c.yellow)}stop(){this.active&&(this.timer&&(clearInterval(this.timer),this.timer=void 0),this.enabled&&this.interactive&&this.stream.write(c.clear),this.active=!1)}render(){if(!this.enabled||!this.active||!this.interactive)return;let r=$[this.frame%$.length],t=this.display==="bar"?this.color?`${c.amber}${B(this.frame)}${c.reset}`:B(this.frame):this.color?`${c.cyan}${r}${c.reset}`:r,i=k(this.startedAt),n=this.color?`${c.dim}${i}${c.reset}`:i;this.stream.write(`${c.clear}${t} ${this.label} ${n}`)}finish(r,t,i){if(!this.enabled){this.active=!1;return}this.startedAt||(this.startedAt=Date.now()),this.timer&&(clearInterval(this.timer),this.timer=void 0);let n=k(this.startedAt),s=this.color?`${i}${r}${c.reset}`:r,l=this.color?`${c.dim}${n}${c.reset}`:n;this.interactive?this.stream.write(`${c.clear}${s} ${t} ${l}
5
+ `):this.stream.write(`${s} ${t} (${n})
6
+ `),this.active=!1}};function x(e){return e?e.length<=8?"********":`${e.slice(0,4)}...${e.slice(-4)}`:"not configured"}function W(){console.log(""),console.log("ToolNet AI Providers"),console.log("===================="),console.log("");for(let e of h)console.log(`- ${e.label}`),console.log(` id : ${e.id}`),console.log(` protocol : ${e.transport}`),e.defaultBaseUrl&&console.log(` base URL : ${e.defaultBaseUrl}`),e.defaultModel&&console.log(` model : ${e.defaultModel}`),console.log("");console.log("- Local / Hash embedding"),console.log(" id : local"),console.log(" protocol : local"),console.log("")}function Q(){let e=u();console.log(""),console.log("\u25C7 ToolNet AI Providers"),console.log(""),console.log("\u25C6 Configuration"),console.log("\u2502"),console.log(`\u251C \u25C6 LLM \u2014 ${e.llm.provider}`),console.log(`\u2502 Model \u2014 ${e.llm.model??"not configured"}`),console.log(`\u2502 Base URL \u2014 ${e.llm.baseUrl??"default/provider native"}`),console.log(`\u2502 API Key \u2014 ${x(e.llm.apiKey)}`),e.llm.accountId&&console.log(`\u2502 Account \u2014 ${e.llm.accountId}`),console.log(`\u2502 Legacy \u2014 ${e.legacy.llm?"yes":"no"}`),console.log("\u2502"),console.log(`\u251C \u25C6 Embedding \u2014 ${e.embedding.provider}`),console.log(`\u2502 Model \u2014 ${e.embedding.model??(e.embedding.provider==="local"?"local hash":"not configured")}`),console.log(`\u2502 Base URL \u2014 ${e.embedding.baseUrl??(e.embedding.provider==="local"?"local":"default/provider native")}`),console.log(`\u2502 API Key \u2014 ${e.embedding.provider==="local"?"not required":x(e.embedding.apiKey)}`),e.embedding.accountId&&console.log(`\u2502 Account \u2014 ${e.embedding.accountId}`),console.log(`\u2502 Legacy \u2014 ${e.legacy.embedding?"yes":"no"}`),console.log("\u2502"),console.log("\u2514 \u25C6 Configuration loaded"),console.log("")}async function S(){let e=u().llm,r=new b(`Testing LLM \u2014 ${e.provider}`,{stream:process.stdout,display:"bar",intervalMs:180}).start();try{let i=await R({id:e.provider,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId}).healthCheck();if(!i.ok)return r.fail(`LLM \u2014 ${i.message}`),!1;let n=[e.provider,i.model??e.model,i.latencyMs!==void 0?`${i.latencyMs}ms`:void 0].filter(Boolean);return r.succeed(`LLM \u2014 ${n.join(" \xB7 ")}`),!0}catch(t){return r.fail(`LLM \u2014 ${t instanceof Error?t.message:String(t)}`),!1}}async function G(){let e=u().embedding,r=new b(`Testing embedding \u2014 ${e.provider}`,{stream:process.stdout,display:"bar",intervalMs:180}).start();try{let t=K(),i=Date.now(),n=await t.embed("ToolNet Memory provider health check"),s=Date.now()-i;if(!Array.isArray(n)||n.length===0)throw new Error("Empty embedding vector");return r.succeed(`Embedding \u2014 ${e.provider} \xB7 ${n.length}d \xB7 ${s}ms`),!0}catch(t){return r.fail(`Embedding \u2014 ${t instanceof Error?t.message:String(t)}`),!1}}async function X(){console.log(""),console.log("\u25C7 ToolNet AI Providers"),console.log(""),console.log("\u25C6 Health check"),console.log("\u2502");let e=await S(),r=await G();return console.log("\u2502"),console.log(e&&r?"\u2514 \u25C6 Providers ready":"\u2514 \u2717 Provider check failed"),console.log(""),e&&r}async function Z(){let e=process.argv[2]??"status";if(e==="list"){W();return}if(e==="status"){Q();return}if(e==="test"){let r=process.argv[3]??"all",t=!1;r==="llm"?t=await S():r==="embedding"?t=await G():t=await X(),process.exitCode=t?0:1;return}console.error(`Unknown provider command: ${e}`),console.error(""),console.error("Usage:"),console.error(" toolnet-memory provider:list"),console.error(" toolnet-memory provider:status"),console.error(" toolnet-memory provider:test"),console.error(" toolnet-memory provider:test llm"),console.error(" toolnet-memory provider:test embedding"),process.exitCode=1}Z().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});
@@ -1,10 +1,11 @@
1
- import{mkdirSync as V,mkdtempSync as y,readFileSync as se,readdirSync as Ht,rmSync as v,writeFileSync as I}from"node:fs";import{tmpdir as A}from"node:os";import{join as p}from"node:path";var ue=[{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 M(t){let e=ue.find(r=>r.id===t);if(!e)throw new Error(`Unsupported AI provider: ${t}`);return e}function C(t){return ue.some(e=>e.id===t)}function s(t){return process.env[t]?.trim()||void 0}function u(...t){return t.find(e=>!!e?.trim())}function de(){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 fe(){let t=s("TOOLNET_LLM_PROVIDER");return t&&C(t)?t:de()??"openai-compatible"}function U(t){let e=M(t);switch(t){case"alibaba":return{provider:t,apiKey:u(s("ALIBABA_API_KEY"),s("DASHSCOPE_API_KEY")),baseUrl:u(s("ALIBABA_BASE_URL"),s("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:u(s("ALIBABA_MODEL"),s("DASHSCOPE_MODEL"))};case"openrouter":return{provider:t,apiKey:s("OPENROUTER_API_KEY"),baseUrl:u(s("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:s("OPENROUTER_MODEL")};case"groq":return{provider:t,apiKey:s("GROQ_API_KEY"),baseUrl:u(s("GROQ_BASE_URL"),e.defaultBaseUrl),model:s("GROQ_MODEL")};case"deepseek":return{provider:t,apiKey:s("DEEPSEEK_API_KEY"),baseUrl:u(s("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:u(s("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:t,apiKey:u(s("NVIDIA_API_KEY"),s("NVIDIA_NIM_API_KEY")),baseUrl:u(s("NVIDIA_BASE_URL"),s("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:u(s("NVIDIA_MODEL"),s("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:t,apiKey:u(s("GEMINI_API_KEY"),s("GOOGLE_API_KEY")),baseUrl:u(s("GEMINI_BASE_URL"),e.defaultBaseUrl),model:s("GEMINI_MODEL")};case"huggingface":return{provider:t,apiKey:s("HF_TOKEN"),baseUrl:u(s("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:u(s("HF_LLM_MODEL"),s("HF_MODEL"))};case"ollama":return{provider:t,apiKey:s("OLLAMA_API_KEY"),baseUrl:u(s("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:s("OLLAMA_MODEL")};case"cloudflare":return{provider:t,accountId:s("CLOUDFLARE_ACCOUNT_ID"),apiKey:s("CLOUDFLARE_API_TOKEN"),baseUrl:s("CLOUDFLARE_AI_BASE_URL"),model:s("CLOUDFLARE_MODEL")};case"custom":return{provider:t,apiKey:s("CUSTOM_AI_API_KEY"),baseUrl:s("CUSTOM_AI_BASE_URL"),model:s("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:u(s("OPENAI_API_KEY"),s("MODEL_API_KEY")),baseUrl:u(s("OPENAI_BASE_URL"),s("MODEL_BASE_URL")),model:u(s("OPENAI_MODEL"),s("MODEL_NAME"))}}}function We(){let t=s("TOOLNET_LLM_PROVIDER"),e=t&&C(t)?t:fe(),r=M(e),o=U(e);return{provider:e,apiKey:u(s("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:u(s("TOOLNET_LLM_BASE_URL"),o.baseUrl,r.defaultBaseUrl),model:u(s("TOOLNET_LLM_MODEL"),o.model,r.defaultModel),accountId:u(s("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function Ge(){let t=s("TOOLNET_EMBEDDING_PROVIDER");return t==="local"?"local":t&&C(t)?t:s("HF_TOKEN")||s("HF_EMBEDDING_MODEL")?"huggingface":"local"}function He(){let t=Ge();if(t==="local")return{provider:"local",model:u(s("TOOLNET_EMBEDDING_MODEL"),s("LOCAL_EMBEDDING_MODEL"))};let e=M(t),r,o,n,i;switch(t){case"huggingface":r=s("HF_TOKEN"),o=s("HF_INFERENCE_BASE_URL"),n=s("HF_EMBEDDING_MODEL");break;case"openai-compatible":r=s("OPENAI_API_KEY"),o=s("OPENAI_BASE_URL"),n=s("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":r=s("CLOUDFLARE_API_TOKEN"),o=s("CLOUDFLARE_AI_BASE_URL"),n=s("CLOUDFLARE_EMBEDDING_MODEL"),i=s("CLOUDFLARE_ACCOUNT_ID");break;default:r=U(t).apiKey,o=U(t).baseUrl,n=s(`${t.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=u(s("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),f=u(s("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),d=t==="cloudflare"&&!f&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:f;return{provider:t,apiKey:u(s("TOOLNET_EMBEDDING_API_KEY"),r),baseUrl:d,model:u(s("TOOLNET_EMBEDDING_MODEL"),n),accountId:a}}function X(){let t=We(),e=He();return{llm:t,embedding:e,legacy:{llm:!s("TOOLNET_LLM_PROVIDER")&&!!de(),embedding:!s("TOOLNET_EMBEDDING_PROVIDER")&&!!(s("HF_TOKEN")||s("HF_EMBEDDING_MODEL"))}}}function me(t=fe()){let e=X().llm;if(t===e.provider)return{id:t,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let r=U(t);return{id:t,apiKey:r.apiKey,baseUrl:r.baseUrl,model:r.model,accountId:r.accountId}}function L(t,e){return s(`TOOLNET_LLM_FALLBACK_${t}_${e}`)}function pe(){let t=[];for(let e of[1,2]){let r=L(e,"PROVIDER");if(!r||!C(r))continue;let o=M(r);t.push({slot:e,config:{provider:r,apiKey:L(e,"API_KEY"),baseUrl:u(L(e,"BASE_URL"),o.defaultBaseUrl),model:u(L(e,"MODEL"),o.defaultModel),accountId:L(e,"ACCOUNT_ID")}})}return t}function ge(){let t=s("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=s("TOOLNET_LLM_MAX_RETRIES"),r=Number(t??6e4),o=Number(e??1);return{cooldownMs:Number.isFinite(r)&&r>=0?r:6e4,maxRetries:Number.isFinite(o)&&o>=0?Math.floor(o):1}}var F=class extends Error{status;constructor(e,r){super(e),this.name="AiHttpError",this.status=r}};async function P(t,e,r=3e4){let o=new AbortController,n=setTimeout(()=>o.abort(),r);n.unref?.();try{let i=await fetch(t,{...e,signal:o.signal}),a=await i.text();if(!i.ok){let f=a;try{let d=JSON.parse(a);f=d.error?.message??d.message??a}catch{}throw new F(f||`HTTP ${i.status}`,i.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(n)}}function K(t,e){return`${t.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var $=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 r=this.config.accountId?.trim(),o=this.config.apiKey?.trim();if(!r)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/${r}/ai/run`).replace(/\/+$/,"")}/${n}`,f=await P(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=f.result?.response?.trim();if(!d)throw new Error(f.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(r){return{ok:!1,provider:"cloudflare",model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-e}}}};var B=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 r=this.config.apiKey?.trim();if(!r)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(m=>m.role==="system"),a=e.messages.filter(m=>m.role!=="system").map(m=>({role:m.role==="assistant"?"model":"user",parts:[{text:m.content}]})),f=`${K(o,`models/${encodeURIComponent(n)}:generateContent`)}?key=${encodeURIComponent(r)}`,d=await P(f,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(m=>m.content).join(`
2
-
3
- `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),k=d.candidates?.[0]?.content?.parts?.map(m=>m.text??"").join("").trim();if(!k)throw new Error("gemini: empty model response");return{text:k,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(r){return{ok:!1,provider:"gemini",model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-e}}}};var j=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 r=this.model(),o=await P(K(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:r,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:r,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 r=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:r.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(r){return{ok:!1,provider:this.id,model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-e}}}};function ke(t=me()){switch(M(t.id).transport){case"gemini":return new B(t);case"cloudflare":return new $(t);default:return new j(t)}}function Qe(t){return new Promise(e=>{setTimeout(e,t)})}function qe(t){if(t instanceof F){let r=t.status;return r===void 0||r===408||r===409||r===425||r===429?!0:r>=500}if(!(t instanceof Error))return!0;let e=t.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 W=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,r=[],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,...r].map(n=>({provider:ke(n.config),label:n.label}))}key(e){let r=this.providers[e];return`${e}:${r.provider.id}:${r.provider.config.model??""}`}state(e){let r=this.key(e),o=this.states.get(r);return o||(o={failures:0,cooldownUntil:0},this.states.set(r,o)),o}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let r=this.state(e);r.failures=0,r.cooldownUntil=0,r.lastError=void 0}fail(e,r){let o=this.state(e);o.failures+=1,o.lastError=r instanceof Error?r.message:String(r),o.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let r=[];for(let o=0;o<this.providers.length;o+=1){if(!this.available(o)){r.push(`${this.providers[o].label}: cooldown`);continue}let n=this.providers[o];for(let i=0;i<=this.maxRetries;i+=1)try{let a=await n.provider.generate(e);return this.success(o),a}catch(a){let f=a instanceof Error?a.message:String(a),d=qe(a);if(r.push(`${n.label}: ${f}`),!d)throw a;if(i<this.maxRetries){await Qe(Math.min(250*2**i,2e3));continue}this.fail(o,a)}}throw new Error(`All ToolNet LLM providers failed: ${r.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let r=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:r.provider,model:r.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(r){return{ok:!1,provider:this.id,model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,r)=>{let o=this.state(r);return{position:r,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 he(){let t=X(),e=pe();return new W({label:`Primary (${t.llm.provider})`,config:{id:t.llm.provider,apiKey:t.llm.apiKey,baseUrl:t.llm.baseUrl,model:t.llm.model,accountId:t.llm.accountId}},e.map(r=>({label:`Fallback ${r.slot} (${r.config.provider})`,config:{id:r.config.provider,apiKey:r.config.apiKey,baseUrl:r.config.baseUrl,model:r.config.model,accountId:r.config.accountId}})),ge())}var z=class{constructor(e=he()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function ye(){return new z(he())}import{existsSync as ct,readFileSync as lt}from"node:fs";import{join as ut}from"node:path";import{existsSync as Ye,mkdirSync as Ve,readFileSync as Je,renameSync as Xe,writeFileSync as ze}from"node:fs";import{dirname as Ze,join as et}from"node:path";function tt(t,e){Ve(Ze(t),{recursive:!0});let r=`${t}.tmp-${process.pid}-${Date.now()}`;ze(r,`${JSON.stringify(e,null,2)}
4
- `,{encoding:"utf8",mode:384}),Xe(r,t)}function _e(t){return et(t.rootPath,".toolnet","work","current.json")}function G(t){let e=_e(t);if(!Ye(e))return null;try{let r=JSON.parse(Je(e,"utf8"));return r.version!==1||r.projectId!==t.id?null:r}catch{return null}}function Z(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function S(t,e,r){let o=[],n=new Set;for(let i of[...t,...e].reverse()){let a=Z(i);if(!(!a||n.has(a))&&(n.add(a),o.push(i),o.length>=r))break}return o.reverse()}function rt(t){return t.kind==="phase"?/^Phase\s+\d+$/iu.test(t.text):t.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(t.text):!1}function ve(t,e){let r=e.status??t?.status??"pending",o=r;t?.status==="completed"&&r!=="completed"&&(o="completed"),t&&r==="pending"&&(t.status==="in_progress"||t.status==="blocked")&&(o=t.status);let n=t&&rt(e)?t.title:e.text;return{id:t?.id??e.id,title:n,status:o,order:e.order??t?.order,confidence:Math.max(t?.confidence??0,e.confidence),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}function Ae(t){let e=new Map;for(let r of t){let o=r.order!==void 0?`order:${r.order}`:Z(r.title);e.set(o,r)}return e}function be(t){return t.order!==void 0?`order:${t.order}`:Z(t.key||t.text)}function we(t){return Array.from(t).sort((e,r)=>{let o=e.order??Number.MAX_SAFE_INTEGER,n=r.order??Number.MAX_SAFE_INTEGER;return o!==n?o-n:e.updatedAt.localeCompare(r.updatedAt)})}function xe(t){return t.find(e=>e.status==="in_progress")??t.find(e=>e.status==="blocked")??t.find(e=>e.status==="pending")}function Ee(t,e){let r=G(t),o=Ae(r?.phases??[]),n=Ae(r?.tasks??[]),i=r?.goal,a=r?.plan,f=r?.lastSession,d=[],k=[],m=[],h=[],T=[],ae=[],N=[...e].sort((c,_)=>{let le=c.occurredAt.localeCompare(_.occurredAt);return le!==0?le:c.sequence-_.sequence});for(let c of N)switch(c.kind){case"goal":i=c.text;break;case"plan":a=c.text;break;case"phase":{let _=be(c);o.set(_,ve(o.get(_),c));break}case"task":{let _=be(c);n.set(_,ve(n.get(_),c));break}case"decision":d.push(c.text);break;case"blocker":k.push(c.text);break;case"warning":m.push(c.text);break;case"next_action":h.push(c.text);break;case"file":T.push(c.text);break;case"test":ae.push(c.text);break;case"session":f={agent:c.agent,nativeSessionId:c.nativeSessionId,sessionKey:c.sessionKey,updatedAt:c.occurredAt};break}let O=we(o.values()),E=we(n.values()),J=xe(O),D=xe(E),$e=S(r?.nextActions??[],[...h,...D?[D.title]:[],...!D&&J?[J.title]:[],...E.filter(c=>c.status==="pending").slice(0,5).map(c=>c.title)],8),Be=S(r?.blockers??[],[...k,...O.filter(c=>c.status==="blocked").map(c=>c.title),...E.filter(c=>c.status==="blocked").map(c=>c.title)],20),je=N.length>0?N[N.length-1].occurredAt:r?.updatedAt??new Date().toISOString(),ce={version:1,projectId:t.id,projectName:t.name,goal:i,plan:a,phases:O,tasks:E,decisions:S(r?.decisions??[],d,20),blockers:Be,warnings:S(r?.warnings??[],m,20),nextActions:$e,filesTouched:S(r?.filesTouched??[],T,30),tests:S(r?.tests??[],ae,20),currentPhase:J,currentTask:D,progress:{phasesTotal:O.length,phasesCompleted:O.filter(c=>c.status==="completed").length,tasksTotal:E.length,tasksCompleted:E.filter(c=>c.status==="completed").length,blocked:O.filter(c=>c.status==="blocked").length+E.filter(c=>c.status==="blocked").length},lastSession:f,updatedAt:je};return tt(_e(t),ce),ce}import{existsSync as ot,mkdirSync as Ar,readFileSync as nt,renameSync as br,writeFileSync as wr}from"node:fs";import{dirname as _r,join as st}from"node:path";function it(t){return st(t.rootPath,".toolnet","context","session-origin.json")}function ee(t){let e=it(t);if(!ot(e))return null;try{let r=JSON.parse(nt(e,"utf8"));return r.version!==1||r.projectId!==t.id?null:r}catch{return null}}function at(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function H(t){let e=at(t),r=/(?: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 r&&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"}var dt={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,phase:75,file:65,next_action:55,blocker:45},next_action:{next_action:100,todo:80,task:65,blocker:60,file:40},last_file:{file:100,task:65,next_action:40},blocker:{blocker:100,task:60,next_action:50,file:35},decision:{decision:100,task:45,file:30},completed:{completed:100,progress:70,task:30},status:{progress:100,task:85,phase:75,blocker:65,next_action:60},summary:{task:100,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,progress:50,test:45,goal:35}},ft={handoff:18,"session-origin":14,"work-state":8};function mt(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function l(t,e){let r=e.value.replace(/\s+/g," ").trim();r&&t.push({...e,value:r,score:0})}function pt(t){let e=ut(t.rootPath,".toolnet","work","handoff-latest.json");if(!ct(e))return null;try{let o=JSON.parse(lt(e,"utf8")).continuity;return o?.schema!=="toolnet.handoff.v2"||o.project.id!==t.id?null:o}catch{return null}}function gt(t){let e=pt(t);if(!e)return[];let r=[];l(r,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.goal&&l(r,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&l(r,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&l(r,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&l(r,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&l(r,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let o of e.blockers)l(r,{kind:"blocker",value:o,source:"handoff"});for(let o of e.decisions)l(r,{kind:"decision",value:o,source:"handoff"});for(let o of e.completed.tasks)l(r,{kind:"completed",value:o,source:"handoff"});for(let o of e.remaining.todos)l(r,{kind:"todo",value:o,source:"handoff"});return l(r,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),l(r,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),r}function kt(t){let e=ee(t);if(!e)return[];let r=[];return l(r,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&l(r,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&l(r,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&l(r,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&l(r,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&l(r,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&l(r,{kind:"decision",value:e.latestDecision,source:"session-origin"}),r}function ht(t){let e=G(t);if(!e)return[];let r=[];e.goal&&l(r,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&l(r,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&l(r,{kind:"task",value:e.currentTask.title,source:"work-state"});let o=e.filesTouched.at(-1);o&&l(r,{kind:"file",value:o,source:"work-state"});for(let n of e.nextActions.slice(0,5))l(r,{kind:"next_action",value:n,source:"work-state"});for(let n of e.blockers.slice(-5))l(r,{kind:"blocker",value:n,source:"work-state"});for(let n of e.decisions.slice(-5))l(r,{kind:"decision",value:n,source:"work-state"});for(let n of e.tasks.filter(i=>i.status==="completed").slice(-8))l(r,{kind:"completed",value:n.title,source:"work-state"});for(let n of e.tasks.filter(i=>i.status!=="completed"&&i.status!=="cancelled").slice(0,8))l(r,{kind:"todo",value:n.title,source:"work-state"});for(let n of e.tests.slice(-5))l(r,{kind:"test",value:n,source:"work-state"});return l(r,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),r}function yt(t,e){let r=dt[t];return e.map((o,n)=>({...o,score:(r[o.kind]??10)+ft[o.source]+Math.max(0,5-n*.01)}))}function vt(t){let e=new Map;for(let r of t){let o=`${r.kind}:${mt(r.value)}`,n=e.get(o);(!n||r.score>n.score)&&e.set(o,r)}return[...e.values()]}function R(t,e,r={}){let o=H(e),n=[...gt(t),...kt(t),...ht(t)],i=vt(yt(o,n)).sort((m,h)=>h.score-m.score),a=Math.max(1,r.maxFacts??12),f=Math.max(300,r.maxChars??3200),d=[],k=0;for(let m of i){if(d.length>=a)break;let h=m.kind.length+m.value.length+m.source.length+16;d.length>0&&k+h>f||(d.push(m),k+=h)}return{intent:o,facts:d,context:{project:{id:t.id,name:t.name},intent:o,selectedFacts:d.map(m=>({kind:m.kind,value:m.value,source:m.source}))},stats:{candidates:n.length,selected:d.length,chars:k}}}var Me={previous_agent:"Agent tr\u01B0\u1EDBc",goal:"M\u1EE5c ti\xEAu",phase:"Phase",task:"Task hi\u1EC7n t\u1EA1i",file:"File hi\u1EC7n t\u1EA1i",todo:"TODO",next_action:"Ti\u1EBFp theo",blocker:"Blocker",decision:"Quy\u1EBFt \u0111\u1ECBnh",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},Ie=["previous_agent","phase","task","file","todo","next_action","blocker","decision","completed","test","progress","goal"],At={previous_agent:["previous_agent"],current_task:["task","file","next_action"],next_action:["next_action","task","file","todo"],last_file:["file","task","next_action"],blocker:["blocker"],decision:["decision"],completed:["completed"],status:["progress","task","next_action","blocker"],summary:Ie};function bt(t){let e=t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)}function wt(t){let e=t.filter(r=>r.source==="handoff");return e.length>0?e:t}function xt(t){let e=new Set,r=[];for(let o of t){let n=`${o.kind}:${o.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(n)||(e.add(n),r.push(o))}return r}function Te(t){switch(t){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function _t(t,e){let r=[];for(let o of e){let n=t.filter(i=>i.kind===o).slice(0,Te(o));for(let i of n)r.push(`${Me[o]}: ${i.value}`)}return r.join(`
5
- `)}function Et(t,e){let r=At[e]??Ie,o=[];for(let n of r){let i=t.filter(a=>a.kind===n).slice(0,Te(n));for(let a of i)o.push(`${Me[n]}: ${a.value}`)}return o.join(`
6
- `)}function g(t,e){let r=R(t,e,{maxFacts:32,maxChars:6400}),o=xt(wt(r.facts)),n=bt(e)?_t(o,["todo","task","next_action","file"]):Et(o,String(r.intent));return n?{intent:String(r.intent),answer:n,source:o[0]?.source??"none"}:{intent:String(r.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}function Mt(t,e){let r=JSON.stringify(t,null,2);return r.length<=e?r:r.slice(0,e)+`
7
- [truncated]`}function It(t,e){let r=g(t,e),o=R(t,e,{maxFacts:12,maxChars:3200});return Mt({project:o.context.project,intent:o.intent,directAnswer:r.answer,selectedMemory:o.context.selectedFacts,retrievalStats:o.stats},4200)}async function Oe(t,e,r={}){let o=g(t,e),n=It(t,e),i=r.router??ye();try{let a=await i.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
1
+ import{mkdirSync as ee,mkdtempSync as A,readFileSync as le,readdirSync as vn,rmSync as x,writeFileSync as I}from"node:fs";import{tmpdir as M}from"node:os";import{join as f}from"node:path";var be=[{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 C(n){let e=be.find(t=>t.id===n);if(!e)throw new Error(`Unsupported AI provider: ${n}`);return e}function N(n){return be.some(e=>e.id===n)}function i(n){return process.env[n]?.trim()||void 0}function u(...n){return n.find(e=>!!e?.trim())}function Ae(){if(i("GROQ_API_KEY"))return"groq";if(i("DEEPSEEK_API_KEY"))return"deepseek";if(i("NVIDIA_API_KEY")||i("NVIDIA_NIM_API_KEY"))return"nvidia";if(i("OPENROUTER_API_KEY"))return"openrouter";if(i("ALIBABA_API_KEY")||i("DASHSCOPE_API_KEY"))return"alibaba";if(i("GEMINI_API_KEY")||i("GOOGLE_API_KEY"))return"gemini";if(i("CLOUDFLARE_API_TOKEN")&&i("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(i("HF_TOKEN"))return"huggingface";if(i("OLLAMA_MODEL")||i("OLLAMA_BASE_URL"))return"ollama"}function xe(){let n=i("TOOLNET_LLM_PROVIDER");return n&&N(n)?n:Ae()??"openai-compatible"}function j(n){let e=C(n);switch(n){case"alibaba":return{provider:n,apiKey:u(i("ALIBABA_API_KEY"),i("DASHSCOPE_API_KEY")),baseUrl:u(i("ALIBABA_BASE_URL"),i("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:u(i("ALIBABA_MODEL"),i("DASHSCOPE_MODEL"))};case"openrouter":return{provider:n,apiKey:i("OPENROUTER_API_KEY"),baseUrl:u(i("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:i("OPENROUTER_MODEL")};case"groq":return{provider:n,apiKey:i("GROQ_API_KEY"),baseUrl:u(i("GROQ_BASE_URL"),e.defaultBaseUrl),model:i("GROQ_MODEL")};case"deepseek":return{provider:n,apiKey:i("DEEPSEEK_API_KEY"),baseUrl:u(i("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:u(i("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:n,apiKey:u(i("NVIDIA_API_KEY"),i("NVIDIA_NIM_API_KEY")),baseUrl:u(i("NVIDIA_BASE_URL"),i("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:u(i("NVIDIA_MODEL"),i("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:n,apiKey:u(i("GEMINI_API_KEY"),i("GOOGLE_API_KEY")),baseUrl:u(i("GEMINI_BASE_URL"),e.defaultBaseUrl),model:i("GEMINI_MODEL")};case"huggingface":return{provider:n,apiKey:i("HF_TOKEN"),baseUrl:u(i("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:u(i("HF_LLM_MODEL"),i("HF_MODEL"))};case"ollama":return{provider:n,apiKey:i("OLLAMA_API_KEY"),baseUrl:u(i("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:i("OLLAMA_MODEL")};case"cloudflare":return{provider:n,accountId:i("CLOUDFLARE_ACCOUNT_ID"),apiKey:i("CLOUDFLARE_API_TOKEN"),baseUrl:i("CLOUDFLARE_AI_BASE_URL"),model:i("CLOUDFLARE_MODEL")};case"custom":return{provider:n,apiKey:i("CUSTOM_AI_API_KEY"),baseUrl:i("CUSTOM_AI_BASE_URL"),model:i("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:u(i("OPENAI_API_KEY"),i("MODEL_API_KEY")),baseUrl:u(i("OPENAI_BASE_URL"),i("MODEL_BASE_URL")),model:u(i("OPENAI_MODEL"),i("MODEL_NAME"))}}}function tt(){let n=i("TOOLNET_LLM_PROVIDER"),e=n&&N(n)?n:xe(),t=C(e),r=j(e);return{provider:e,apiKey:u(i("TOOLNET_LLM_API_KEY"),r.apiKey),baseUrl:u(i("TOOLNET_LLM_BASE_URL"),r.baseUrl,t.defaultBaseUrl),model:u(i("TOOLNET_LLM_MODEL"),r.model,t.defaultModel),accountId:u(i("TOOLNET_LLM_ACCOUNT_ID"),r.accountId)}}function nt(){let n=i("TOOLNET_EMBEDDING_PROVIDER");return n==="local"?"local":n&&N(n)?n:i("HF_TOKEN")||i("HF_EMBEDDING_MODEL")?"huggingface":"local"}function rt(){let n=nt();if(n==="local")return{provider:"local",model:u(i("TOOLNET_EMBEDDING_MODEL"),i("LOCAL_EMBEDDING_MODEL"))};let e=C(n),t,r,o,s;switch(n){case"huggingface":t=i("HF_TOKEN"),r=i("HF_INFERENCE_BASE_URL"),o=i("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=i("OPENAI_API_KEY"),r=i("OPENAI_BASE_URL"),o=i("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=i("CLOUDFLARE_API_TOKEN"),r=i("CLOUDFLARE_AI_BASE_URL"),o=i("CLOUDFLARE_EMBEDDING_MODEL"),s=i("CLOUDFLARE_ACCOUNT_ID");break;default:t=j(n).apiKey,r=j(n).baseUrl,o=i(`${n.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=u(i("TOOLNET_EMBEDDING_ACCOUNT_ID"),s),m=u(i("TOOLNET_EMBEDDING_BASE_URL"),r,e.defaultBaseUrl),d=n==="cloudflare"&&!m&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:m;return{provider:n,apiKey:u(i("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:d,model:u(i("TOOLNET_EMBEDDING_MODEL"),o),accountId:a}}function ne(){let n=tt(),e=rt();return{llm:n,embedding:e,legacy:{llm:!i("TOOLNET_LLM_PROVIDER")&&!!Ae(),embedding:!i("TOOLNET_EMBEDDING_PROVIDER")&&!!(i("HF_TOKEN")||i("HF_EMBEDDING_MODEL"))}}}function Me(n=xe()){let e=ne().llm;if(n===e.provider)return{id:n,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=j(n);return{id:n,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function L(n,e){return i(`TOOLNET_LLM_FALLBACK_${n}_${e}`)}function Se(){let n=[];for(let e of[1,2]){let t=L(e,"PROVIDER");if(!t||!N(t))continue;let r=C(t);n.push({slot:e,config:{provider:t,apiKey:L(e,"API_KEY"),baseUrl:u(L(e,"BASE_URL"),r.defaultBaseUrl),model:u(L(e,"MODEL"),r.defaultModel),accountId:L(e,"ACCOUNT_ID")}})}return n}function we(){let n=i("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=i("TOOLNET_LLM_MAX_RETRIES"),t=Number(n??6e4),r=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(r)&&r>=0?Math.floor(r):1}}var D=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function P(n,e,t=3e4){let r=new AbortController,o=setTimeout(()=>r.abort(),t);o.unref?.();try{let s=await fetch(n,{...e,signal:r.signal}),a=await s.text();if(!s.ok){let m=a;try{let d=JSON.parse(a);m=d.error?.message??d.message??a}catch{}throw new D(m||`HTTP ${s.status}`,s.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(o)}}function B(n,e){return`${n.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var W=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(),r=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!r)throw new Error("cloudflare: API TOKEN is not configured");let o=this.model(),a=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${o}`,m=await P(a,{method:"POST",headers:{authorization:`Bearer ${r}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),d=m.result?.response?.trim();if(!d)throw new Error(m.errors?.[0]?.message??"cloudflare: empty model response");return{text:d,provider:"cloudflare",model:o}}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 q=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 r=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",o=this.model(),s=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}]})),m=`${B(r,`models/${encodeURIComponent(o)}:generateContent`)}?key=${encodeURIComponent(t)}`,d=await P(m,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...s.length?{systemInstruction:{parts:[{text:s.map(p=>p.content).join(`
2
+
3
+ `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),k=d.candidates?.[0]?.content?.parts?.map(p=>p.text??"").join("").trim();if(!k)throw new Error("gemini: empty model response");return{text:k,provider:"gemini",model:o,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 z=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(),r=await P(B(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}:{}})}),o=r.choices?.[0]?.message?.content?.trim();if(!o)throw new Error(`${this.id}: empty model response`);return{text:o,provider:this.id,model:t,usage:r.usage?{inputTokens:r.usage.prompt_tokens,outputTokens:r.usage.completion_tokens,totalTokens:r.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 Ee(n=Me()){switch(C(n.id).transport){case"gemini":return new q(n);case"cloudflare":return new W(n);default:return new z(n)}}function ot(n){return new Promise(e=>{setTimeout(e,n)})}function st(n){if(n instanceof D){let t=n.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(n instanceof Error))return!0;let e=n.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 H=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],r={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=r.cooldownMs??6e4,this.maxRetries=Math.max(0,r.maxRetries??1),this.providers=[e,...t].map(o=>({provider:Ee(o.config),label:o.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),r=this.states.get(t);return r||(r={failures:0,cooldownUntil:0},this.states.set(t,r)),r}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 r=this.state(e);r.failures+=1,r.lastError=t instanceof Error?t.message:String(t),r.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let r=0;r<this.providers.length;r+=1){if(!this.available(r)){t.push(`${this.providers[r].label}: cooldown`);continue}let o=this.providers[r];for(let s=0;s<=this.maxRetries;s+=1)try{let a=await o.provider.generate(e);return this.success(r),a}catch(a){let m=a instanceof Error?a.message:String(a),d=st(a);if(t.push(`${o.label}: ${m}`),!d)throw a;if(s<this.maxRetries){await ot(Math.min(250*2**s,2e3));continue}this.fail(r,a)}}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 r=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:r.cooldownUntil>Date.now(),cooldownUntil:r.cooldownUntil||void 0,failures:r.failures,lastError:r.lastError}})}};function _e(){let n=ne(),e=Se();return new H({label:`Primary (${n.llm.provider})`,config:{id:n.llm.provider,apiKey:n.llm.apiKey,baseUrl:n.llm.baseUrl,model:n.llm.model,accountId:n.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}})),we())}var re=class{constructor(e=_e()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function Ce(){return new re(_e())}import{existsSync as Ft,readFileSync as Nt}from"node:fs";import{join as Lt}from"node:path";import{existsSync as it,mkdirSync as at,readFileSync as ct,renameSync as lt,writeFileSync as ut}from"node:fs";import{dirname as dt,join as mt}from"node:path";function pt(n,e){at(dt(n),{recursive:!0});let t=`${n}.tmp-${process.pid}-${Date.now()}`;ut(t,`${JSON.stringify(e,null,2)}
4
+ `,{encoding:"utf8",mode:384}),lt(t,n)}function Fe(n){return mt(n.rootPath,".toolnet","work","current.json")}function G(n){let e=Fe(n);if(!it(e))return null;try{let t=JSON.parse(ct(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function Y(n){return n.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function y(n,e,t){let r=[],o=new Set;for(let s of[...n,...e].reverse()){let a=Y(s);if(!(!a||o.has(a))&&(o.add(a),r.push(s),r.length>=t))break}return r.reverse()}function ft(n,e,t=20){let r=new Map;for(let o of[...n,...e]){let s=`${o.kind}|${Y(o.command)}`;r.delete(s),r.set(s,o)}return Array.from(r.values()).slice(-t)}function gt(n){return n.kind==="phase"?/^Phase\s+\d+$/iu.test(n.text):n.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(n.text):!1}function Ie(n,e){let t=e.status??n?.status??"pending",r=t;n?.status==="completed"&&t!=="completed"&&(r="completed"),n&&t==="pending"&&(n.status==="in_progress"||n.status==="blocked")&&(r=n.status);let o=n&&gt(e)?n.title:e.text;return{id:n?.id??e.id,title:o,status:r,order:e.order??n?.order,confidence:Math.max(n?.confidence??0,e.confidence),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}function Te(n){let e=new Map;for(let t of n){let r=t.order!==void 0?`order:${t.order}`:Y(t.title);e.set(r,t)}return e}function Oe(n){return n.order!==void 0?`order:${n.order}`:Y(n.key||n.text)}function Pe(n){return Array.from(n).sort((e,t)=>{let r=e.order??Number.MAX_SAFE_INTEGER,o=t.order??Number.MAX_SAFE_INTEGER;return r!==o?r-o:e.updatedAt.localeCompare(t.updatedAt)})}function Re(n){return n.find(e=>e.status==="in_progress")??n.find(e=>e.status==="blocked")??n.find(e=>e.status==="pending")}function Ne(n,e){let t=G(n),r=Te(t?.phases??[]),o=Te(t?.tasks??[]),s=t?.currentRequest,a=t?.currentActivity,m=t?.goal,d=t?.plan,k=t?.lastSession,p=[],v=[],T=[],de=[],me=[],K=[...t?.activeFiles??[]],pe=[],fe=[],ge=[],ye=[],he=[],ke=[],$=[...e].sort((c,g)=>{let F=c.occurredAt.localeCompare(g.occurredAt);return F!==0?F:c.sequence-g.sequence});for(let c of $)switch(c.kind){case"request":s=c.text;break;case"activity":a=c.text;break;case"goal":m=c.text;break;case"plan":d=c.text;break;case"phase":{let g=Oe(c);r.set(g,Ie(r.get(g),c));break}case"task":{let g=Oe(c);o.set(g,Ie(o.get(g),c));break}case"decision":p.push(c.text);break;case"blocker":v.push(c.text);break;case"warning":T.push(c.text);break;case"next_action":de.push(c.text);break;case"file":{me.push(c.text);let g=c.fileAction??"active",F=K.indexOf(c.text);F>=0&&K.splice(F,1),g!=="deleted"&&K.push(c.text),g==="modified"?pe.push(c.text):g==="created"?fe.push(c.text):g==="deleted"&&ge.push(c.text);break}case"command":ye.push(c.text);break;case"test":he.push(c.text),c.checkKind&&ke.push({kind:c.checkKind,command:c.text,status:c.checkStatus??"unknown",updatedAt:c.occurredAt,agent:c.agent,nativeSessionId:c.nativeSessionId});break;case"session":k={agent:c.agent,nativeSessionId:c.nativeSessionId,sessionKey:c.sessionKey,updatedAt:c.occurredAt};break}let O=Pe(r.values()),_=Pe(o.values()),te=Re(O),U=Re(_),Xe=y(t?.nextActions??[],[...de,...U?[U.title]:[],...!U&&te?[te.title]:[],..._.filter(c=>c.status==="pending").slice(0,5).map(c=>c.title)],8),Ze=y(t?.blockers??[],[...v,...O.filter(c=>c.status==="blocked").map(c=>c.title),..._.filter(c=>c.status==="blocked").map(c=>c.title)],20),et=$.length>0?$[$.length-1].occurredAt:t?.updatedAt??new Date().toISOString(),ve={version:1,projectId:n.id,projectName:n.name,currentRequest:s,currentActivity:a,goal:m,plan:d,phases:O,tasks:_,decisions:y(t?.decisions??[],p,20),blockers:Ze,warnings:y(t?.warnings??[],T,20),nextActions:Xe,filesTouched:y(t?.filesTouched??[],me,30),activeFiles:y([],K,5),modifiedFiles:y(t?.modifiedFiles??[],pe,30),createdFiles:y(t?.createdFiles??[],fe,30),deletedFiles:y(t?.deletedFiles??[],ge,30),commands:y(t?.commands??[],ye,20),tests:y(t?.tests??[],he,20),checks:ft(t?.checks??[],ke,20),currentPhase:te,currentTask:U,progress:{phasesTotal:O.length,phasesCompleted:O.filter(c=>c.status==="completed").length,tasksTotal:_.length,tasksCompleted:_.filter(c=>c.status==="completed").length,blocked:O.filter(c=>c.status==="blocked").length+_.filter(c=>c.status==="blocked").length},lastSession:k,updatedAt:et};return pt(Fe(n),ve),ve}import{existsSync as yt,mkdirSync as Yn,readFileSync as ht,renameSync as Vn,writeFileSync as Jn}from"node:fs";import{dirname as Xn,join as kt}from"node:path";function vt(n){return kt(n.rootPath,".toolnet","context","session-origin.json")}function oe(n){let e=vt(n);if(!yt(e))return null;try{let t=JSON.parse(ht(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function bt(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function V(n){let e=bt(n),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),r=/(?:đ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&&r?"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"}import{existsSync as It,mkdirSync as Wr,readFileSync as Tt}from"node:fs";import{join as Le}from"node:path";var xt=[{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}],J=class{scan(e){let t=[];for(let r of xt){let o=new RegExp(r.regex.source,r.regex.flags);for(let s of e.matchAll(o))t.push({type:r.type,value:s[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var Q=class{scanner=new J;sanitize(e){let t=e,r=this.scanner.scan(e),o=new Set;for(let s of r)o.add(s.type),t=t.split(s.value).join(`[REDACTED:${s.type}]`);return{text:t,redacted:r.length,secretTypes:[...o]}}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[r,o]of Object.entries(e)){let s=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")?t[r]="[REDACTED]":t[r]=this.sanitizeValue(o)}return t}return e}};import{existsSync as Mt,readFileSync as St}from"node:fs";import{homedir as wt}from"node:os";import{join as Et}from"node:path";function _t(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
5
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Ct(){let n=process.env.TOOLNET_GLOBAL_ENV??Et(wt(),".config","toolnet-memory",".env");if(!Mt(n))return;let e=St(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let s=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=_t(r.slice(o+1)))}}Ct();var Or=new Q;function Ot(n){return Le(n.rootPath,".toolnet","memory","checkpoints")}function Pt(n){return Le(Ot(n),"latest.json")}function Rt(n){let e=Pt(n);if(!It(e))return null;try{let t=JSON.parse(Tt(e,"utf8"));return t.schema!=="toolnet.memory.checkpoint.v1"||t.project.id!==n.id?null:t}catch{return null}}function De(n){return Rt(n)}var Dt={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,request:95,activity:90,phase:75,file:65,next_action:55,blocker:45},next_action:{next_action:100,todo:80,task:65,blocker:60,file:40},last_file:{file:100,task:65,next_action:40},blocker:{blocker:100,task:60,next_action:50,file:35},decision:{decision:100,rule:85,architecture:80,task:45,file:30},completed:{completed:100,progress:70,task:30},status:{progress:100,task:85,phase:75,blocker:65,next_action:60},summary:{task:100,request:98,activity:96,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,rule:54,architecture:53,fix:52,progress:50,test:45,goal:35}},Kt={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function $t(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function l(n,e){let t=e.value.replace(/\s+/g," ").trim();t&&n.push({...e,value:t,score:0})}function Ut(n){let e=Lt(n.rootPath,".toolnet","work","handoff-latest.json");if(!Ft(e))return null;try{let r=JSON.parse(Nt(e,"utf8")).continuity;return r?.schema!=="toolnet.handoff.v2"||r.project.id!==n.id?null:r}catch{return null}}function jt(n){let e=De(n);if(!e)return[];let t=[];e.request&&l(t,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&l(t,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&l(t,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&l(t,{kind:"task",value:e.current.task.title,source:"checkpoint"});let r=e.files.active.at(-1);r&&l(t,{kind:"file",value:r,source:"checkpoint"});for(let o of e.nextActions)l(t,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)l(t,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)l(t,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)l(t,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)l(t,{kind:o.kind,value:o.content,source:"checkpoint"});return t}function Bt(n){let e=Ut(n);if(!e)return[];let t=[];l(t,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&l(t,{kind:"request",value:e.request,source:"handoff"}),e.activity&&l(t,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&l(t,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&l(t,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&l(t,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&l(t,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&l(t,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let r of e.blockers)l(t,{kind:"blocker",value:r,source:"handoff"});for(let r of e.decisions)l(t,{kind:"decision",value:r,source:"handoff"});for(let r of e.completed.tasks)l(t,{kind:"completed",value:r,source:"handoff"});for(let r of e.remaining.todos)l(t,{kind:"todo",value:r,source:"handoff"});return l(t,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),l(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),t}function Wt(n){let e=oe(n);if(!e)return[];let t=[];return l(t,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&l(t,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&l(t,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&l(t,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&l(t,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&l(t,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&l(t,{kind:"decision",value:e.latestDecision,source:"session-origin"}),t}function qt(n){let e=G(n);if(!e)return[];let t=[];e.currentRequest&&l(t,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&l(t,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&l(t,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&l(t,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&l(t,{kind:"task",value:e.currentTask.title,source:"work-state"});let r=e.activeFiles?.at(-1)??e.filesTouched.at(-1);r&&l(t,{kind:"file",value:r,source:"work-state"});for(let o of e.nextActions.slice(0,5))l(t,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))l(t,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))l(t,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(s=>s.status==="completed").slice(-8))l(t,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(s=>s.status!=="completed"&&s.status!=="cancelled").slice(0,8))l(t,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))l(t,{kind:"test",value:o,source:"work-state"});return l(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),t}function zt(n,e){let t=Dt[n];return e.map((r,o)=>({...r,score:(t[r.kind]??10)+Kt[r.source]+Math.max(0,5-o*.01)}))}function Ht(n){let e=new Map;for(let t of n){let r=`${t.kind}:${$t(t.value)}`,o=e.get(r);(!o||t.score>o.score)&&e.set(r,t)}return[...e.values()]}function R(n,e,t={}){let r=V(e),o=[...jt(n),...Bt(n),...Wt(n),...qt(n)],s=Ht(zt(r,o)).sort((p,v)=>v.score-p.score),a=Math.max(1,t.maxFacts??12),m=Math.max(300,t.maxChars??3200),d=[],k=0;for(let p of s){if(d.length>=a)break;let v=p.kind.length+p.value.length+p.source.length+16;d.length>0&&k+v>m||(d.push(p),k+=v)}return{intent:r,facts:d,context:{project:{id:n.id,name:n.name},intent:r,selectedFacts:d.map(p=>({kind:p.kind,value:p.value,source:p.source}))},stats:{candidates:o.length,selected:d.length,chars:k}}}var Ke={previous_agent:"Agent tr\u01B0\u1EDBc",request:"Y\xEAu c\u1EA7u hi\u1EC7n t\u1EA1i",activity:"\u0110ang l\xE0m",goal:"M\u1EE5c ti\xEAu",phase:"Phase",task:"Task hi\u1EC7n t\u1EA1i",file:"File hi\u1EC7n t\u1EA1i",todo:"TODO",next_action:"Ti\u1EBFp theo",blocker:"Blocker",decision:"Quy\u1EBFt \u0111\u1ECBnh",rule:"Quy t\u1EAFc",architecture:"Ki\u1EBFn tr\xFAc",fix:"\u0110\xE3 s\u1EEDa",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},$e=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],Gt={previous_agent:["previous_agent"],current_task:["request","activity","task","file","next_action"],next_action:["next_action","task","file","todo"],last_file:["file","task","next_action"],blocker:["blocker"],decision:["decision"],completed:["completed"],status:["progress","task","next_action","blocker"],summary:$e};function Yt(n){let e=n.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)}function Vt(n){let e=n.filter(r=>r.source==="handoff");if(e.length===0)return n;let t=n.filter(r=>r.source==="checkpoint"&&["rule","architecture","fix"].includes(r.kind));return[...e,...t]}function Jt(n){let e=new Set,t=[];for(let r of n){let o=`${r.kind}:${r.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),t.push(r))}return t}function Ue(n){switch(n){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function Qt(n,e){let t=[];for(let r of e){let o=n.filter(s=>s.kind===r).slice(0,Ue(r));for(let s of o)t.push(`${Ke[r]}: ${s.value}`)}return t.join(`
6
+ `)}function Xt(n,e){let t=Gt[e]??$e,r=[];for(let o of t){let s=n.filter(a=>a.kind===o).slice(0,Ue(o));for(let a of s)r.push(`${Ke[o]}: ${a.value}`)}return r.join(`
7
+ `)}function h(n,e){let t=R(n,e,{maxFacts:32,maxChars:6400}),r=Jt(Vt(t.facts)),o=Yt(e)?Qt(r,["todo","task","next_action","file"]):Xt(r,String(t.intent));return o?{intent:String(t.intent),answer:o,source:r[0]?.source??"none"}:{intent:String(t.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}function Zt(n,e){let t=JSON.stringify(n,null,2);return t.length<=e?t:t.slice(0,e)+`
8
+ [truncated]`}function en(n,e){let t=h(n,e),r=R(n,e,{maxFacts:12,maxChars:3200});return Zt({project:r.context.project,intent:r.intent,directAnswer:t.answer,selectedMemory:r.context.selectedFacts,retrievalStats:r.stats},4200)}async function je(n,e,t={}){let r=h(n,e),o=en(n,e),s=t.router??Ce();try{let a=await s.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
8
9
  You are ToolNet Memory Agent.
9
10
 
10
11
  You are NOT the coding agent.
@@ -38,18 +39,18 @@ ${e}
38
39
 
39
40
  ToolNet selected memory:
40
41
 
41
- ${n}
42
+ ${o}
42
43
 
43
44
  Answer the coding agent directly.
44
- `.trim()}]}),f=a.text.trim();return f?{answer:f,provider:a.provider,model:a.model,usedAi:!0}:{answer:o.answer,usedAi:!1}}catch{return{answer:o.answer,usedAi:!1}}}import{existsSync as Tt,mkdirSync as Ot,readFileSync as Pt,renameSync as St,rmSync as Rt,writeFileSync as Ct}from"node:fs";import{join as Pe}from"node:path";var Se=720*60*1e3;function Re(t){return Pe(t.rootPath,".toolnet","context","memory-agent-conversation.json")}function Q(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function Lt(t){let e=Q(t);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(r=>r.test(e))}function Ft(t){if(Lt(t))return!1;let e=Q(t),r=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(o=>o.test(e))?!0:r.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function Ce(t,e,r){let o=Re(t);if(!Tt(o))return null;try{let n=JSON.parse(Pt(o,"utf8"));if(n.schema!=="toolnet.memory-conversation.v1"||n.version!==1||n.projectId!==t.id||!Array.isArray(n.focus))return null;let i=Date.parse(n.updatedAt);return!Number.isFinite(i)||e-i>r?null:n}catch{return null}}function Nt(t,e=8){let r=new Set,o=[];for(let n of t){let i=n.value.replace(/\s+/gu," ").trim();if(!i)continue;let a=[n.kind,Q(i)].join(":");if(!r.has(a)&&(r.add(a),o.push({...n,value:i}),o.length>=e))break}return o}function Dt(t,e){let r=Re(t),o=Pe(t.rootPath,".toolnet","context");Ot(o,{recursive:!0,mode:448});let n=`${r}.${process.pid}.tmp`;try{Ct(n,JSON.stringify(e,null,2)+`
45
- `,{encoding:"utf8",mode:384}),St(n,r)}finally{Rt(n,{force:!0})}}function Ut(t){return t.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
46
- `)}function Kt(t){let e=Q(t);return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function te(t,e,r={}){let o=r.now??Date.now(),n=r.maxAgeMs??Se,i=Ce(t,o,n),a=!!(i&&i.focus.length>0&&Ft(e)&&!Kt(e)),f=a&&i?[e.trim(),"","Previous ToolNet Memory conversation focus:",Ut(i),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
47
- `):e.trim(),d=H(e),m=R(t,f,{maxFacts:8,maxChars:1800}).facts.map(T=>({kind:T.kind,value:T.value,source:T.source})),h=Nt(a&&i?[...m,...i.focus]:m);return Dt(t,{schema:"toolnet.memory-conversation.v1",version:1,projectId:t.id,updatedAt:new Date(o).toISOString(),lastIntent:d,focus:h}),{question:f,originalQuestion:e,usedPriorFocus:a,previousIntent:i?.lastIntent,currentIntent:d,priorFocus:i?.focus??[],focusCount:h.length}}function Le(t,e={}){return Ce(t,e.now??Date.now(),e.maxAgeMs??Se)}import{existsSync as $t,readFileSync as Bt,writeFileSync as jt}from"node:fs";import{join as Wt}from"node:path";var Ne="<!-- TOOLNET:STABLE-WORK:BEGIN -->",re="<!-- TOOLNET:STABLE-WORK:END -->";function oe(t){switch(t.status){case"completed":return"[x]";case"in_progress":return"[~]";case"blocked":return"[!]";case"cancelled":return"[-]";default:return"[ ]"}}function q(t,e){return e.length?["",`${t}:`,...e.map(r=>`- ${r}`)]:[]}function Fe(t,e){return e.length?["",`${t}:`,...e.map(r=>`- ${oe(r)} ${r.title}`)]:[]}function Gt(t){let e=[Ne,"# ToolNet Stable Work State","",`Updated: ${t.updatedAt}`];return t.lastSession&&e.push(`Last agent: ${t.lastSession.agent}`,`Last session: ${t.lastSession.nativeSessionId}`),t.goal&&e.push("","Goal:",t.goal),t.plan&&e.push("","Plan:",t.plan),t.currentPhase&&e.push("","Current phase:",`${oe(t.currentPhase)} ${t.currentPhase.title}`),t.currentTask&&e.push("","Current task:",`${oe(t.currentTask)} ${t.currentTask.title}`),e.push(...Fe("Phases",t.phases)),e.push(...Fe("TODO / Tasks",t.tasks)),e.push(...q("Next actions",t.nextActions)),e.push(...q("Blockers",t.blockers)),e.push(...q("Important decisions",t.decisions)),e.push(...q("Files touched",t.filesTouched)),e.push("","Progress:",`- Phases: ${t.progress.phasesCompleted}/${t.progress.phasesTotal}`,`- Tasks: ${t.progress.tasksCompleted}/${t.progress.tasksTotal}`,`- Blocked: ${t.progress.blocked}`,"","Continuation:","- Resume current unfinished task.","- Never redo completed TODO/Phase unless explicitly requested.","- Ask ToolNet Memory for deeper history only when necessary.",re),e.join(`
48
- `)}function De(t,e){let r=Wt(t.rootPath,".toolnet","current.md"),o="";if($t(r))try{o=Bt(r,"utf8")}catch{o=""}o=o.replace(/<!-- TOOLNET:AUTO-CURRENT:BEGIN -->[\s\S]*?<!-- TOOLNET:AUTO-CURRENT:END -->/gu,"");let n=Gt(e),i=o.indexOf(Ne),a=o.indexOf(re),f;i>=0&&a>=i?f=[o.slice(0,i).trimEnd(),n,o.slice(a+re.length).trimStart()].filter(Boolean).join(`
49
-
50
- `):f=o.trim()?`${o.trim()}
51
-
52
- ${n}`:n,jt(r,`${f.trim()}
53
- `,{encoding:"utf8",mode:384})}function b(t,e){return{id:e,name:e,rootPath:t,createdAt:"2026-08-13T16:00:00.000Z",updatedAt:"2026-08-13T16:00:00.000Z",graphVersion:1,memoryVersion:1}}function w(t){V(p(t,".toolnet","work"),{recursive:!0,mode:448}),V(p(t,".toolnet","context"),{recursive:!0,mode:448}),V(p(t,".toolnet","sessions"),{recursive:!0,mode:448})}function ie(t,e){V(p(t,".."),{recursive:!0}),I(t,JSON.stringify(e,null,2)+`
54
- `,{encoding:"utf8",mode:384})}function Y(t,e,r,o){ie(p(t.rootPath,".toolnet","context","session-origin.json"),{version:1,projectId:t.id,agent:"codex",nativeSessionId:"x2-origin",updatedAt:"2026-08-13T16:00:00.000Z",currentTask:e,currentPhase:"X2 Recovery",lastTouchedFile:r,latestNextAction:o})}function ne(t,e,r,o){let i={version:1,projectId:t.id,confidence:1,occurredAt:"2026-08-13T16:00:00.000Z",sequence:1,agent:"opencode",nativeSessionId:"x2-work",sessionKey:"opencode:x2-work"},a=Ee(t,[{...i,id:"x2-task-observation",kind:"task",key:"task:x2",text:e,status:"in_progress",order:1,eventId:"x2-task-event"},{...i,id:"x2-file-observation",kind:"file",key:"file:x2",text:r,eventId:"x2-file-event"},{...i,id:"x2-next-observation",kind:"next_action",key:"next:x2",text:o,eventId:"x2-next-event"}]);De(t,a)}function Ue(t,e,r,o,n){return{continuity:{schema:"toolnet.handoff.v2",version:2,project:{id:t.id,name:t.name},source:{agent:"agy",nativeSessionId:"x2-handoff",sessionKey:"agy:x2-handoff",sequence:99,reason:"checkpoint"},capturedAt:"2026-08-13T16:00:00.000Z",current:{phase:{id:"x2",title:"X2 Recovery",status:"in_progress"},task:{id:"x2-task",title:e,status:"in_progress"},file:r},completed:{phases:["X1"],tasks:["X1 cross-agent continuity"]},remaining:{phases:["X2"],tasks:[e],todos:[o]},nextAction:n,blockers:[],decisions:["Canonical handoff must remain authoritative"],files:{current:r,recent:[r]},tests:{status:"passing",recent:["X1 PASS 4/4"]},attention:[],progress:{phasesTotal:3,phasesCompleted:1,tasksTotal:3,tasksCompleted:1,blocked:0},stateDigest:"a".repeat(64)}}}function Qt(t){let e=p(t,".toolnet","context");for(let r of Ht(e)){let o=p(e,r);if(r.endsWith(".json"))try{if(JSON.parse(se(o,"utf8")).schema==="toolnet.memory-conversation.v1")return o}catch{}}return null}async function x(t,e,r){try{let o=await r();return{id:t,label:e,passed:o,detail:o?void 0:"Certification condition returned false."}}catch(o){return{id:t,label:e,passed:!1,detail:o instanceof Error?o.message:String(o)}}}async function Ke(){let t=[];t.push(await x("corrupt-handoff","corrupt handoff \u2192 safe fallback",()=>{let r=y(p(A(),"toolnet-x2-corrupt-handoff-"));try{let o=b(r,"x2-corrupt-handoff");w(r),I(p(r,".toolnet","work","handoff-latest.json"),"{ definitely broken","utf8"),Y(o,"Recover task from session origin","src/x2/session-origin.ts","Continue safely");let n=g(o,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return n.source==="session-origin"&&n.answer.includes("Recover task from session origin")}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("missing-handoff","missing handoff \u2192 WorkState fallback",()=>{let r=y(p(A(),"toolnet-x2-missing-handoff-"));try{let o=b(r,"x2-missing-handoff");w(r),ne(o,"Recover task from WorkState","src/x2/work-state.ts","Continue from WorkState");let n=g(o,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return n.source==="work-state"&&n.answer.includes("Recover task from WorkState")}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("corrupt-session-origin","corrupt session-origin \u2192 WorkState fallback",()=>{let r=y(p(A(),"toolnet-x2-corrupt-origin-"));try{let o=b(r,"x2-corrupt-origin");w(r),I(p(r,".toolnet","context","session-origin.json"),"{ broken origin","utf8"),ne(o,"WorkState survives corrupt origin","src/x2/origin-fallback.ts","Use current WorkState");let n=g(o,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return n.source==="work-state"&&n.answer.includes("WorkState survives corrupt origin")}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("corrupt-conversation","corrupt conversation \u2192 fresh clean state",()=>{let r=y(p(A(),"toolnet-x2-conversation-"));try{let o=b(r,"x2-conversation");w(r),Y(o,"Conversation recovery task","src/x2/conversation.ts","Recover conversation"),te(o,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");let n=Qt(r);if(!n)return!1;I(n,"{ broken conversation","utf8");let i=te(o,"R\u1ED3i sao?"),a=Le(o);return i.usedPriorFocus===!1&&a?.schema==="toolnet.memory-conversation.v1"&&a.projectId===o.id}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("corrupt-work-state","corrupt WorkState \u2192 safe empty answer",()=>{let r=y(p(A(),"toolnet-x2-workstate-"));try{let o=b(r,"x2-corrupt-workstate");w(r),I(p(r,".toolnet","work","current.json"),"{ broken work state","utf8");let n=g(o,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return n.source==="none"&&n.answer.includes("ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory")}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("ai-failure","AI/provider failure \u2192 deterministic local continuity",async()=>{let r=y(p(A(),"toolnet-x2-ai-"));try{let o=b(r,"x2-ai");w(r),Y(o,"Deterministic AI outage fallback","src/x2/ai-fallback.ts","Continue without provider");let n=await Oe(o,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?",{router:{generate:async()=>{throw new Error("X2 forced provider outage")}}});return n.usedAi===!1&&n.answer.includes("Deterministic AI outage fallback")}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("canonical-priority","valid canonical handoff \u2192 stale fallback rejected",()=>{let r=y(p(A(),"toolnet-x2-priority-"));try{let o=b(r,"x2-priority");w(r);let n=p(r,".toolnet","work","handoff-latest.json");ie(n,Ue(o,"CANONICAL X2 TASK","src/x2/canonical.ts","Canonical TODO","Canonical next action")),Y(o,"STALE ORIGIN TASK","src/x2/stale-origin.ts","Stale origin next"),ne(o,"STALE WORKSTATE TASK","src/x2/stale-work.ts","Stale WorkState next");let i=g(o,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return i.source==="handoff"&&i.answer.includes("CANONICAL X2 TASK")&&!i.answer.includes("STALE ORIGIN TASK")&&!i.answer.includes("STALE WORKSTATE TASK")}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("memory-preserved","recovery read \u2192 valid handoff never destroyed",()=>{let r=y(p(A(),"toolnet-x2-preserve-"));try{let o=b(r,"x2-preserve");w(r);let n=p(r,".toolnet","work","handoff-latest.json");ie(n,Ue(o,"Preserve canonical state","src/x2/preserve.ts","Preserve TODO","Preserve next action"));let i=se(n,"utf8");g(o,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?");let a=se(n,"utf8");return i===a}finally{v(r,{recursive:!0,force:!0})}})),t.push(await x("raw-transcript-isolation","raw transcript \u2192 never used for recovery",()=>{let r=y(p(A(),"toolnet-x2-transcript-"));try{let o=b(r,"x2-transcript");w(r);let n="X2_SECRET_RAW_TRANSCRIPT_MUST_NEVER_ENTER_CONTINUITY";I(p(r,".toolnet","sessions","raw-transcript.json"),JSON.stringify({transcript:n}),"utf8"),I(p(r,".toolnet","sessions","events.jsonl"),JSON.stringify({text:n})+`
55
- `,"utf8");let i=g(o,"Agent tr\u01B0\u1EDBc \u0111ang l\xE0m g\xEC?");return i.source==="none"&&!i.answer.includes(n)}finally{v(r,{recursive:!0,force:!0})}}));let e=t.filter(r=>r.passed).length;return{passed:e===t.length,total:t.length,passedCount:e,checks:t}}async function qt(){let t=await Ke();console.log(""),console.log("\u25C7 ToolNet Recovery & Resilience Certification"),console.log("\u2502");for(let e of t.checks)console.log(`\u2502 ${e.passed?"\u2713":"\u2717"} ${e.label}`),!e.passed&&e.detail&&console.log(`\u2502 \u21B3 ${e.detail}`);if(console.log("\u2502"),t.passed){console.log(`\u25C6 PASS ${t.passedCount}/${t.total} recovery checks`);return}console.log(`\u25C6 FAIL ${t.passedCount}/${t.total} recovery checks`),process.exitCode=1}await qt();
45
+ `.trim()}]}),m=a.text.trim();return m?{answer:m,provider:a.provider,model:a.model,usedAi:!0}:{answer:r.answer,usedAi:!1}}catch{return{answer:r.answer,usedAi:!1}}}import{existsSync as tn,mkdirSync as nn,readFileSync as rn,renameSync as on,rmSync as sn,writeFileSync as an}from"node:fs";import{join as Be}from"node:path";var We=720*60*1e3;function qe(n){return Be(n.rootPath,".toolnet","context","memory-agent-conversation.json")}function X(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function cn(n){let e=X(n);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(t=>t.test(e))}function ln(n){if(cn(n))return!1;let e=X(n),t=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(r=>r.test(e))?!0:t.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function ze(n,e,t){let r=qe(n);if(!tn(r))return null;try{let o=JSON.parse(rn(r,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==n.id||!Array.isArray(o.focus))return null;let s=Date.parse(o.updatedAt);return!Number.isFinite(s)||e-s>t?null:o}catch{return null}}function un(n,e=8){let t=new Set,r=[];for(let o of n){let s=o.value.replace(/\s+/gu," ").trim();if(!s)continue;let a=[o.kind,X(s)].join(":");if(!t.has(a)&&(t.add(a),r.push({...o,value:s}),r.length>=e))break}return r}function dn(n,e){let t=qe(n),r=Be(n.rootPath,".toolnet","context");nn(r,{recursive:!0,mode:448});let o=`${t}.${process.pid}.tmp`;try{an(o,JSON.stringify(e,null,2)+`
46
+ `,{encoding:"utf8",mode:384}),on(o,t)}finally{sn(o,{force:!0})}}function mn(n){return n.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
47
+ `)}function pn(n){let e=X(n);return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function se(n,e,t={}){let r=t.now??Date.now(),o=t.maxAgeMs??We,s=ze(n,r,o),a=!!(s&&s.focus.length>0&&ln(e)&&!pn(e)),m=a&&s?[e.trim(),"","Previous ToolNet Memory conversation focus:",mn(s),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
48
+ `):e.trim(),d=V(e),p=R(n,m,{maxFacts:8,maxChars:1800}).facts.map(T=>({kind:T.kind,value:T.value,source:T.source})),v=un(a&&s?[...p,...s.focus]:p);return dn(n,{schema:"toolnet.memory-conversation.v1",version:1,projectId:n.id,updatedAt:new Date(r).toISOString(),lastIntent:d,focus:v}),{question:m,originalQuestion:e,usedPriorFocus:a,previousIntent:s?.lastIntent,currentIntent:d,priorFocus:s?.focus??[],focusCount:v.length}}function He(n,e={}){return ze(n,e.now??Date.now(),e.maxAgeMs??We)}import{existsSync as fn,readFileSync as gn,writeFileSync as yn}from"node:fs";import{join as hn}from"node:path";var Ye="<!-- TOOLNET:STABLE-WORK:BEGIN -->",ie="<!-- TOOLNET:STABLE-WORK:END -->";function ae(n){switch(n.status){case"completed":return"[x]";case"in_progress":return"[~]";case"blocked":return"[!]";case"cancelled":return"[-]";default:return"[ ]"}}function b(n,e){return e.length?["",`${n}:`,...e.map(t=>`- ${t}`)]:[]}function Ge(n,e){return e.length?["",`${n}:`,...e.map(t=>`- ${ae(t)} ${t.title}`)]:[]}function kn(n){let e=[Ye,"# ToolNet Stable Work State","",`Updated: ${n.updatedAt}`];return n.lastSession&&e.push(`Last agent: ${n.lastSession.agent}`,`Last session: ${n.lastSession.nativeSessionId}`),n.currentRequest&&e.push("","Current request:",n.currentRequest),n.currentActivity&&e.push("","Current activity:",n.currentActivity),n.goal&&e.push("","Goal:",n.goal),n.plan&&e.push("","Plan:",n.plan),n.currentPhase&&e.push("","Current phase:",`${ae(n.currentPhase)} ${n.currentPhase.title}`),n.currentTask&&e.push("","Current task:",`${ae(n.currentTask)} ${n.currentTask.title}`),e.push(...Ge("Phases",n.phases)),e.push(...Ge("TODO / Tasks",n.tasks)),e.push(...b("Next actions",n.nextActions)),e.push(...b("Blockers",n.blockers)),e.push(...b("Important decisions",n.decisions)),e.push(...b("Active files",n.activeFiles??[])),e.push(...b("Modified files",n.modifiedFiles??[])),e.push(...b("Created files",n.createdFiles??[])),e.push(...b("Deleted files",n.deletedFiles??[])),e.push(...b("Files touched",n.filesTouched)),e.push(...b("Recent commands",n.commands??[])),e.push(...b("Checks",(n.checks??[]).map(t=>`[${t.status}] ${t.kind}: ${t.command}`))),e.push("","Progress:",`- Phases: ${n.progress.phasesCompleted}/${n.progress.phasesTotal}`,`- Tasks: ${n.progress.tasksCompleted}/${n.progress.tasksTotal}`,`- Blocked: ${n.progress.blocked}`,"","Continuation:","- Resume current unfinished task.","- Never redo completed TODO/Phase unless explicitly requested.","- Ask ToolNet Memory for deeper history only when necessary.",ie),e.join(`
49
+ `)}function Ve(n,e){let t=hn(n.rootPath,".toolnet","current.md"),r="";if(fn(t))try{r=gn(t,"utf8")}catch{r=""}r=r.replace(/<!-- TOOLNET:AUTO-CURRENT:BEGIN -->[\s\S]*?<!-- TOOLNET:AUTO-CURRENT:END -->/gu,"");let o=kn(e),s=r.indexOf(Ye),a=r.indexOf(ie),m;s>=0&&a>=s?m=[r.slice(0,s).trimEnd(),o,r.slice(a+ie.length).trimStart()].filter(Boolean).join(`
50
+
51
+ `):m=r.trim()?`${r.trim()}
52
+
53
+ ${o}`:o,yn(t,`${m.trim()}
54
+ `,{encoding:"utf8",mode:384})}function S(n,e){return{id:e,name:e,rootPath:n,createdAt:"2026-08-13T16:00:00.000Z",updatedAt:"2026-08-13T16:00:00.000Z",graphVersion:1,memoryVersion:1}}function w(n){ee(f(n,".toolnet","work"),{recursive:!0,mode:448}),ee(f(n,".toolnet","context"),{recursive:!0,mode:448}),ee(f(n,".toolnet","sessions"),{recursive:!0,mode:448})}function ue(n,e){ee(f(n,".."),{recursive:!0}),I(n,JSON.stringify(e,null,2)+`
55
+ `,{encoding:"utf8",mode:384})}function Z(n,e,t,r){ue(f(n.rootPath,".toolnet","context","session-origin.json"),{version:1,projectId:n.id,agent:"codex",nativeSessionId:"x2-origin",updatedAt:"2026-08-13T16:00:00.000Z",currentTask:e,currentPhase:"X2 Recovery",lastTouchedFile:t,latestNextAction:r})}function ce(n,e,t,r){let s={version:1,projectId:n.id,confidence:1,occurredAt:"2026-08-13T16:00:00.000Z",sequence:1,agent:"opencode",nativeSessionId:"x2-work",sessionKey:"opencode:x2-work"},a=Ne(n,[{...s,id:"x2-task-observation",kind:"task",key:"task:x2",text:e,status:"in_progress",order:1,eventId:"x2-task-event"},{...s,id:"x2-file-observation",kind:"file",key:"file:x2",text:t,eventId:"x2-file-event"},{...s,id:"x2-next-observation",kind:"next_action",key:"next:x2",text:r,eventId:"x2-next-event"}]);Ve(n,a)}function Je(n,e,t,r,o){return{continuity:{schema:"toolnet.handoff.v2",version:2,project:{id:n.id,name:n.name},source:{agent:"agy",nativeSessionId:"x2-handoff",sessionKey:"agy:x2-handoff",sequence:99,reason:"checkpoint"},capturedAt:"2026-08-13T16:00:00.000Z",current:{phase:{id:"x2",title:"X2 Recovery",status:"in_progress"},task:{id:"x2-task",title:e,status:"in_progress"},file:t},completed:{phases:["X1"],tasks:["X1 cross-agent continuity"]},remaining:{phases:["X2"],tasks:[e],todos:[r]},nextAction:o,blockers:[],decisions:["Canonical handoff must remain authoritative"],files:{current:t,recent:[t]},tests:{status:"passing",recent:["X1 PASS 4/4"]},attention:[],progress:{phasesTotal:3,phasesCompleted:1,tasksTotal:3,tasksCompleted:1,blocked:0},stateDigest:"a".repeat(64)}}}function bn(n){let e=f(n,".toolnet","context");for(let t of vn(e)){let r=f(e,t);if(t.endsWith(".json"))try{if(JSON.parse(le(r,"utf8")).schema==="toolnet.memory-conversation.v1")return r}catch{}}return null}async function E(n,e,t){try{let r=await t();return{id:n,label:e,passed:r,detail:r?void 0:"Certification condition returned false."}}catch(r){return{id:n,label:e,passed:!1,detail:r instanceof Error?r.message:String(r)}}}async function Qe(){let n=[];n.push(await E("corrupt-handoff","corrupt handoff \u2192 safe fallback",()=>{let t=A(f(M(),"toolnet-x2-corrupt-handoff-"));try{let r=S(t,"x2-corrupt-handoff");w(t),I(f(t,".toolnet","work","handoff-latest.json"),"{ definitely broken","utf8"),Z(r,"Recover task from session origin","src/x2/session-origin.ts","Continue safely");let o=h(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="session-origin"&&o.answer.includes("Recover task from session origin")}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("missing-handoff","missing handoff \u2192 WorkState fallback",()=>{let t=A(f(M(),"toolnet-x2-missing-handoff-"));try{let r=S(t,"x2-missing-handoff");w(t),ce(r,"Recover task from WorkState","src/x2/work-state.ts","Continue from WorkState");let o=h(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="work-state"&&o.answer.includes("Recover task from WorkState")}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("corrupt-session-origin","corrupt session-origin \u2192 WorkState fallback",()=>{let t=A(f(M(),"toolnet-x2-corrupt-origin-"));try{let r=S(t,"x2-corrupt-origin");w(t),I(f(t,".toolnet","context","session-origin.json"),"{ broken origin","utf8"),ce(r,"WorkState survives corrupt origin","src/x2/origin-fallback.ts","Use current WorkState");let o=h(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="work-state"&&o.answer.includes("WorkState survives corrupt origin")}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("corrupt-conversation","corrupt conversation \u2192 fresh clean state",()=>{let t=A(f(M(),"toolnet-x2-conversation-"));try{let r=S(t,"x2-conversation");w(t),Z(r,"Conversation recovery task","src/x2/conversation.ts","Recover conversation"),se(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");let o=bn(t);if(!o)return!1;I(o,"{ broken conversation","utf8");let s=se(r,"R\u1ED3i sao?"),a=He(r);return s.usedPriorFocus===!1&&a?.schema==="toolnet.memory-conversation.v1"&&a.projectId===r.id}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("corrupt-work-state","corrupt WorkState \u2192 safe empty answer",()=>{let t=A(f(M(),"toolnet-x2-workstate-"));try{let r=S(t,"x2-corrupt-workstate");w(t),I(f(t,".toolnet","work","current.json"),"{ broken work state","utf8");let o=h(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="none"&&o.answer.includes("ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory")}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("ai-failure","AI/provider failure \u2192 deterministic local continuity",async()=>{let t=A(f(M(),"toolnet-x2-ai-"));try{let r=S(t,"x2-ai");w(t),Z(r,"Deterministic AI outage fallback","src/x2/ai-fallback.ts","Continue without provider");let o=await je(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?",{router:{generate:async()=>{throw new Error("X2 forced provider outage")}}});return o.usedAi===!1&&o.answer.includes("Deterministic AI outage fallback")}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("canonical-priority","valid canonical handoff \u2192 stale fallback rejected",()=>{let t=A(f(M(),"toolnet-x2-priority-"));try{let r=S(t,"x2-priority");w(t);let o=f(t,".toolnet","work","handoff-latest.json");ue(o,Je(r,"CANONICAL X2 TASK","src/x2/canonical.ts","Canonical TODO","Canonical next action")),Z(r,"STALE ORIGIN TASK","src/x2/stale-origin.ts","Stale origin next"),ce(r,"STALE WORKSTATE TASK","src/x2/stale-work.ts","Stale WorkState next");let s=h(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return s.source==="handoff"&&s.answer.includes("CANONICAL X2 TASK")&&!s.answer.includes("STALE ORIGIN TASK")&&!s.answer.includes("STALE WORKSTATE TASK")}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("memory-preserved","recovery read \u2192 valid handoff never destroyed",()=>{let t=A(f(M(),"toolnet-x2-preserve-"));try{let r=S(t,"x2-preserve");w(t);let o=f(t,".toolnet","work","handoff-latest.json");ue(o,Je(r,"Preserve canonical state","src/x2/preserve.ts","Preserve TODO","Preserve next action"));let s=le(o,"utf8");h(r,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?");let a=le(o,"utf8");return s===a}finally{x(t,{recursive:!0,force:!0})}})),n.push(await E("raw-transcript-isolation","raw transcript \u2192 never used for recovery",()=>{let t=A(f(M(),"toolnet-x2-transcript-"));try{let r=S(t,"x2-transcript");w(t);let o="X2_SECRET_RAW_TRANSCRIPT_MUST_NEVER_ENTER_CONTINUITY";I(f(t,".toolnet","sessions","raw-transcript.json"),JSON.stringify({transcript:o}),"utf8"),I(f(t,".toolnet","sessions","events.jsonl"),JSON.stringify({text:o})+`
56
+ `,"utf8");let s=h(r,"Agent tr\u01B0\u1EDBc \u0111ang l\xE0m g\xEC?");return s.source==="none"&&!s.answer.includes(o)}finally{x(t,{recursive:!0,force:!0})}}));let e=n.filter(t=>t.passed).length;return{passed:e===n.length,total:n.length,passedCount:e,checks:n}}async function An(){let n=await Qe();console.log(""),console.log("\u25C7 ToolNet Recovery & Resilience Certification"),console.log("\u2502");for(let e of n.checks)console.log(`\u2502 ${e.passed?"\u2713":"\u2717"} ${e.label}`),!e.passed&&e.detail&&console.log(`\u2502 \u21B3 ${e.detail}`);if(console.log("\u2502"),n.passed){console.log(`\u25C6 PASS ${n.passedCount}/${n.total} recovery checks`);return}console.log(`\u25C6 FAIL ${n.passedCount}/${n.total} recovery checks`),process.exitCode=1}await An();