toolnet-memory 0.3.16 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +74 -0
- package/.release-target +1 -1
- package/README.md +157 -7
- package/bin/toolnet-memory +12 -0
- package/bundle/agy-hook.js +59 -59
- package/bundle/agy.js +58 -58
- package/bundle/api.js +15 -15
- package/bundle/audit.js +2 -0
- package/bundle/background-refresh.js +7 -7
- package/bundle/code-capabilities.js +2 -0
- package/bundle/codex.js +63 -63
- package/bundle/context-runtime.js +41 -41
- package/bundle/context.js +15 -15
- package/bundle/copilot-hook.js +73 -73
- package/bundle/cursor-hook.js +73 -73
- package/bundle/docker-healthcheck.js +3 -0
- package/bundle/doctor.js +4 -4
- package/bundle/full-index.js +20 -19
- package/bundle/gc.js +5 -3
- package/bundle/graph-cli.js +1 -1
- package/bundle/graph-index.js +5 -4
- package/bundle/graph-ui.js +4 -3
- package/bundle/grok-hook.js +52 -52
- package/bundle/handoff-refresh.js +2 -2
- package/bundle/help-cli.js +4 -4
- package/bundle/impact.js +5 -4
- package/bundle/incremental.js +5 -5
- package/bundle/init.js +35 -35
- package/bundle/kiro-hook.js +74 -74
- package/bundle/learner.js +8 -6
- package/bundle/mcp.js +19 -17
- package/bundle/memory-agent.js +4 -4
- package/bundle/memory-query.js +3 -3
- package/bundle/opencode.js +73 -73
- package/bundle/project-manual.js +7 -7
- package/bundle/public/index.html +1089 -2306
- package/bundle/runtime.js +16 -13
- package/bundle/semantic.js +6 -5
- package/bundle/service.js +11 -6
- package/bundle/snapshot.js +6 -4
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +49 -49
- package/bundle/work-continuity.js +7 -7
- package/package.json +26 -2
- package/release-manifest.json +57 -1
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{createConnection as p}from"node:net";import{homedir as m}from"node:os";import{join as O}from"node:path";function a(){return process.env.TOOLNET_SERVICE_SOCKET??O(m(),".toolnet","run","service.sock")}var E=Math.max(250,Number(process.env.TOOLNET_DOCKER_HEALTH_TIMEOUT_MS??2e3));async function u(){let l=a();return new Promise(f=>{let e=p({path:l}),t=!1,n="",o=r=>{t||(t=!0,clearTimeout(T),e.destroy(),f(r))},T=setTimeout(()=>{o(!1)},E);e.setEncoding("utf8"),e.once("connect",()=>{e.write(JSON.stringify({type:"ping"})+`
|
|
2
|
+
`)}),e.on("data",r=>{n+=r;let s=n.indexOf(`
|
|
3
|
+
`);if(s<0)return;let c=n.slice(0,s).trim();if(!c){o(!1);return}try{let i=JSON.parse(c);o(i.ok===!0&&i.type==="ping")}catch{o(!1)}}),e.once("error",()=>{o(!1)}),e.once("end",()=>{t||o(!1)})})}var S=await u();S?console.log("TOOLNET_DOCKER_HEALTH=PASS"):(console.error("TOOLNET_DOCKER_HEALTH=FAIL"),process.exitCode=1);
|
package/bundle/doctor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"dotenv/config";import{existsSync as
|
|
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
|
|
3
|
-
`,{encoding:"utf8",mode:384}),Fe(o,n)}function f(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}function H(r){return{version:1,scheme:b,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function Be(r){let e=r.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var P=class{adopt(e,t){let n=W(g(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(oe(n)){let a=A(y(n));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return f(a,n)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=H(t.gitIdentity));let i={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:n,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return M(n,i),f(i,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),s=y(o.rootPath),i=A(s),a=Be(i);if(a&&a!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${a}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let c=i.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:H(t)},i.updatedAt=new Date().toISOString(),M(o.rootPath,i)),f(i,o.rootPath)}findExisting(e=process.cwd()){let t=g(e),n=W(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>C(x(n,c))),i=te(t,s?n:void 0);if(!i)return null;let a=A(y(i));return f(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=g(e),n=W(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>C(x(n,u))),i=te(t,s?n:void 0);if(i){let u=y(i),p=A(u);return p.rootPath!==i&&(p.rootPath=i,p.updatedAt=new Date().toISOString(),M(i,p)),f(p,i)}let a=new Date().toISOString(),c=ze(n),d=ee(n),m={version:1,id:d?X(d.canonicalRemote):He(n),name:c,remote:d?.repositoryName??c,rootPath:n,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:d?{toolnetIdentity:H(d)}:void 0};return M(n,m),f(m,n)}};var Ge=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],Je=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function se(r){return r.normalize("NFKC").trim().toLowerCase()}function Ue(r){if(r.length===0)return 0;let e=new Map;for(let n of r)e.set(n,(e.get(n)??0)+1);let t=0;for(let n of e.values()){let o=n/r.length;t-=o*Math.log2(o)}return t}function Ye(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function qe(r,e,t){let n=r.slice(Math.max(0,e-48),e),o=r.slice(t,Math.min(r.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${o}`)}function Ze(r,e){return r.start<e.end&&e.start<r.end}function ie(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var E=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=se(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of Ge){let i=new RegExp(s.regex.source,s.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:s.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ie(t),o=[];for(let s of n)o.some(i=>Ze(i,s))||o.push(s);return ie(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=se(e);return Je.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(n)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||Ye(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||qe(e,o.index,o.index+s.length)&&(Ue(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var I=class{scanner;constructor(e={}){this.scanner=new E(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let n=e,o=[...t].sort((i,a)=>a.start-i.start),s=new Set;for(let i of o)s.add(i.type),n=n.slice(0,i.start)+`[REDACTED:${i.type}]`+n.slice(i.end);return{text:n,redacted:t.length,secretTypes:[...s].sort()}}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[n,o]of Object.entries(e)){let s=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(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[n]="[REDACTED]";continue}t[n]=this.sanitizeValue(o)}return t}return e}};var tr=new I;import{homedir as xt}from"node:os";import{join as wt}from"node:path";import{DeleteObjectCommand as Xe,GetObjectCommand as et,HeadObjectCommand as tt,ListObjectsV2Command as rt,PutObjectCommand as nt,S3Client as ot}from"@aws-sdk/client-s3";import{getSignedUrl as st}from"@aws-sdk/s3-request-presigner";var T=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ot({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,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new nt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await st(this.client,new et({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new tt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Xe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new rt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as ae,mkdir as it,readFile as at,readdir as ct,rm as ut,stat as ce,writeFile as dt}from"node:fs/promises";import{dirname as lt,join as pt,relative as ue,resolve as mt}from"node:path";var w=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return mt(this.root,t)}async put(e,t){let n=this.path(e);await it(lt(n),{recursive:!0}),await dt(n,t)}async get(e){try{return await at(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 ae(this.path(e)),!0}catch{return!1}}async delete(e){await ut(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await ae(t)}catch{return n}let o=async i=>{let a=await ct(i,{withFileTypes:!0});for(let c of a){let d=pt(i,c.name);if(c.isDirectory()){await o(d);continue}let m=await ce(d);n.push({key:ue(this.root,d),size:m.size,updatedAt:m.mtime.toISOString()})}},s=await ce(t);return s.isDirectory()?await o(t):n.push({key:ue(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as ft,GetObjectCommand as gt,HeadObjectCommand as yt,ListObjectsV2Command as ht,PutObjectCommand as St,S3Client as kt}from"@aws-sdk/client-s3";import{getSignedUrl as bt}from"@aws-sdk/s3-request-presigner";var v=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new kt({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,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new St({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await bt(this.client,new gt({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.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 yt({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 ft({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new ht({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};function B(r,e){return console.warn(e),new w(r)}function de(r){let e=r.localRoot??wt(xt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new v({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):B(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new v({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):B(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new T({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):B(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new w(e)}var _=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 n=JSON.parse(t);if(!Array.isArray(n))throw new Error("Invalid memory snapshot");return n}async save(e,t){let n=JSON.stringify(t,null,2);await this.storage.put(this.key(e),n,"application/json")}};var $=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let n=JSON.parse(t);if(n.version!==1||n.projectId!==e||!Array.isArray(n.records))throw new Error("Invalid vector snapshot");return n}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var O=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var N=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var K=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function vt(r){return new Promise(e=>setTimeout(e,r))}async function le(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await r()}catch(a){if(s=a,i>=t)break;let c=Math.min(o,n*2**(i-1)),d=Math.floor(Math.random()*Math.max(1,c*.2));await vt(c+d)}throw s}var jt=new Set(["put","get","getText","delete","list"]);function pe(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:jt.has(n)?(...s)=>le(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function me(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function fe(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var D=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=me(o??n),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(),n=t,o=await this.provider.getText(e);if(o){let i;try{i=JSON.parse(o)}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"&&(n=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,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=fe(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,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}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))}};var At=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],L=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",n){let o=new Date().toISOString(),s=o.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,s),c=[];for(let m of At){let u=`${i}/${m}`,p=await this.storage.get(u);p&&(await this.storage.put(`${a}/${m}`,p,"application/json"),c.push(m))}if(c.length===0)return null;let d={version:1,id:s,projectId:e,createdAt:o,reason:t,objects:c,metadata:n};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(d,null,2),"application/json"),d}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),o=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),s=[];for(let i of o){let a=await this.storage.getText(i.key);if(a)try{s.push(JSON.parse(a))}catch{}}return s.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let n=this.snapshotPrefix(e,t),o=await this.storage.getText(`${n}/snapshot.json`);if(!o)throw new Error(`Snapshot not found: ${t}`);let s=JSON.parse(o);if(s.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of s.objects){let d=await this.storage.get(`${n}/${c}`);d&&(await this.storage.put(`${i}/${c}`,d,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let n=this.snapshotPrefix(e,t),o=await this.storage.list(n);for(let s of o)await this.storage.delete(s.key);return o.length}async prune(e,t=10){let o=(await this.list(e)).slice(t),s=0;for(let i of o)await this.remove(e,i.id),s++;return s}};function G(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function ge(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?G(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?G(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?G(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: Hugging Face S3 storage credentials incomplete"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Mt}from"node:crypto";var F=class{constructor(e){this.storage=e}storage;async run(){let e=`_health/production-${Mt()}.txt`,t=`toolnet-memory:${Date.now()}`,n=!1;try{await this.storage.put(e,t,"text/plain"),n=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}return{ok:n,storage:{ok:n,provider:this.storage.name},embedding:null}}};import{existsSync as be,readFileSync as It,readdirSync as he}from"node:fs";import{join as j}from"node:path";var Yn=new Int32Array(new SharedArrayBuffer(4));import{closeSync as eo,existsSync as Ct,fsyncSync as to,mkdirSync as ro,openSync as no,readFileSync as Rt,renameSync as oo,writeFileSync as so}from"node:fs";import{dirname as ao,join as Pt}from"node:path";function Et(r){return Pt(r.rootPath,".toolnet","work","current.json")}function ye(r){let e=Et(r);if(!Ct(e))return null;try{let t=JSON.parse(Rt(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function xe(r){if(!be(r))return null;try{return JSON.parse(It(r,"utf8"))}catch{return null}}function Se(r,e){if(!be(r))return[];let t=[];for(let n of he(r,{withFileTypes:!0})){if(!n.isDirectory())continue;let o=j(r,n.name);for(let s of he(o,{withFileTypes:!0})){if(!s.isDirectory())continue;let i=xe(j(o,s.name,"state.json"));i&&i.version===1&&i.projectId===e.id&&t.push(i)}}return t}function Tt(r){let e=j(r.rootPath,".toolnet","runtime","sources"),t=j(r.rootPath,".toolnet","sessions"),n=Se(e,r),o=Se(t,r),s=new Map;for(let i of o)s.set(`${i.agent}:${i.nativeSessionId}`,i);for(let i of n)s.set(`${i.agent}:${i.nativeSessionId}`,i);return Array.from(s.values())}function ke(r){return r.filter(e=>!!e).sort().at(-1)}function _t(r){let e=xe(j(r.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==r.rootPath?null:e}function we(r){let e=Tt(r),n=[...e].sort((u,p)=>(u.lastLocalEventAt??u.updatedAt).localeCompare(p.lastLocalEventAt??p.updatedAt)).at(-1),o=Array.from(new Set(e.map(u=>u.agent))).sort(),s=e.reduce((u,p)=>u+Math.max(0,p.lastSequence-p.lastRemoteSequence),0),i=_t(r),a=i?.state==="capture-failed",c=i?.state==="sync-failed",d;a?d="degraded":s>0||c?d="pending":e.length>0?d="healthy":d="unknown";let m=ye(r);return{ok:d!=="degraded",agents:o,sessions:e.length,latestAgent:n?.agent,latestSessionId:n?.nativeSessionId,lastCaptureAt:ke(e.map(u=>u.lastLocalEventAt??u.updatedAt)),lastFlushAt:ke(e.map(u=>u.lastRemoteAt)),pendingWal:s,currentTask:m?.currentTask?.title,currentFile:m?.activeFiles?.at(-1)??m?.filesTouched.at(-1),syncHealth:d,opencode:i?{state:i.state,reason:i.reason,timestamp:i.timestamp,error:i.error}:void 0}}function je(){return process.argv.includes("--json")}function $t(r){let e=process.stdout.isTTY===!0&&process.env.TERM!=="dumb"&&process.env.NO_COLOR===void 0,t=(l,J)=>e?`\x1B[${l}m${J}\x1B[0m`:J,n=l=>t("38;5;82",l),o=l=>t("38;5;51",l),s=l=>t("38;5;214",l),i=l=>t("38;5;196",l),a=l=>t("38;5;255",l),c=l=>t("2",l),d=l=>t("1",l),m=c("\u2502"),u=c("\u251C");if(console.log(""),console.log(`${o("\u25C7")} ${d(a("ToolNet Memory Doctor"))}`),console.log(""),r.project&&console.log(`${n("\u25C6")} Project ${a(r.project)}`),console.log(m),r.storage){let l=typeof r.storage.provider=="string"?` \u2014 ${r.storage.provider}`:"";r.storage.ok?console.log(`${u} ${n("\u25C6")} Storage${l}`):console.log(`${u} ${i("\u2717")} Storage${l}`)}if((r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(m),console.log(`${o("\u25C7")} ${a("Project data")}`),r.memory!==void 0&&console.log(`${u} ${c("Memories")} ${a(String(r.memory))}`),r.graphSymbols!==void 0&&console.log(`${u} ${c("Graph symbols")} ${a(String(r.graphSymbols))}`),r.graphEdges!==void 0&&console.log(`${u} ${c("Graph edges")} ${a(String(r.graphEdges))}`),r.memoryVectors!==void 0&&console.log(`${u} ${c("Memory vectors")} ${a(String(r.memoryVectors))}`),r.codeChunks!==void 0&&console.log(`${u} ${c("Code chunks")} ${a(String(r.codeChunks))}`),r.codeVectors!==void 0&&console.log(`${u} ${c("Code vectors")} ${a(String(r.codeVectors))}`),r.snapshots!==void 0&&console.log(`${u} ${c("Snapshots")} ${a(String(r.snapshots))}`)),r.capture){console.log(m),console.log(`${o("\u25C7")} ${a("Session continuity")}`),console.log(`${u} ${c("Agents")} ${a(r.capture.agents.length?r.capture.agents.join(", "):"none")}`),r.capture.latestAgent&&console.log(`${u} ${c("Latest agent")} ${a(String(r.capture.latestAgent))}`),r.capture.currentTask&&console.log(`${u} ${c("Current task")} ${a(r.capture.currentTask)}`),r.capture.currentFile&&console.log(`${u} ${c("Current file")} ${a(r.capture.currentFile)}`),r.capture.lastCaptureAt&&console.log(`${u} ${c("Last capture")} ${a(r.capture.lastCaptureAt)}`),r.capture.lastFlushAt&&console.log(`${u} ${c("Last flush")} ${a(r.capture.lastFlushAt)}`),console.log(`${u} ${c("Pending WAL")} ${a(String(r.capture.pendingWal))}`);let l=r.capture.syncHealth==="healthy"?n(r.capture.syncHealth):r.capture.syncHealth==="degraded"?i(r.capture.syncHealth):s(r.capture.syncHealth);console.log(`${u} ${c("Sync health")} ${l}`)}let p=r.config?.errors??[];if(p.length>0){console.log(m),console.log(`${i("\u2717")} ${a("Configuration required")}`);for(let l of p)console.log(`${u} ${i("\u2022")} ${l}`)}let V=[...r.config?.warnings??[],...r.warnings??[]],h=[...new Set(V)];if(h.length>0){console.log(m),console.log(`${s("\u25C7")} ${a("Warnings")}`);for(let l of h)console.log(`${u} ${s("!")} ${l}`)}console.log(m),r.ok?console.log(`${n("\u2514 \u25C6")} ${d(a("ToolNet Memory is ready"))}`):(console.log(`${i("\u2514 \u2717")} ${d(a("ToolNet Memory requires attention"))}`),p.length>0&&console.log(c(" Run: toolnet-memory setup"))),console.log("")}function ve(r){je()?console.log(JSON.stringify(r,null,2)):$t(r)}async function Ot(){let r=ge();if(!r.ok){let l={ok:!1,config:r,warnings:r.warnings};ve(l),process.exitCode=1;return}let e=U(),t=new P().detect(),n=pe(de({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new D(n,t.id,t.name,t.remote??t.name),s=await new F(n).run(),i=await new _(o).load(t.id),a=await new O(o).load(t.id),c=await new $(o).load(t.id),d=await new N(o).load(t.id),m=await new K(o).load(t.id),u=await new L(o).list(t.id),p=we(t),V=p.syncHealth==="degraded"?[`Session capture degraded${p.opencode?.error?`: ${p.opencode.error}`:""}`]:[],h={ok:s.ok&&p.ok,project:t.name,storage:s.storage,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:c?.records.length??0,codeChunks:d?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:u.length,capture:p,warnings:[...r.warnings,...V]};ve(h),process.exitCode=h.ok?0:1}Ot().catch(r=>{let e=r instanceof Error?r.message:String(r);je()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
|
|
1
|
+
import"dotenv/config";import{existsSync as Be,readFileSync as He}from"node:fs";import{homedir as Ue}from"node:os";import{join as Ge}from"node:path";function Je(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function qe(){let r=process.env.TOOLNET_GLOBAL_ENV??Ge(Ue(),".config","toolnet-memory",".env");if(!Be(r))return;let e=He(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Je(n.slice(o+1)))}}qe();function b(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function w(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function oe(){return{memory:{autoCapture:b(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:b(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:b(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:b(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:w(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:w(process.env.MEMORY_RERANK_TOP,10),finalContext:w(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:w(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:b(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:w(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as nt}from"node:crypto";import{existsSync as T,mkdirSync as ot,readFileSync as st,renameSync as it,writeFileSync as at}from"node:fs";import{basename as ct,dirname as _,join as E,parse as pe,resolve as y}from"node:path";import{createHash as ae}from"node:crypto";import{spawnSync as Ze}from"node:child_process";var x="git-remote-v1",Qe=new Set(["github.com","gitlab.com","bitbucket.org"]);function ce(r,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(n=>!n||n==="."||n==="..")?null:(Qe.has(r)&&(t=t.toLowerCase()),t)}function Xe(r){let e;try{e=new URL(r)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let n=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!n?`${t}:${e.port}`:t,s=ce(t,e.pathname);return s?`${o}/${s}`:null}function et(r){let e=r.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let n=ce(t,e[2]??"");return n?`${t}/${n}`:null}function se(r){let e=r.trim();return e?e.includes("://")?Xe(e):et(e):null}function tt(r){return ae("sha256").update(`${x}:${r}`).digest("hex")}function ue(r){return ae("sha256").update(`toolnet-project:${x}:${r}`).digest("hex").slice(0,16)}function rt(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function U(r,e){let t=Ze("git",["-C",r,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function ie(r,e){let t=rt(r);return t?{scheme:x,canonicalRemote:r,fingerprint:tt(r),repositoryName:t,source:e}:null}function de(r){let e=U(r,["remote","get-url","origin"]);if(e){let o=se(e);if(o)return ie(o,"origin")}let t=U(r,["remote"]);if(!t)return null;let n=new Set;for(let o of t.split(/\r?\n/u).map(s=>s.trim()).filter(Boolean)){let s=U(r,["remote","get-url",o]);if(!s)continue;let i=se(s);i&&n.add(i)}return n.size!==1?null:ie([...n][0],"unique-remote")}var me=".toolnet",ut="project.json";function dt(r){return nt("sha256").update(r).digest("hex").slice(0,16)}function S(r){return E(r,me,ut)}function fe(r){return T(S(r))}function le(r,e){let t=y(r),n=pe(t).root;for(;;){if(fe(t))return t;if(t===n||e&&t===y(e))break;let o=_(t);if(o===t)break;t=o}return null}function G(r){let e=y(r),t=pe(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>T(E(e,s))))return e;if(e===t)break;let o=_(e);if(o===e)break;e=o}return y(r)}function P(r){let e;try{e=JSON.parse(st(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:_(_(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function I(r,e){let t=E(r,me);ot(t,{recursive:!0});let n=S(r),o=`${n}.tmp-${process.pid}`;at(o,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),it(o,n)}function g(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}function J(r){return{version:1,scheme:x,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function lt(r){let e=r.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var O=class{adopt(e,t){let n=G(y(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(fe(n)){let a=P(S(n));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return g(a,n)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=J(t.gitIdentity));let i={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:n,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return I(n,i),g(i,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),s=S(o.rootPath),i=P(s),a=lt(i);if(a&&a!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${a}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let c=i.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:J(t)},i.updatedAt=new Date().toISOString(),I(o.rootPath,i)),g(i,o.rootPath)}findExisting(e=process.cwd()){let t=y(e),n=G(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>T(E(n,c))),i=le(t,s?n:void 0);if(!i)return null;let a=P(S(i));return g(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=y(e),n=G(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>T(E(n,u))),i=le(t,s?n:void 0);if(i){let u=S(i),m=P(u);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),I(i,m)),g(m,i)}let a=new Date().toISOString(),c=ct(n),d=de(n),p={version:1,id:d?ue(d.canonicalRemote):dt(n),name:c,remote:d?.repositoryName??c,rootPath:n,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:d?{toolnetIdentity:J(d)}:void 0};return I(n,p),g(p,n)}};var pt=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],mt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ge(r){return r.normalize("NFKC").trim().toLowerCase()}function ft(r){if(r.length===0)return 0;let e=new Map;for(let n of r)e.set(n,(e.get(n)??0)+1);let t=0;for(let n of e.values()){let o=n/r.length;t-=o*Math.log2(o)}return t}function gt(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function yt(r,e,t){let n=r.slice(Math.max(0,e-48),e),o=r.slice(t,Math.min(r.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${o}`)}function ht(r,e){return r.start<e.end&&e.start<r.end}function ye(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var N=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=ge(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of pt){let i=new RegExp(s.regex.source,s.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:s.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ye(t),o=[];for(let s of n)o.some(i=>ht(i,s))||o.push(s);return ye(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ge(e);return mt.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(n)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||gt(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||yt(e,o.index,o.index+s.length)&&(ft(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var $=class{scanner;constructor(e={}){this.scanner=new N(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let n=e,o=[...t].sort((i,a)=>a.start-i.start),s=new Set;for(let i of o)s.add(i.type),n=n.slice(0,i.start)+`[REDACTED:${i.type}]`+n.slice(i.end);return{text:n,redacted:t.length,secretTypes:[...s].sort()}}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[n,o]of Object.entries(e)){let s=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(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[n]="[REDACTED]";continue}t[n]=this.sanitizeValue(o)}return t}return e}};var Cr=new $;import{homedir as Jt}from"node:os";import{join as qt}from"node:path";import{DeleteObjectCommand as kt,GetObjectCommand as bt,HeadObjectCommand as wt,ListObjectsV2Command as xt,PutObjectCommand as Et,S3Client as vt}from"@aws-sdk/client-s3";import{getSignedUrl as Rt}from"@aws-sdk/s3-request-presigner";var K=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new vt({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,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Et({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Rt(this.client,new bt({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.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 wt({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 kt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new xt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as he,mkdir as At,readFile as Mt,readdir as jt,rm as Ct,stat as Se,writeFile as Pt}from"node:fs/promises";import{dirname as It,join as Tt,relative as ke,resolve as _t}from"node:path";var v=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _t(this.root,t)}async put(e,t){let n=this.path(e);await At(It(n),{recursive:!0}),await Pt(n,t)}async get(e){try{return await Mt(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 he(this.path(e)),!0}catch{return!1}}async delete(e){await Ct(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await he(t)}catch{return n}let o=async i=>{let a=await jt(i,{withFileTypes:!0});for(let c of a){let d=Tt(i,c.name);if(c.isDirectory()){await o(d);continue}let p=await Se(d);n.push({key:ke(this.root,d),size:p.size,updatedAt:p.mtime.toISOString()})}},s=await Se(t);return s.isDirectory()?await o(t):n.push({key:ke(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as Ot,GetObjectCommand as Nt,HeadObjectCommand as $t,ListObjectsV2Command as Kt,PutObjectCommand as Dt,S3Client as Lt}from"@aws-sdk/client-s3";import{getSignedUrl as Ft}from"@aws-sdk/s3-request-presigner";var R=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Lt({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,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Dt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Ft(this.client,new Nt({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.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 $t({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 Ot({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Kt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{createCipheriv as Vt,createDecipheriv as Yt,createHash as zt,randomBytes as Wt,timingSafeEqual as Bt}from"node:crypto";import{readFileSync as Ht}from"node:fs";var h=Buffer.from("TNMEME01","ascii"),we=1,A=8,M=12,q=16,xe=h.length+1+A+M+q,Ut="toolnet-memory:remote-encryption:v1:",Ee="aes-256-gcm",Z=32,f=class extends Error{constructor(t,n){super(n);this.code=t;this.name="RemoteEncryptionError"}code};function Gt(r){return r?["1","true","yes","on","enabled"].includes(r.trim().toLowerCase()):!1}function Q(r=process.env){return Gt(r.TOOLNET_REMOTE_ENCRYPTION)}function be(r){let e=r.trim();if(!e)throw new f("REMOTE_ENCRYPTION_KEY_EMPTY","Remote encryption key is empty.");let t;if(e.startsWith("hex:")){let n=e.slice(4);if(!/^[0-9a-f]{64}$/iu.test(n))throw new f("REMOTE_ENCRYPTION_KEY_INVALID","hex: remote encryption key must contain exactly 64 hexadecimal characters.");t=Buffer.from(n,"hex")}else if(/^[0-9a-f]{64}$/iu.test(e))t=Buffer.from(e,"hex");else{let n=e.startsWith("base64:")?e.slice(7):e;if(!/^[A-Za-z0-9+/_-]+={0,2}$/u.test(n))throw new f("REMOTE_ENCRYPTION_KEY_INVALID","Remote encryption key must be 32 raw bytes encoded as hexadecimal or base64.");t=Buffer.from(n,n.includes("-")||n.includes("_")?"base64url":"base64")}if(t.length!==Z)throw new f("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH",`Remote encryption key must decode to exactly ${Z} bytes.`);return t}function ve(r=process.env){let e=r.TOOLNET_REMOTE_ENCRYPTION_KEY?.trim(),t=r.TOOLNET_REMOTE_ENCRYPTION_KEY_FILE?.trim();if(e&&t)throw new f("REMOTE_ENCRYPTION_KEY_AMBIGUOUS","Configure either TOOLNET_REMOTE_ENCRYPTION_KEY or TOOLNET_REMOTE_ENCRYPTION_KEY_FILE, not both.");if(e)return be(e);if(t){let n;try{n=Ht(t,"utf8")}catch(o){throw new f("REMOTE_ENCRYPTION_KEY_FILE_READ_FAILED",[`Unable to read remote encryption key file: ${t}.`,o instanceof Error?o.message:String(o)].join(" "))}return be(n)}}function Re(r){return zt("sha256").update(r).digest().subarray(0,A)}function Ae(r){return Buffer.from(`${Ut}${r}`,"utf8")}function X(r){return r.byteLength<h.length?!1:Buffer.from(r).subarray(0,h.length).equals(h)}function Me(r,e,t){if(t.byteLength!==Z)throw new f("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH","AES-256-GCM requires a 32-byte key.");let n=typeof e=="string"?Buffer.from(e,"utf8"):Buffer.from(e),o=Wt(M),s=Vt(Ee,t,o);s.setAAD(Ae(r));let i=Buffer.concat([s.update(n),s.final()]),a=s.getAuthTag(),c=Buffer.alloc(xe),d=0;return h.copy(c,d),d+=h.length,c.writeUInt8(we,d),d+=1,Re(t).copy(c,d),d+=A,o.copy(c,d),d+=M,a.copy(c,d),Buffer.concat([c,i])}function je(r,e,t){let n=Buffer.from(e);if(!X(n))throw new f("REMOTE_ENCRYPTION_ENVELOPE_REQUIRED","Payload is not a ToolNet encrypted remote object.");if(n.length<xe)throw new f("REMOTE_ENCRYPTION_ENVELOPE_TRUNCATED","Encrypted remote payload is truncated.");let o=h.length,s=n.readUInt8(o);if(o+=1,s!==we)throw new f("REMOTE_ENCRYPTION_VERSION_UNSUPPORTED",`Unsupported remote encryption envelope version: ${s}.`);let i=n.subarray(o,o+A);o+=A;let a=Re(t);if(!Bt(i,a))throw new f("REMOTE_ENCRYPTION_KEY_MISMATCH","Configured remote encryption key does not match this encrypted object.");let c=n.subarray(o,o+M);o+=M;let d=n.subarray(o,o+q);o+=q;let p=n.subarray(o),u=Yt(Ee,t,c);u.setAAD(Ae(r)),u.setAuthTag(d);try{return Buffer.concat([u.update(p),u.final()])}catch{throw new f("REMOTE_ENCRYPTION_AUTH_FAILED","Encrypted remote object failed AES-GCM authentication.")}}var ee=class{constructor(e,t){this.inner=e;this.options=t;if(this.name=e.name,t.enabled&&!t.key)throw new f("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote client-side encryption is enabled but no encryption key is configured.")}inner;options;name;async put(e,t,n){if(!this.options.enabled){await this.inner.put(e,t,n);return}let o=this.options.key;if(!o)throw new f("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote encryption key is unavailable.");let s=Me(e,t,o);await this.inner.put(e,s,"application/octet-stream")}async get(e){let t=await this.inner.get(e);if(!t)return null;if(!X(t))return t;if(!this.options.enabled)throw new f("REMOTE_ENCRYPTION_REQUIRED",["Remote object is client-side encrypted.","Enable TOOLNET_REMOTE_ENCRYPTION and configure the matching key."].join(" "));let n=this.options.key;if(!n)throw new f("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote object is encrypted but no decryption key is configured.");return je(e,t,n)}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){return this.inner.exists(e)}async delete(e){await this.inner.delete(e)}async list(e=""){return this.inner.list(e)}};function Ce(r,e=process.env){if(r.name==="local")return Q(e)&&console.warn("[storage] Remote encryption requested but active storage provider is local; local data remains unchanged."),r;let t=Q(e),n=t?ve(e):void 0;return new ee(r,{enabled:t,key:n})}function j(r){return Ce(r)}function te(r,e){return console.warn(e),j(new v(r))}function Pe(r){let e=r.localRoot??qt(Jt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?j(new R({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):te(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?j(new R({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):te(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?j(new K({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):te(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return j(new v(e))}var D=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 n=JSON.parse(t);if(!Array.isArray(n))throw new Error("Invalid memory snapshot");return n}async save(e,t){let n=JSON.stringify(t,null,2);await this.storage.put(this.key(e),n,"application/json")}};var L=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let n=JSON.parse(t);if(n.version!==1||n.projectId!==e||!Array.isArray(n.records))throw new Error("Invalid vector snapshot");return n}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var F=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var V=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var Y=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function Zt(r){return new Promise(e=>setTimeout(e,r))}async function Ie(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await r()}catch(a){if(s=a,i>=t)break;let c=Math.min(o,n*2**(i-1)),d=Math.floor(Math.random()*Math.max(1,c*.2));await Zt(c+d)}throw s}var Qt=new Set(["put","get","getText","delete","list"]);function Te(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:Qt.has(n)?(...s)=>Ie(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function _e(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Oe(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var z=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=_e(o??n),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(),n=t,o=await this.provider.getText(e);if(o){let i;try{i=JSON.parse(o)}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"&&(n=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,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=Oe(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,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}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))}};var Xt=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],W=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",n){let o=new Date().toISOString(),s=o.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,s),c=[];for(let p of Xt){let u=`${i}/${p}`,m=await this.storage.get(u);m&&(await this.storage.put(`${a}/${p}`,m,"application/json"),c.push(p))}if(c.length===0)return null;let d={version:1,id:s,projectId:e,createdAt:o,reason:t,objects:c,metadata:n};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(d,null,2),"application/json"),d}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),o=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),s=[];for(let i of o){let a=await this.storage.getText(i.key);if(a)try{s.push(JSON.parse(a))}catch{}}return s.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let n=this.snapshotPrefix(e,t),o=await this.storage.getText(`${n}/snapshot.json`);if(!o)throw new Error(`Snapshot not found: ${t}`);let s=JSON.parse(o);if(s.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of s.objects){let d=await this.storage.get(`${n}/${c}`);d&&(await this.storage.put(`${i}/${c}`,d,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let n=this.snapshotPrefix(e,t),o=await this.storage.list(n);for(let s of o)await this.storage.delete(s.key);return o.length}async prune(e,t=10){let o=(await this.list(e)).slice(t),s=0;for(let i of o)await this.remove(e,i.id),s++;return s}};function re(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function Ne(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?re(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?re(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?re(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: Hugging Face S3 storage credentials incomplete"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as er}from"node:crypto";var B=class{constructor(e){this.storage=e}storage;async run(){let e=`_health/production-${er()}.txt`,t=`toolnet-memory:${Date.now()}`,n=!1;try{await this.storage.put(e,t,"text/plain"),n=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}return{ok:n,storage:{ok:n,provider:this.storage.name},embedding:null}}};import{existsSync as Fe,readFileSync as sr,readdirSync as Ke}from"node:fs";import{join as C}from"node:path";var Io=new Int32Array(new SharedArrayBuffer(4));import{closeSync as $o,existsSync as tr,fsyncSync as Ko,mkdirSync as Do,openSync as Lo,readFileSync as rr,renameSync as Fo,writeFileSync as Vo}from"node:fs";import{dirname as zo,join as nr}from"node:path";function or(r){return nr(r.rootPath,".toolnet","work","current.json")}function $e(r){let e=or(r);if(!tr(e))return null;try{let t=JSON.parse(rr(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function Ve(r){if(!Fe(r))return null;try{return JSON.parse(sr(r,"utf8"))}catch{return null}}function De(r,e){if(!Fe(r))return[];let t=[];for(let n of Ke(r,{withFileTypes:!0})){if(!n.isDirectory())continue;let o=C(r,n.name);for(let s of Ke(o,{withFileTypes:!0})){if(!s.isDirectory())continue;let i=Ve(C(o,s.name,"state.json"));i&&i.version===1&&i.projectId===e.id&&t.push(i)}}return t}function ir(r){let e=C(r.rootPath,".toolnet","runtime","sources"),t=C(r.rootPath,".toolnet","sessions"),n=De(e,r),o=De(t,r),s=new Map;for(let i of o)s.set(`${i.agent}:${i.nativeSessionId}`,i);for(let i of n)s.set(`${i.agent}:${i.nativeSessionId}`,i);return Array.from(s.values())}function Le(r){return r.filter(e=>!!e).sort().at(-1)}function ar(r){let e=Ve(C(r.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==r.rootPath?null:e}function Ye(r){let e=ir(r),n=[...e].sort((u,m)=>(u.lastLocalEventAt??u.updatedAt).localeCompare(m.lastLocalEventAt??m.updatedAt)).at(-1),o=Array.from(new Set(e.map(u=>u.agent))).sort(),s=e.reduce((u,m)=>u+Math.max(0,m.lastSequence-m.lastRemoteSequence),0),i=ar(r),a=i?.state==="capture-failed",c=i?.state==="sync-failed",d;a?d="degraded":s>0||c?d="pending":e.length>0?d="healthy":d="unknown";let p=$e(r);return{ok:d!=="degraded",agents:o,sessions:e.length,latestAgent:n?.agent,latestSessionId:n?.nativeSessionId,lastCaptureAt:Le(e.map(u=>u.lastLocalEventAt??u.updatedAt)),lastFlushAt:Le(e.map(u=>u.lastRemoteAt)),pendingWal:s,currentTask:p?.currentTask?.title,currentFile:p?.activeFiles?.at(-1)??p?.filesTouched.at(-1),syncHealth:d,opencode:i?{state:i.state,reason:i.reason,timestamp:i.timestamp,error:i.error}:void 0}}function We(){return process.argv.includes("--json")}function cr(r){let e=process.stdout.isTTY===!0&&process.env.TERM!=="dumb"&&process.env.NO_COLOR===void 0,t=(l,ne)=>e?`\x1B[${l}m${ne}\x1B[0m`:ne,n=l=>t("38;5;82",l),o=l=>t("38;5;51",l),s=l=>t("38;5;214",l),i=l=>t("38;5;196",l),a=l=>t("38;5;255",l),c=l=>t("2",l),d=l=>t("1",l),p=c("\u2502"),u=c("\u251C");if(console.log(""),console.log(`${o("\u25C7")} ${d(a("ToolNet Memory Doctor"))}`),console.log(""),r.project&&console.log(`${n("\u25C6")} Project ${a(r.project)}`),console.log(p),r.storage){let l=typeof r.storage.provider=="string"?` \u2014 ${r.storage.provider}`:"";r.storage.ok?console.log(`${u} ${n("\u25C6")} Storage${l}`):console.log(`${u} ${i("\u2717")} Storage${l}`)}if((r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(p),console.log(`${o("\u25C7")} ${a("Project data")}`),r.memory!==void 0&&console.log(`${u} ${c("Memories")} ${a(String(r.memory))}`),r.graphSymbols!==void 0&&console.log(`${u} ${c("Graph symbols")} ${a(String(r.graphSymbols))}`),r.graphEdges!==void 0&&console.log(`${u} ${c("Graph edges")} ${a(String(r.graphEdges))}`),r.memoryVectors!==void 0&&console.log(`${u} ${c("Memory vectors")} ${a(String(r.memoryVectors))}`),r.codeChunks!==void 0&&console.log(`${u} ${c("Code chunks")} ${a(String(r.codeChunks))}`),r.codeVectors!==void 0&&console.log(`${u} ${c("Code vectors")} ${a(String(r.codeVectors))}`),r.snapshots!==void 0&&console.log(`${u} ${c("Snapshots")} ${a(String(r.snapshots))}`)),r.capture){console.log(p),console.log(`${o("\u25C7")} ${a("Session continuity")}`),console.log(`${u} ${c("Agents")} ${a(r.capture.agents.length?r.capture.agents.join(", "):"none")}`),r.capture.latestAgent&&console.log(`${u} ${c("Latest agent")} ${a(String(r.capture.latestAgent))}`),r.capture.currentTask&&console.log(`${u} ${c("Current task")} ${a(r.capture.currentTask)}`),r.capture.currentFile&&console.log(`${u} ${c("Current file")} ${a(r.capture.currentFile)}`),r.capture.lastCaptureAt&&console.log(`${u} ${c("Last capture")} ${a(r.capture.lastCaptureAt)}`),r.capture.lastFlushAt&&console.log(`${u} ${c("Last flush")} ${a(r.capture.lastFlushAt)}`),console.log(`${u} ${c("Pending WAL")} ${a(String(r.capture.pendingWal))}`);let l=r.capture.syncHealth==="healthy"?n(r.capture.syncHealth):r.capture.syncHealth==="degraded"?i(r.capture.syncHealth):s(r.capture.syncHealth);console.log(`${u} ${c("Sync health")} ${l}`)}let m=r.config?.errors??[];if(m.length>0){console.log(p),console.log(`${i("\u2717")} ${a("Configuration required")}`);for(let l of m)console.log(`${u} ${i("\u2022")} ${l}`)}let H=[...r.config?.warnings??[],...r.warnings??[]],k=[...new Set(H)];if(k.length>0){console.log(p),console.log(`${s("\u25C7")} ${a("Warnings")}`);for(let l of k)console.log(`${u} ${s("!")} ${l}`)}console.log(p),r.ok?console.log(`${n("\u2514 \u25C6")} ${d(a("ToolNet Memory is ready"))}`):(console.log(`${i("\u2514 \u2717")} ${d(a("ToolNet Memory requires attention"))}`),m.length>0&&console.log(c(" Run: toolnet-memory setup"))),console.log("")}function ze(r){We()?console.log(JSON.stringify(r,null,2)):cr(r)}async function ur(){let r=Ne();if(!r.ok){let l={ok:!1,config:r,warnings:r.warnings};ze(l),process.exitCode=1;return}let e=oe(),t=new O().detect(),n=Te(Pe({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new z(n,t.id,t.name,t.remote??t.name),s=await new B(n).run(),i=await new D(o).load(t.id),a=await new F(o).load(t.id),c=await new L(o).load(t.id),d=await new V(o).load(t.id),p=await new Y(o).load(t.id),u=await new W(o).list(t.id),m=Ye(t),H=m.syncHealth==="degraded"?[`Session capture degraded${m.opencode?.error?`: ${m.opencode.error}`:""}`]:[],k={ok:s.ok&&m.ok,project:t.name,storage:s.storage,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:c?.records.length??0,codeChunks:d?.chunks.length??0,codeVectors:p?.records.length??0,snapshots:u.length,capture:m,warnings:[...r.warnings,...H]};ze(k),process.exitCode=k.ok?0:1}ur().catch(r=>{let e=r instanceof Error?r.message:String(r);We()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
|