toolnet-memory 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -4
- package/README.md +428 -202
- package/bin/toolnet-memory +15 -42
- package/bundle/agy-hook.js +47 -47
- package/bundle/agy.js +31 -31
- package/bundle/api.js +15 -52
- package/bundle/auto-integrate.js +34 -33
- package/bundle/claude-hook.js +9 -9
- package/bundle/codex.js +28 -28
- package/bundle/config.js +17 -12
- package/bundle/context-runtime.js +9 -9
- package/bundle/context.js +12 -12
- package/bundle/continuity-certify.js +13 -50
- package/bundle/copilot-hook.js +13 -13
- package/bundle/cursor-hook.js +13 -13
- package/bundle/doctor.js +4 -6
- package/bundle/full-index.js +21 -22
- package/bundle/graph-index.js +3 -3
- package/bundle/graph-ui.js +3 -3
- package/bundle/grok-hook.js +13 -13
- package/bundle/help-cli.js +4 -4
- package/bundle/impact.js +3 -3
- package/bundle/incremental.js +3 -3
- package/bundle/init.js +37 -36
- package/bundle/kilo.js +2 -0
- package/bundle/kiro-hook.js +14 -14
- package/bundle/learner.js +4 -4
- package/bundle/mcp.js +18 -56
- package/bundle/memory-agent.js +7 -47
- package/bundle/opencode.js +27 -27
- package/bundle/project-manual.js +2 -2
- package/bundle/recovery-certify.js +13 -53
- package/bundle/runtime.js +11 -11
- package/bundle/semantic.js +5 -6
- package/bundle/snapshot.js +3 -3
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +2 -0
- package/bundle/work-continuity.js +5 -5
- package/package.json +1 -3
- package/bundle/model-cli.js +0 -2
- package/bundle/provider.js +0 -6
- package/bundle/setup.js +0 -1159
package/bundle/learner.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import{existsSync as ie,readFileSync as ae}from"node:fs";import{homedir as ce}from"node:os";import{join as pe}from"node:path";function ue(o){let e=o.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function de(){let o=process.env.TOOLNET_GLOBAL_ENV??pe(ce(),".config","toolnet-memory",".env");if(!ie(o))return;let e=ae(o,"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 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]=ue(r.slice(n+1)))}}de();function l(o,e){return o===void 0?e:["1","true","yes","on"].includes(o.toLowerCase())}function m(o,e){if(!o)return e;let t=Number(o);return Number.isFinite(t)?t:e}function N(){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)}}}var le={critical:100,high:75,normal:50,temporary:20};function K(o){return le[o]}function $(o,e){let t=e.toLowerCase();return t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c")||t.includes("must not")||t.includes("critical")?"critical":o==="rule"||o==="decision"?"high":o==="todo"?"normal":o==="activity"||o==="summary"?"temporary":"normal"}import{createHash as me}from"node:crypto";import{existsSync as M,mkdirSync as ge,readFileSync as fe,renameSync as ye,writeFileSync as he}from"node:fs";import{basename as Se,dirname as h,join as
|
|
3
|
-
`,{encoding:"utf8",mode:384}),ye(n,r)}function L(o,e){return{id:o.id,name:o.name,remote:o.remote,rootPath:e,createdAt:o.createdAt,updatedAt:o.updatedAt,graphVersion:o.graphVersion,memoryVersion:o.memoryVersion,metadata:o.metadata}}var S=class{detect(e=process.cwd()){let t=g(e),r=be(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>M(v(r,d))),i=xe(t,s?r:void 0);if(i){let d=I(i),u=ke(d);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),D(i,u)),L(u,i)}let a=new Date().toISOString(),c=Se(r),p={version:1,id:we(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return D(r,p),L(p,r)}};import{randomUUID as Le}from"node:crypto";var Pe=[{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}],w=class{scan(e){let t=[];for(let r of Pe){let n=new RegExp(r.regex.source,r.regex.flags);for(let s of e.matchAll(n))t.push({type:r.type,value:s[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var j=class{scanner=new w;sanitize(e){let t=e,r=this.scanner.scan(e),n=new Set;for(let s of r)n.add(s.type),t=t.split(s.value).join(`[REDACTED:${s.type}]`);return{text:t,redacted:r.length,secretTypes:[...n]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,n]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(n)}return t}return e}};var Re=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),Ae=new Set(["d\xF9ng","s\u1EED","d\u1EE5ng","use","using","the","a","an","cho","v\xE0","l\xE0","c\u1EE7a","to","for","with","quy\u1EBFt","\u0111\u1ECBnh"]);function V(o){return new Set(o.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!Ae.has(e)))}function Me(o,e){let t=V(o),r=V(e);if(t.size===0||r.size===0)return 0;let n=0;for(let i of t)r.has(i)&&n++;let s=new Set([...t,...r]).size;return n/s}function F(o){return new Set(o.tags.filter(e=>!Re.has(e.toLowerCase())))}var x=class{findSuperseded(e,t){if(e.type!=="rule"&&e.type!=="decision")return[];let r=typeof e.metadata?.topic=="string"?e.metadata.topic:void 0,n=F(e);return t.filter(s=>{if(s.id===e.id||s.projectId!==e.projectId||s.type!==e.type||s.metadata?.supersededBy)return!1;let i=typeof s.metadata?.topic=="string"?s.metadata.topic:void 0;if(r&&i&&r===i)return!0;let a=F(s);for(let c of n)if(a.has(c))return!0;return Me(e.content,s.content)>=.6})}};var Ie=new Set(["code","decision","rule","todo","summary"]);function Ce(o){return o.normalize("NFKC").toLowerCase().replace(/[“”"'`]/gu,"").replace(/[.!?]+$/gu,"").replace(/\s+/gu," ").trim()}function J(o){return o.tags.includes("class:permanent")?4:o.tags.includes("class:task")?3:o.tags.includes("class:session")?2:o.tags.includes("class:transient")?1:0}function Te(o,e){let t=J(e)-J(o);if(t!==0)return t;let r=e.importanceScore-o.importanceScore;if(r!==0)return r;let n=e.updatedAt.localeCompare(o.updatedAt);if(n!==0)return n;let s=e.createdAt.localeCompare(o.createdAt);return s!==0?s:o.id.localeCompare(e.id)}function U(o){let e=new Set,t=[];for(let r of o){let n=r.trim();if(!n)continue;let s=n.normalize("NFKC").toLowerCase();e.has(s)||(e.add(s),t.push(n))}return t}function H(o){let e=new Map;for(let n of o){if(!Ie.has(n.type)||n.metadata?.supersededBy)continue;let s=Ce(n.content);if(!s)continue;let i=[n.projectId,n.type,s].join("\0"),a=e.get(i)??[];a.push(n),e.set(i,a)}let t=[],r=0;for(let n of e.values()){if(n.length<2)continue;let s=[...n].sort(Te),i=s[0];if(!i)continue;let a=s.slice(1);t.push({canonicalId:i.id,duplicateIds:a.map(c=>c.id),mergedTags:U(s.flatMap(c=>c.tags)),mergedSources:U(s.map(c=>c.source))}),r+=a.length}return{groups:t,duplicates:r}}function C(o){if(o.tags.includes("class:permanent"))return"permanent";if(o.tags.includes("class:task"))return"task";if(o.tags.includes("class:session"))return"session";if(o.tags.includes("class:transient"))return"transient"}function Ee(o,e){let t=new Date(o.updatedAt).getTime();return Number.isFinite(t)?Math.max(0,(e-t)/864e5):0}function Oe(o){let e=C(o);if(e==="permanent")return 730;if(e==="task")return 180;if(e==="session")return 45;if(e==="transient")return 7;switch(o.type){case"rule":return 730;case"decision":return 365;case"code":return 180;case"todo":return 120;case"summary":return 45;case"activity":return 14}}function _e(o){return C(o)==="permanent"||o.type==="rule"||o.type==="decision"||o.importance==="critical"}function Ne(o){let e=o.normalize("NFKC").toLowerCase().trim();return e.length<8?!0:[/^ok(?:ay)?[.!]?$/u,/^done[.!]?$/u,/^thanks?[.!]?$/u,/^test(?:ing)?[.!]?$/u,/^npm notice\b/u,/^changed \d+ packages?/u,/^packages? are looking for funding/u].some(t=>t.test(e))}function Y(o,e=Date.now()){let t=50,r=[],n=C(o);switch(n==="permanent"?(t+=25,r.push("permanent project knowledge")):n==="task"?(t+=15,r.push("active task knowledge")):n==="session"?(t+=2,r.push("session-scoped knowledge")):n==="transient"&&(t-=25,r.push("transient knowledge")),o.importance){case"critical":t+=25,r.push("critical importance");break;case"high":t+=15,r.push("high importance");break;case"normal":break;case"temporary":t-=15,r.push("temporary importance");break}(o.type==="rule"||o.type==="decision")&&(t+=10,r.push("durable knowledge type"));let s=o.content.trim().length;s<12?(t-=30,r.push("very short content")):s<30?(t-=10,r.push("limited context")):s<=1200?(t+=8,r.push("useful context density")):s>5e3&&(t-=15,r.push("excessively large memory")),Ne(o.content)&&(t-=35,r.push("matches transient/noise pattern"));let i=o.metadata?.consolidation;i&&typeof i=="object"&&Array.isArray(i.sources)&&i.sources.length>1&&(t+=10,r.push("confirmed across multiple sources"));let a=Ee(o,e)>=Oe(o);a&&(t-=15,r.push("stale for lifecycle class"));let c=_e(o);t=Math.max(0,Math.min(100,Math.round(t)));let p;t>=80?p="trusted":t>=55?p="useful":t>=30?p="weak":p="noise";let d=o.importance==="temporary"||o.type==="activity"||n==="transient";return{score:t,tier:p,stale:a,protected:c,pruneEligible:!c&&(p==="noise"&&d||a&&(p==="noise"||p==="weak")),reasons:r}}var Ke={critical:100,high:75,normal:50,temporary:20},$e={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function G(o,e,t=new Date){let r;if(e==="temporary"&&(r=30),o==="activity"&&(r=Math.min(r??14,14)),o==="summary"&&(r=Math.min(r??30,30)),!!r)return new Date(t.getTime()+r*864e5).toISOString()}function T(o,e=Date.now()){return o.expiresAt?new Date(o.expiresAt).getTime()<=e:!1}function De(o){return!!o.metadata?.supersededBy}function E(o,e=Date.now()){return!T(o,e)&&!De(o)}function O(o,e=Date.now()){if(!E(o,e))return 0;let t=Ke[o.importance];if(o.importance==="critical")return t;let r=$e[o.type]??180,s=Math.max(0,e-new Date(o.updatedAt).getTime())/864e5,i=Math.pow(.5,s/r);return t*i}var b=class{memories=new Map;sanitizer=new j;conflicts=new x;remember(e){let t=new Date().toISOString(),r=this.sanitizer.sanitize(e.content.trim()).text,n=e.importance??$(e.type,r),s={id:Le(),projectId:e.projectId,type:e.type,content:r,importance:n,importanceScore:K(n),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??G(e.type,n,new Date(t)),metadata:this.sanitizer.sanitizeValue(e.metadata)},i=this.conflicts.findSuperseded(s,this.list(e.projectId));if(i.length){s.metadata={...s.metadata??{},supersedes:i.map(a=>a.id)};for(let a of i)a.updatedAt=t,a.metadata={...a.metadata??{},supersededBy:s.id,supersededAt:t},this.memories.set(a.id,a)}return this.memories.set(s.id,s),s}importRecords(e){let t=0;for(let r of e)r?.id&&(this.memories.set(r.id,r),t++);return t}exportProject(e){return this.listAll(e)}get(e){return this.memories.get(e)}delete(e){return this.memories.delete(e)}listAll(e){return[...this.memories.values()].filter(t=>t.projectId===e).sort((t,r)=>r.createdAt.localeCompare(t.createdAt))}list(e){return this.listAll(e).filter(t=>E(t))}recent(e,t=10){return this.list(e).slice(0,t)}byType(e,t){return this.list(e).filter(r=>r.type===t)}search(e){let t=e.query.trim().toLowerCase(),r=e.limit??10,n=t.split(/\s+/).filter(Boolean);return this.list(e.projectId).filter(s=>{if(e.types&&!e.types.includes(s.type))return!1;let i=O(s);return!(e.minImportanceScore&&i<e.minImportanceScore||e.tags?.length&&!e.tags.some(c=>s.tags.includes(c)))}).map(s=>{let i=s.content.toLowerCase(),a=n.filter(d=>i.includes(d)).length,c=n.length===0?0:a/n.length,p=O(s)/500;return{memory:s,score:c+p,source:"memory"}}).filter(s=>t.length===0||s.score>0).sort((s,i)=>i.score-s.score).slice(0,r)}consolidate(e,t=Date.now()){let r=H(this.list(e)),n=[],s=0;for(let i of r.groups){let a=this.memories.get(i.canonicalId);if(a){a.tags=i.mergedTags,a.metadata={...a.metadata??{},consolidation:{version:1,consolidatedAt:new Date(t).toISOString(),mergedIds:i.duplicateIds,sources:i.mergedSources}},this.memories.set(a.id,a),n.push(a.id);for(let c of i.duplicateIds)this.memories.delete(c)&&(s+=1)}}return{groupsConsolidated:n.length,duplicatesRemoved:s,canonicalIds:n}}reviewLifecycle(e,t=Date.now()){let r={reviewed:0,trusted:0,useful:0,weak:0,noise:0,stale:0,protected:0,pruned:0};for(let n of this.list(e)){let s=Y(n,t);r.reviewed+=1,r[s.tier]+=1,s.stale&&(r.stale+=1),s.protected&&(r.protected+=1),n.metadata={...n.metadata??{},lifecycle:{version:1,reviewedAt:new Date(t).toISOString(),qualityScore:s.score,tier:s.tier,stale:s.stale,protected:s.protected,reasons:s.reasons}},this.memories.set(n.id,n),s.pruneEligible&&this.memories.delete(n.id)&&(r.pruned+=1)}return r}pruneExpired(e,t=Date.now()){let r=0;for(let[n,s]of this.memories)s.projectId===e&&T(s,t)&&(this.memories.delete(n),r++);return r}pruneSuperseded(e,t=30,r=Date.now()){let n=0,s=t*864e5;for(let[i,a]of this.memories){if(a.projectId!==e)continue;let c=a.metadata?.supersededAt;if(typeof c!="string")continue;r-new Date(c).getTime()>=s&&(this.memories.delete(i),n++)}return n}clearProject(e){let t=0;for(let[r,n]of this.memories)n.projectId===e&&(this.memories.delete(r),t++);return t}};import{homedir as ct}from"node:os";import{join as pt}from"node:path";import{DeleteObjectCommand as ze,GetObjectCommand as Be,HeadObjectCommand as Ve,ListObjectsV2Command as Fe,PutObjectCommand as Je,S3Client as Ue}from"@aws-sdk/client-s3";import{getSignedUrl as He}from"@aws-sdk/s3-request-presigner";var k=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ue({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Je({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await He(this.client,new Be({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{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(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Ve({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new ze({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new Fe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};import{access as W,mkdir as Ye,readFile as Ge,readdir as We,rm as Qe,stat as Q,writeFile as qe}from"node:fs/promises";import{dirname as Ze,join as Xe,relative as q,resolve as et}from"node:path";var f=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return et(this.root,t)}async put(e,t){let r=this.path(e);await Ye(Ze(r),{recursive:!0}),await qe(r,t)}async get(e){try{return await Ge(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await W(this.path(e)),!0}catch{return!1}}async delete(e){await Qe(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await W(t)}catch{return r}let n=async i=>{let a=await We(i,{withFileTypes:!0});for(let c of a){let p=Xe(i,c.name);if(c.isDirectory()){await n(p);continue}let d=await Q(p);r.push({key:q(this.root,p),size:d.size,updatedAt:d.mtime.toISOString()})}},s=await Q(t);return s.isDirectory()?await n(t):r.push({key:q(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),r}};import{DeleteObjectCommand as tt,GetObjectCommand as rt,HeadObjectCommand as ot,ListObjectsV2Command as nt,PutObjectCommand as st,S3Client as it}from"@aws-sdk/client-s3";import{getSignedUrl as at}from"@aws-sdk/s3-request-presigner";var y=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new it({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new st({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await at(this.client,new rt({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{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(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new ot({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new tt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new nt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};function _(o,e){return console.warn(e),new f(o)}function Z(o){let e=o.localRoot??pt(ct(),".toolnet-memory","storage");if(o.provider==="r2"){let t=o.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new y({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):_(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(o.provider==="s3"){let t=o.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new y({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):_(e,"[storage] S3 credentials missing. Using local fallback.")}if(o.provider==="huggingface"){let t=o.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new k({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):_(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new f(e)}var P=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let r=JSON.parse(t);if(!Array.isArray(r))throw new Error("Invalid memory snapshot");return r}async save(e,t){let r=JSON.stringify(t,null,2);await this.storage.put(this.key(e),r,"application/json")}};function ut(o){return new Promise(e=>setTimeout(e,o))}async function X(o,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,n=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await o()}catch(a){if(s=a,i>=t)break;let c=Math.min(n,r*2**(i-1)),p=Math.floor(Math.random()*Math.max(1,c*.2));await ut(c+p)}throw s}var dt=new Set(["put","get","getText","delete","list"]);function ee(o,e={}){return new Proxy(o,{get(t,r){let n=Reflect.get(t,r,t);return typeof n!="function"?n:dt.has(r)?(...s)=>X(()=>Promise.resolve(n.apply(t,s)),e):n.bind(t)}})}function te(o){let e=o.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function re(o){let e=o.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var R=class{constructor(e,t,r,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=te(n??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,n=await this.provider.getText(e);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
|
|
4
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=re(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,r){return await this.ensureRegistered(),this.provider.put(this.key(e),t,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{closeSync as lt,mkdirSync as mt,openSync as gt,readFileSync as ft,unlinkSync as oe,writeFileSync as yt}from"node:fs";import{tmpdir as ht}from"node:os";import{join as ne}from"node:path";function St(o){try{return process.kill(o,0),!0}catch(e){return e?.code==="EPERM"}}var A=class{acquired=!1;path;exitHandler=()=>{this.releaseSync()};constructor(e){let t=ne(ht(),"toolnet-memory-locks");mt(t,{recursive:!0});let r=e.replace(/[^A-Za-z0-9_.-]/g,"_");this.path=ne(t,`${r}.lock`)}async acquire(){if(!this.acquired){for(let e=0;e<2;e++)try{let t=gt(this.path,"wx");yt(t,JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()})),lt(t),this.acquired=!0,process.once("exit",this.exitHandler);return}catch(t){if(t?.code!=="EEXIST")throw t;let r=!0;try{let n=JSON.parse(ft(this.path,"utf8"));Number.isInteger(n.pid)&&St(n.pid)&&(r=!1)}catch{r=!0}if(!r)throw new Error("ToolNet Memory is already running for this project");try{oe(this.path)}catch{}}throw new Error("Unable to acquire ToolNet Memory project lock")}}async release(){this.releaseSync()}releaseSync(){if(this.acquired){try{oe(this.path)}catch{}this.acquired=!1,process.off("exit",this.exitHandler)}}};function
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function de(){let o=process.env.TOOLNET_GLOBAL_ENV??pe(ce(),".config","toolnet-memory",".env");if(!ie(o))return;let e=ae(o,"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 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]=ue(r.slice(n+1)))}}de();function l(o,e){return o===void 0?e:["1","true","yes","on"].includes(o.toLowerCase())}function m(o,e){if(!o)return e;let t=Number(o);return Number.isFinite(t)?t:e}function N(){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)}}}var le={critical:100,high:75,normal:50,temporary:20};function K(o){return le[o]}function $(o,e){let t=e.toLowerCase();return t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c")||t.includes("must not")||t.includes("critical")?"critical":o==="rule"||o==="decision"?"high":o==="todo"?"normal":o==="activity"||o==="summary"?"temporary":"normal"}import{createHash as me}from"node:crypto";import{existsSync as M,mkdirSync as ge,readFileSync as fe,renameSync as ye,writeFileSync as he}from"node:fs";import{basename as Se,dirname as h,join as w,parse as z,resolve as g}from"node:path";var B=".toolnet",we="project.json";function ve(o){return me("sha256").update(o).digest("hex").slice(0,16)}function C(o){return w(o,B,we)}function je(o){return M(C(o))}function be(o,e){let t=g(o),r=z(t).root;for(;;){if(je(t))return t;if(t===r||e&&t===g(e))break;let n=h(t);if(n===t)break;t=n}return null}function xe(o){let e=g(o),t=z(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>M(w(e,s))))return e;if(e===t)break;let n=h(e);if(n===e)break;e=n}return g(o)}function ke(o){let e;try{e=JSON.parse(fe(o,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${o}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${o}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${o}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${o}`);let r=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:h(h(o)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function D(o,e){let t=w(o,B);ge(t,{recursive:!0});let r=C(o),n=`${r}.tmp-${process.pid}`;he(n,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),ye(n,r)}function L(o,e){return{id:o.id,name:o.name,remote:o.remote,rootPath:e,createdAt:o.createdAt,updatedAt:o.updatedAt,graphVersion:o.graphVersion,memoryVersion:o.memoryVersion,metadata:o.metadata}}var S=class{detect(e=process.cwd()){let t=g(e),r=xe(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>M(w(r,d))),i=be(t,s?r:void 0);if(i){let d=C(i),u=ke(d);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),D(i,u)),L(u,i)}let a=new Date().toISOString(),c=Se(r),p={version:1,id:ve(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return D(r,p),L(p,r)}};import{randomUUID as Le}from"node:crypto";var Pe=[{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}],v=class{scan(e){let t=[];for(let r of Pe){let n=new RegExp(r.regex.source,r.regex.flags);for(let s of e.matchAll(n))t.push({type:r.type,value:s[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var j=class{scanner=new v;sanitize(e){let t=e,r=this.scanner.scan(e),n=new Set;for(let s of r)n.add(s.type),t=t.split(s.value).join(`[REDACTED:${s.type}]`);return{text:t,redacted:r.length,secretTypes:[...n]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,n]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(n)}return t}return e}};var Re=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),Ae=new Set(["d\xF9ng","s\u1EED","d\u1EE5ng","use","using","the","a","an","cho","v\xE0","l\xE0","c\u1EE7a","to","for","with","quy\u1EBFt","\u0111\u1ECBnh"]);function V(o){return new Set(o.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!Ae.has(e)))}function Me(o,e){let t=V(o),r=V(e);if(t.size===0||r.size===0)return 0;let n=0;for(let i of t)r.has(i)&&n++;let s=new Set([...t,...r]).size;return n/s}function F(o){return new Set(o.tags.filter(e=>!Re.has(e.toLowerCase())))}var b=class{findSuperseded(e,t){if(e.type!=="rule"&&e.type!=="decision")return[];let r=typeof e.metadata?.topic=="string"?e.metadata.topic:void 0,n=F(e);return t.filter(s=>{if(s.id===e.id||s.projectId!==e.projectId||s.type!==e.type||s.metadata?.supersededBy)return!1;let i=typeof s.metadata?.topic=="string"?s.metadata.topic:void 0;if(r&&i&&r===i)return!0;let a=F(s);for(let c of n)if(a.has(c))return!0;return Me(e.content,s.content)>=.6})}};var Ce=new Set(["code","decision","rule","todo","summary"]);function Ie(o){return o.normalize("NFKC").toLowerCase().replace(/[“”"'`]/gu,"").replace(/[.!?]+$/gu,"").replace(/\s+/gu," ").trim()}function J(o){return o.tags.includes("class:permanent")?4:o.tags.includes("class:task")?3:o.tags.includes("class:session")?2:o.tags.includes("class:transient")?1:0}function Te(o,e){let t=J(e)-J(o);if(t!==0)return t;let r=e.importanceScore-o.importanceScore;if(r!==0)return r;let n=e.updatedAt.localeCompare(o.updatedAt);if(n!==0)return n;let s=e.createdAt.localeCompare(o.createdAt);return s!==0?s:o.id.localeCompare(e.id)}function U(o){let e=new Set,t=[];for(let r of o){let n=r.trim();if(!n)continue;let s=n.normalize("NFKC").toLowerCase();e.has(s)||(e.add(s),t.push(n))}return t}function H(o){let e=new Map;for(let n of o){if(!Ce.has(n.type)||n.metadata?.supersededBy)continue;let s=Ie(n.content);if(!s)continue;let i=[n.projectId,n.type,s].join("\0"),a=e.get(i)??[];a.push(n),e.set(i,a)}let t=[],r=0;for(let n of e.values()){if(n.length<2)continue;let s=[...n].sort(Te),i=s[0];if(!i)continue;let a=s.slice(1);t.push({canonicalId:i.id,duplicateIds:a.map(c=>c.id),mergedTags:U(s.flatMap(c=>c.tags)),mergedSources:U(s.map(c=>c.source))}),r+=a.length}return{groups:t,duplicates:r}}function I(o){if(o.tags.includes("class:permanent"))return"permanent";if(o.tags.includes("class:task"))return"task";if(o.tags.includes("class:session"))return"session";if(o.tags.includes("class:transient"))return"transient"}function Ee(o,e){let t=new Date(o.updatedAt).getTime();return Number.isFinite(t)?Math.max(0,(e-t)/864e5):0}function Oe(o){let e=I(o);if(e==="permanent")return 730;if(e==="task")return 180;if(e==="session")return 45;if(e==="transient")return 7;switch(o.type){case"rule":return 730;case"decision":return 365;case"code":return 180;case"todo":return 120;case"summary":return 45;case"activity":return 14}}function _e(o){return I(o)==="permanent"||o.type==="rule"||o.type==="decision"||o.importance==="critical"}function Ne(o){let e=o.normalize("NFKC").toLowerCase().trim();return e.length<8?!0:[/^ok(?:ay)?[.!]?$/u,/^done[.!]?$/u,/^thanks?[.!]?$/u,/^test(?:ing)?[.!]?$/u,/^npm notice\b/u,/^changed \d+ packages?/u,/^packages? are looking for funding/u].some(t=>t.test(e))}function Y(o,e=Date.now()){let t=50,r=[],n=I(o);switch(n==="permanent"?(t+=25,r.push("permanent project knowledge")):n==="task"?(t+=15,r.push("active task knowledge")):n==="session"?(t+=2,r.push("session-scoped knowledge")):n==="transient"&&(t-=25,r.push("transient knowledge")),o.importance){case"critical":t+=25,r.push("critical importance");break;case"high":t+=15,r.push("high importance");break;case"normal":break;case"temporary":t-=15,r.push("temporary importance");break}(o.type==="rule"||o.type==="decision")&&(t+=10,r.push("durable knowledge type"));let s=o.content.trim().length;s<12?(t-=30,r.push("very short content")):s<30?(t-=10,r.push("limited context")):s<=1200?(t+=8,r.push("useful context density")):s>5e3&&(t-=15,r.push("excessively large memory")),Ne(o.content)&&(t-=35,r.push("matches transient/noise pattern"));let i=o.metadata?.consolidation;i&&typeof i=="object"&&Array.isArray(i.sources)&&i.sources.length>1&&(t+=10,r.push("confirmed across multiple sources"));let a=Ee(o,e)>=Oe(o);a&&(t-=15,r.push("stale for lifecycle class"));let c=_e(o);t=Math.max(0,Math.min(100,Math.round(t)));let p;t>=80?p="trusted":t>=55?p="useful":t>=30?p="weak":p="noise";let d=o.importance==="temporary"||o.type==="activity"||n==="transient";return{score:t,tier:p,stale:a,protected:c,pruneEligible:!c&&(p==="noise"&&d||a&&(p==="noise"||p==="weak")),reasons:r}}var Ke={critical:100,high:75,normal:50,temporary:20},$e={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function G(o,e,t=new Date){let r;if(e==="temporary"&&(r=30),o==="activity"&&(r=Math.min(r??14,14)),o==="summary"&&(r=Math.min(r??30,30)),!!r)return new Date(t.getTime()+r*864e5).toISOString()}function T(o,e=Date.now()){return o.expiresAt?new Date(o.expiresAt).getTime()<=e:!1}function De(o){return!!o.metadata?.supersededBy}function E(o,e=Date.now()){return!T(o,e)&&!De(o)}function O(o,e=Date.now()){if(!E(o,e))return 0;let t=Ke[o.importance];if(o.importance==="critical")return t;let r=$e[o.type]??180,s=Math.max(0,e-new Date(o.updatedAt).getTime())/864e5,i=Math.pow(.5,s/r);return t*i}var x=class{memories=new Map;sanitizer=new j;conflicts=new b;remember(e){let t=new Date().toISOString(),r=this.sanitizer.sanitize(e.content.trim()).text,n=e.importance??$(e.type,r),s={id:Le(),projectId:e.projectId,type:e.type,content:r,importance:n,importanceScore:K(n),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??G(e.type,n,new Date(t)),metadata:this.sanitizer.sanitizeValue(e.metadata)},i=this.conflicts.findSuperseded(s,this.list(e.projectId));if(i.length){s.metadata={...s.metadata??{},supersedes:i.map(a=>a.id)};for(let a of i)a.updatedAt=t,a.metadata={...a.metadata??{},supersededBy:s.id,supersededAt:t},this.memories.set(a.id,a)}return this.memories.set(s.id,s),s}importRecords(e){let t=0;for(let r of e)r?.id&&(this.memories.set(r.id,r),t++);return t}exportProject(e){return this.listAll(e)}get(e){return this.memories.get(e)}delete(e){return this.memories.delete(e)}listAll(e){return[...this.memories.values()].filter(t=>t.projectId===e).sort((t,r)=>r.createdAt.localeCompare(t.createdAt))}list(e){return this.listAll(e).filter(t=>E(t))}recent(e,t=10){return this.list(e).slice(0,t)}byType(e,t){return this.list(e).filter(r=>r.type===t)}search(e){let t=e.query.trim().toLowerCase(),r=e.limit??10,n=t.split(/\s+/).filter(Boolean);return this.list(e.projectId).filter(s=>{if(e.types&&!e.types.includes(s.type))return!1;let i=O(s);return!(e.minImportanceScore&&i<e.minImportanceScore||e.tags?.length&&!e.tags.some(c=>s.tags.includes(c)))}).map(s=>{let i=s.content.toLowerCase(),a=n.filter(d=>i.includes(d)).length,c=n.length===0?0:a/n.length,p=O(s)/500;return{memory:s,score:c+p,source:"memory"}}).filter(s=>t.length===0||s.score>0).sort((s,i)=>i.score-s.score).slice(0,r)}consolidate(e,t=Date.now()){let r=H(this.list(e)),n=[],s=0;for(let i of r.groups){let a=this.memories.get(i.canonicalId);if(a){a.tags=i.mergedTags,a.metadata={...a.metadata??{},consolidation:{version:1,consolidatedAt:new Date(t).toISOString(),mergedIds:i.duplicateIds,sources:i.mergedSources}},this.memories.set(a.id,a),n.push(a.id);for(let c of i.duplicateIds)this.memories.delete(c)&&(s+=1)}}return{groupsConsolidated:n.length,duplicatesRemoved:s,canonicalIds:n}}reviewLifecycle(e,t=Date.now()){let r={reviewed:0,trusted:0,useful:0,weak:0,noise:0,stale:0,protected:0,pruned:0};for(let n of this.list(e)){let s=Y(n,t);r.reviewed+=1,r[s.tier]+=1,s.stale&&(r.stale+=1),s.protected&&(r.protected+=1),n.metadata={...n.metadata??{},lifecycle:{version:1,reviewedAt:new Date(t).toISOString(),qualityScore:s.score,tier:s.tier,stale:s.stale,protected:s.protected,reasons:s.reasons}},this.memories.set(n.id,n),s.pruneEligible&&this.memories.delete(n.id)&&(r.pruned+=1)}return r}pruneExpired(e,t=Date.now()){let r=0;for(let[n,s]of this.memories)s.projectId===e&&T(s,t)&&(this.memories.delete(n),r++);return r}pruneSuperseded(e,t=30,r=Date.now()){let n=0,s=t*864e5;for(let[i,a]of this.memories){if(a.projectId!==e)continue;let c=a.metadata?.supersededAt;if(typeof c!="string")continue;r-new Date(c).getTime()>=s&&(this.memories.delete(i),n++)}return n}clearProject(e){let t=0;for(let[r,n]of this.memories)n.projectId===e&&(this.memories.delete(r),t++);return t}};import{homedir as ct}from"node:os";import{join as pt}from"node:path";import{DeleteObjectCommand as ze,GetObjectCommand as Be,HeadObjectCommand as Ve,ListObjectsV2Command as Fe,PutObjectCommand as Je,S3Client as Ue}from"@aws-sdk/client-s3";import{getSignedUrl as He}from"@aws-sdk/s3-request-presigner";var k=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ue({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Je({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await He(this.client,new Be({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{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(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Ve({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new ze({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new Fe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};import{access as W,mkdir as Ye,readFile as Ge,readdir as We,rm as Qe,stat as Q,writeFile as qe}from"node:fs/promises";import{dirname as Ze,join as Xe,relative as q,resolve as et}from"node:path";var f=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return et(this.root,t)}async put(e,t){let r=this.path(e);await Ye(Ze(r),{recursive:!0}),await qe(r,t)}async get(e){try{return await Ge(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await W(this.path(e)),!0}catch{return!1}}async delete(e){await Qe(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await W(t)}catch{return r}let n=async i=>{let a=await We(i,{withFileTypes:!0});for(let c of a){let p=Xe(i,c.name);if(c.isDirectory()){await n(p);continue}let d=await Q(p);r.push({key:q(this.root,p),size:d.size,updatedAt:d.mtime.toISOString()})}},s=await Q(t);return s.isDirectory()?await n(t):r.push({key:q(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),r}};import{DeleteObjectCommand as tt,GetObjectCommand as rt,HeadObjectCommand as ot,ListObjectsV2Command as nt,PutObjectCommand as st,S3Client as it}from"@aws-sdk/client-s3";import{getSignedUrl as at}from"@aws-sdk/s3-request-presigner";var y=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new it({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new st({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await at(this.client,new rt({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{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(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new ot({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new tt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new nt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};function _(o,e){return console.warn(e),new f(o)}function Z(o){let e=o.localRoot??pt(ct(),".toolnet-memory","storage");if(o.provider==="r2"){let t=o.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new y({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):_(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(o.provider==="s3"){let t=o.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new y({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):_(e,"[storage] S3 credentials missing. Using local fallback.")}if(o.provider==="huggingface"){let t=o.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new k({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):_(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new f(e)}var P=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let r=JSON.parse(t);if(!Array.isArray(r))throw new Error("Invalid memory snapshot");return r}async save(e,t){let r=JSON.stringify(t,null,2);await this.storage.put(this.key(e),r,"application/json")}};function ut(o){return new Promise(e=>setTimeout(e,o))}async function X(o,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,n=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await o()}catch(a){if(s=a,i>=t)break;let c=Math.min(n,r*2**(i-1)),p=Math.floor(Math.random()*Math.max(1,c*.2));await ut(c+p)}throw s}var dt=new Set(["put","get","getText","delete","list"]);function ee(o,e={}){return new Proxy(o,{get(t,r){let n=Reflect.get(t,r,t);return typeof n!="function"?n:dt.has(r)?(...s)=>X(()=>Promise.resolve(n.apply(t,s)),e):n.bind(t)}})}function te(o){let e=o.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function re(o){let e=o.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var R=class{constructor(e,t,r,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=te(n??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,n=await this.provider.getText(e);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=re(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,r){return await this.ensureRegistered(),this.provider.put(this.key(e),t,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{closeSync as lt,mkdirSync as mt,openSync as gt,readFileSync as ft,unlinkSync as oe,writeFileSync as yt}from"node:fs";import{tmpdir as ht}from"node:os";import{join as ne}from"node:path";function St(o){try{return process.kill(o,0),!0}catch(e){return e?.code==="EPERM"}}var A=class{acquired=!1;path;exitHandler=()=>{this.releaseSync()};constructor(e){let t=ne(ht(),"toolnet-memory-locks");mt(t,{recursive:!0});let r=e.replace(/[^A-Za-z0-9_.-]/g,"_");this.path=ne(t,`${r}.lock`)}async acquire(){if(!this.acquired){for(let e=0;e<2;e++)try{let t=gt(this.path,"wx");yt(t,JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()})),lt(t),this.acquired=!0,process.once("exit",this.exitHandler);return}catch(t){if(t?.code!=="EEXIST")throw t;let r=!0;try{let n=JSON.parse(ft(this.path,"utf8"));Number.isInteger(n.pid)&&St(n.pid)&&(r=!1)}catch{r=!0}if(!r)throw new Error("ToolNet Memory is already running for this project");try{oe(this.path)}catch{}}throw new Error("Unable to acquire ToolNet Memory project lock")}}async release(){this.releaseSync()}releaseSync(){if(this.acquired){try{oe(this.path)}catch{}this.acquired=!1,process.off("exit",this.exitHandler)}}};function wt(o){let e=o.metadata?.learningFingerprint;return typeof e=="string"?e:void 0}async function vt(o,e){let t=`projects/${o.id}/memory/learned/`,r=await e.list(t),n=[];for(let s of r.filter(i=>i.key.includes("/batches/")&&i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await e.getText(s.key);if(i)try{let a=JSON.parse(i);if(a.version!==1||!Array.isArray(a.candidates))continue;n.push(a)}catch{}}return n}async function se(o,e){let t=await vt(o,e),r=new P(e),n=await r.load(o.id),s=new x;s.importRecords(n);let i=new Set(n.map(d=>wt(d)).filter(d=>!!d)),a=0,c=0,p=0;for(let d of t)for(let u of d.candidates){if(a+=1,i.has(u.fingerprint)){p+=1;continue}s.remember({projectId:o.id,type:u.type,content:u.content,importance:u.importance,tags:u.tags,source:"session-memory-learner",metadata:{learningFingerprint:u.fingerprint,learningKind:u.kind,confidence:u.confidence,provenance:u.provenance,sourceCreatedAt:u.createdAt,sessionKey:u.sessionKey,agent:u.agent,nativeSessionId:u.nativeSessionId}}),i.add(u.fingerprint),c+=1}return c>0&&await r.save(o.id,s.exportProject(o.id)),{batches:t.length,candidates:a,added:c,duplicates:p,memories:s.exportProject(o.id).length}}function jt(o,e){let t=o.indexOf(e);return t>=0?o[t+1]:void 0}async function bt(){let[o="help",...e]=process.argv.slice(2);if(o!=="reconcile"){console.log(`Session Memory Learner
|
|
5
5
|
|
|
6
6
|
Commands:
|
|
7
7
|
reconcile [--project PATH]
|
|
8
|
-
`);return}let t=jt(e,"--project")??process.cwd(),r=new S().detect(t),n=N(),s=ee(Z({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:3}),i=new R(s,r.id,r.name,r.remote??r.name),a=new A(r.id);await a.acquire();try{let c=await se(r,i);console.log(JSON.stringify({project:r.name,...c},null,2))}finally{await a.release()}}
|
|
8
|
+
`);return}let t=jt(e,"--project")??process.cwd(),r=new S().detect(t),n=N(),s=ee(Z({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:3}),i=new R(s,r.id,r.name,r.remote??r.name),a=new A(r.id);await a.acquire();try{let c=await se(r,i);console.log(JSON.stringify({project:r.name,...c},null,2))}finally{await a.release()}}bt().catch(o=>{console.error(o instanceof Error?o.message:o),process.exit(1)});
|