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.
Files changed (45) hide show
  1. package/.env.example +74 -0
  2. package/.release-target +1 -1
  3. package/README.md +157 -7
  4. package/bin/toolnet-memory +12 -0
  5. package/bundle/agy-hook.js +59 -59
  6. package/bundle/agy.js +58 -58
  7. package/bundle/api.js +15 -15
  8. package/bundle/audit.js +2 -0
  9. package/bundle/background-refresh.js +7 -7
  10. package/bundle/code-capabilities.js +2 -0
  11. package/bundle/codex.js +63 -63
  12. package/bundle/context-runtime.js +41 -41
  13. package/bundle/context.js +15 -15
  14. package/bundle/copilot-hook.js +73 -73
  15. package/bundle/cursor-hook.js +73 -73
  16. package/bundle/docker-healthcheck.js +3 -0
  17. package/bundle/doctor.js +4 -4
  18. package/bundle/full-index.js +20 -19
  19. package/bundle/gc.js +5 -3
  20. package/bundle/graph-cli.js +1 -1
  21. package/bundle/graph-index.js +5 -4
  22. package/bundle/graph-ui.js +4 -3
  23. package/bundle/grok-hook.js +52 -52
  24. package/bundle/handoff-refresh.js +2 -2
  25. package/bundle/help-cli.js +4 -4
  26. package/bundle/impact.js +5 -4
  27. package/bundle/incremental.js +5 -5
  28. package/bundle/init.js +35 -35
  29. package/bundle/kiro-hook.js +74 -74
  30. package/bundle/learner.js +8 -6
  31. package/bundle/mcp.js +19 -17
  32. package/bundle/memory-agent.js +4 -4
  33. package/bundle/memory-query.js +3 -3
  34. package/bundle/opencode.js +73 -73
  35. package/bundle/project-manual.js +7 -7
  36. package/bundle/public/index.html +1089 -2306
  37. package/bundle/runtime.js +16 -13
  38. package/bundle/semantic.js +6 -5
  39. package/bundle/service.js +11 -6
  40. package/bundle/snapshot.js +6 -4
  41. package/bundle/status-cli.js +4 -4
  42. package/bundle/toolnet-cli.js +49 -49
  43. package/bundle/work-continuity.js +7 -7
  44. package/package.json +26 -2
  45. package/release-manifest.json +57 -1
@@ -0,0 +1,2 @@
1
+ import{createHash as W}from"node:crypto";import{existsSync as A,mkdirSync as tt,readFileSync as et,renameSync as nt,writeFileSync as rt}from"node:fs";import{basename as ot,dirname as w,join as m,parse as V,resolve as d}from"node:path";import{createHash as O}from"node:crypto";import{spawnSync as q}from"node:child_process";var g="git-remote-v1",K=new Set(["github.com","gitlab.com","bitbucket.org"]);function N(n,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(r=>!r||r==="."||r==="..")?null:(K.has(n)&&(t=t.toLowerCase()),t)}function Y(n){let e;try{e=new URL(n)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let r=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!r?`${t}:${e.port}`:t,i=N(t,e.pathname);return i?`${o}/${i}`:null}function B(n){let e=n.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let r=N(t,e[2]??"");return r?`${t}/${r}`:null}function T(n){let e=n.trim();return e?e.includes("://")?Y(e):B(e):null}function X(n){return O("sha256").update(`${g}:${n}`).digest("hex")}function v(n){return O("sha256").update(`toolnet-project:${g}:${n}`).digest("hex").slice(0,16)}function Q(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function x(n,e){let t=q("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function M(n,e){let t=Q(n);return t?{scheme:g,canonicalRemote:n,fingerprint:X(n),repositoryName:t,source:e}:null}function D(n){let e=x(n,["remote","get-url","origin"]);if(e){let o=T(e);if(o)return M(o,"origin")}let t=x(n,["remote"]);if(!t)return null;let r=new Set;for(let o of t.split(/\r?\n/u).map(i=>i.trim()).filter(Boolean)){let i=x(n,["remote","get-url",o]);if(!i)continue;let s=T(i);s&&r.add(s)}return r.size!==1?null:M([...r][0],"unique-remote")}var z=".toolnet",it="project.json";function st(n){return W("sha256").update(n).digest("hex").slice(0,16)}function l(n){return m(n,z,it)}function C(n){return A(l(n))}function L(n,e){let t=d(n),r=V(t).root;for(;;){if(C(t))return t;if(t===r||e&&t===d(e))break;let o=w(t);if(o===t)break;t=o}return null}function b(n){let e=d(n),t=V(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(i=>A(m(e,i))))return e;if(e===t)break;let o=w(e);if(o===e)break;e=o}return d(n)}function h(n){let e;try{e=JSON.parse(et(n,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${n}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);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:w(w(n)),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 y(n,e){let t=m(n,z);tt(t,{recursive:!0});let r=l(n),o=`${r}.tmp-${process.pid}`;rt(o,JSON.stringify(e,null,2)+`
2
+ `,{encoding:"utf8",mode:384}),nt(o,r)}function u(n,e){return{id:n.id,name:n.name,remote:n.remote,rootPath:e,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}function _(n){return{version:1,scheme:g,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function ct(n){let e=n.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var S=class{adopt(e,t){let r=b(d(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(C(r)){let c=h(l(r));if(c.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${c.id}`,`requested=${t.id}`].join(" "));return u(c,r)}let o=new Date().toISOString(),i={...t.metadata};t.gitIdentity&&(i.toolnetIdentity=_(t.gitIdentity));let s={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:r,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(i).length?i:void 0};return y(r,s),u(s,r)}recordGitIdentity(e,t,r={}){let o=this.requireExisting(e),i=l(o.rootPath),s=h(i),c=ct(s);if(c&&c!==t.fingerprint&&!r.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${c}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let a=s.metadata?.toolnetIdentity;return a&&typeof a=="object"&&!Array.isArray(a)&&a.fingerprint===t.fingerprint||(s.metadata={...s.metadata,toolnetIdentity:_(t)},s.updatedAt=new Date().toISOString(),y(o.rootPath,s)),u(s,o.rootPath)}findExisting(e=process.cwd()){let t=d(e),r=b(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(a=>A(m(r,a))),s=L(t,i?r:void 0);if(!s)return null;let c=h(l(s));return u(c,s)}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=d(e),r=b(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(k=>A(m(r,k))),s=L(t,i?r:void 0);if(s){let k=l(s),p=h(k);return p.rootPath!==s&&(p.rootPath=s,p.updatedAt=new Date().toISOString(),y(s,p)),u(p,s)}let c=new Date().toISOString(),a=ot(r),f=D(r),j={version:1,id:f?v(f.canonicalRemote):st(r),name:a,remote:f?.repositoryName??a,rootPath:r,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0,metadata:f?{toolnetIdentity:_(f)}:void 0};return y(r,j),u(j,r)}};import{appendFileSync as zt,closeSync as Ct,existsSync as gt,mkdirSync as $t,openSync as Ht,readFileSync as mt,statSync as Gt,unlinkSync as Ft,writeFileSync as Jt}from"node:fs";import{createHash as ht,randomUUID as Ut}from"node:crypto";import{dirname as Kt,join as F}from"node:path";var at=[{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"}],ut=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function $(n){return n.normalize("NFKC").trim().toLowerCase()}function dt(n){if(n.length===0)return 0;let e=new Map;for(let r of n)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let o=r/n.length;t-=o*Math.log2(o)}return t}function lt(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function ft(n,e,t){let r=n.slice(Math.max(0,e-48),e),o=n.slice(t,Math.min(n.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${o}`)}function pt(n,e){return n.start<e.end&&e.start<n.end}function H(n){return n.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 r=$(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let i of at){let s=new RegExp(i.regex.source,i.regex.flags);for(let c of e.matchAll(s))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:i.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:i.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=H(t),o=[];for(let i of r)o.some(s=>pt(s,i))||o.push(i);return H(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=$(e);return ut.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(r)){if(o.index===void 0||!o[0])continue;let i=o[0];this.allowed(i)||lt(i)||!/[A-Za-z]/u.test(i)||!/[0-9]/u.test(i)||ft(e,o.index,o.index+i.length)&&(dt(i)<3.7||t.push({type:"high_entropy_secret",value:i,start:o.index,end:o.index+i.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 r=e,o=[...t].sort((s,c)=>c.start-s.start),i=new Set;for(let s of o)i.add(s.type),r=r.slice(0,s.start)+`[REDACTED:${s.type}]`+r.slice(s.end);return{text:r,redacted:t.length,secretTypes:[...i].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[r,o]of Object.entries(e)){let i=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(i.includes("password")||i.includes("passwd")||i==="pwd"||i.includes("secret")||i.includes("token")||i.includes("cookie")||i.includes("authorization")||i.includes("apikey")||i.includes("accesskey")||i.includes("privatekey")||i.includes("clientsecret")||i.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(o)}return t}return e}};var vt=new I;var G="0".repeat(64);function yt(n){return F(n.rootPath,".toolnet","audit")}function P(n){return F(yt(n),"events.jsonl")}function R(n){if(Array.isArray(n))return n.map(R);if(!n||typeof n!="object")return n;let e=n;return Object.fromEntries(Object.keys(e).sort().map(t=>[t,R(e[t])]))}function At(n){return JSON.stringify(R(n))}function wt(n){return ht("sha256").update(At(n),"utf8").digest("hex")}function J(n){let e=P(n);if(!gt(e))return[];let t=mt(e,"utf8"),r=[];for(let o of t.split(/\r?\n/u)){let i=o.trim();i&&r.push(JSON.parse(i))}return r}function Z(n){let e;try{e=J(n)}catch(o){return{valid:!1,records:0,lastHash:G,firstInvalidLine:1,error:o instanceof Error?o.message:String(o)}}let t=G,r=1;for(let o=0;o<e.length;o+=1){let i=e[o];if(i.sequence!==r)return{valid:!1,records:e.length,lastHash:t,firstInvalidLine:o+1,error:"AUDIT_SEQUENCE_INVALID"};if(i.previousHash!==t)return{valid:!1,records:e.length,lastHash:t,firstInvalidLine:o+1,error:"AUDIT_PREVIOUS_HASH_INVALID"};let{hash:s,...c}=i,a=wt(c);if(s!==a)return{valid:!1,records:e.length,lastHash:t,firstInvalidLine:o+1,error:"AUDIT_HASH_INVALID"};t=s,r+=1}return{valid:!0,records:e.length,lastHash:t}}function U(n,e=50){let t=Math.max(1,Math.min(1e3,Math.trunc(e)));return J(n).slice(-t)}function St(n){let e=n.find(o=>o.startsWith("--limit=")),t=e?e.slice(8):n[n.indexOf("--limit")+1];if(!t)return 50;let r=Number(t);if(!Number.isSafeInteger(r)||r<1)throw new Error(`Invalid --limit: ${t}`);return Math.min(r,1e3)}async function Et(){let n=process.argv.slice(2),e=n[0]??"list",t=new S().requireExisting(process.cwd());if(e==="verify"){let i=Z(t);console.log(JSON.stringify({file:P(t),...i},null,2)),i.valid||(process.exitCode=1);return}let r=St(n),o=U(t,r);if(n.includes("--json")){console.log(JSON.stringify(o,null,2));return}console.log(`Audit: ${P(t)}`),console.log(`Events: ${o.length}`);for(let i of o)console.log([i.at,i.action,i.outcome,i.actor.kind,i.actor.id??""].filter(Boolean).join(" | "))}Et().catch(n=>{console.error(n instanceof Error?n.message:String(n)),process.exitCode=1});
@@ -1,7 +1,7 @@
1
- import{existsSync as Ge,readFileSync as Ue}from"node:fs";import{homedir as Ye}from"node:os";import{join as qe}from"node:path";function Ze(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??qe(Ye(),".config","toolnet-memory",".env");if(!Ge(r))return;let e=Ue(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]=Ze(n.slice(o+1)))}}Qe();function R(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function A(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function ce(){return{memory:{autoCapture:R(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:R(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:R(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:R(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:A(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:A(process.env.MEMORY_RERANK_TOP,10),finalContext:A(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:A(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:R(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:A(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as st}from"node:crypto";import{existsSync as N,mkdirSync as it,readFileSync as at,renameSync as ct,writeFileSync as ut}from"node:fs";import{basename as dt,dirname as K,join as P,parse as ye,resolve as w}from"node:path";import{createHash as le}from"node:crypto";import{spawnSync as Xe}from"node:child_process";var I="git-remote-v1",et=new Set(["github.com","gitlab.com","bitbucket.org"]);function pe(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:(et.has(r)&&(t=t.toLowerCase()),t)}function tt(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=pe(t,e.pathname);return s?`${o}/${s}`:null}function rt(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=pe(t,e[2]??"");return n?`${t}/${n}`:null}function ue(r){let e=r.trim();return e?e.includes("://")?tt(e):rt(e):null}function nt(r){return le("sha256").update(`${I}:${r}`).digest("hex")}function me(r){return le("sha256").update(`toolnet-project:${I}:${r}`).digest("hex").slice(0,16)}function ot(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function U(r,e){let t=Xe("git",["-C",r,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function de(r,e){let t=ot(r);return t?{scheme:I,canonicalRemote:r,fingerprint:nt(r),repositoryName:t,source:e}:null}function fe(r){let e=U(r,["remote","get-url","origin"]);if(e){let o=ue(e);if(o)return de(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 a=ue(s);a&&n.add(a)}return n.size!==1?null:de([...n][0],"unique-remote")}var he=".toolnet",lt="project.json";function pt(r){return st("sha256").update(r).digest("hex").slice(0,16)}function v(r){return P(r,he,lt)}function Se(r){return N(v(r))}function ge(r,e){let t=w(r),n=ye(t).root;for(;;){if(Se(t))return t;if(t===n||e&&t===w(e))break;let o=K(t);if(o===t)break;t=o}return null}function Y(r){let e=w(r),t=ye(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>N(P(e,s))))return e;if(e===t)break;let o=K(e);if(o===e)break;e=o}return w(r)}function O(r){let e;try{e=JSON.parse(at(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:K(K(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 _(r,e){let t=P(r,he);it(t,{recursive:!0});let n=v(r),o=`${n}.tmp-${process.pid}`;ut(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ct(o,n)}function k(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 q(r){return{version:1,scheme:I,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function mt(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 D=class{adopt(e,t){let n=Y(w(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(Se(n)){let c=O(v(n));if(c.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${c.id}`,`requested=${t.id}`].join(" "));return k(c,n)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=q(t.gitIdentity));let a={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 _(n,a),k(a,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),s=v(o.rootPath),a=O(s),c=mt(a);if(c&&c!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${c}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let d=a.metadata?.toolnetIdentity;return d&&typeof d=="object"&&!Array.isArray(d)&&d.fingerprint===t.fingerprint||(a.metadata={...a.metadata,toolnetIdentity:q(t)},a.updatedAt=new Date().toISOString(),_(o.rootPath,a)),k(a,o.rootPath)}findExisting(e=process.cwd()){let t=w(e),n=Y(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>N(P(n,d))),a=ge(t,s?n:void 0);if(!a)return null;let c=O(v(a));return k(c,a)}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=w(e),n=Y(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(g=>N(P(n,g))),a=ge(t,s?n:void 0);if(a){let g=v(a),u=O(g);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),_(a,u)),k(u,a)}let c=new Date().toISOString(),d=dt(n),l=fe(n),m={version:1,id:l?me(l.canonicalRemote):pt(n),name:d,remote:l?.repositoryName??d,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0,metadata:l?{toolnetIdentity:q(l)}:void 0};return _(n,m),k(m,n)}};var ft=[{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"}],gt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function be(r){return r.normalize("NFKC").trim().toLowerCase()}function yt(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 ht(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function St(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 bt(r,e){return r.start<e.end&&e.start<r.end}function ke(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var $=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=be(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of ft){let a=new RegExp(s.regex.source,s.regex.flags);for(let c of e.matchAll(a))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:s.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ke(t),o=[];for(let s of n)o.some(a=>bt(a,s))||o.push(s);return ke(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=be(e);return gt.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)||ht(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||St(e,o.index,o.index+s.length)&&(yt(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var z=class{scanner;constructor(e={}){this.scanner=new $(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((a,c)=>c.start-a.start),s=new Set;for(let a of o)s.add(a.type),n=n.slice(0,a.start)+`[REDACTED:${a.type}]`+n.slice(a.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 Dr=new z;import{homedir as Vt}from"node:os";import{join as Ft}from"node:path";import{DeleteObjectCommand as kt,GetObjectCommand as wt,HeadObjectCommand as xt,ListObjectsV2Command as vt,PutObjectCommand as Mt,S3Client as jt}from"@aws-sdk/client-s3";import{getSignedUrl as Rt}from"@aws-sdk/s3-request-presigner";var L=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new jt({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 Mt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Rt(this.client,new wt({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 xt({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 vt({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 we,mkdir as At,readFile as It,readdir as Pt,rm as Ct,stat as xe,writeFile as Tt}from"node:fs/promises";import{dirname as Et,join as Ot,relative as ve,resolve as _t}from"node:path";var C=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(Et(n),{recursive:!0}),await Tt(n,t)}async get(e){try{return await It(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 we(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 we(t)}catch{return n}let o=async a=>{let c=await Pt(a,{withFileTypes:!0});for(let d of c){let l=Ot(a,d.name);if(d.isDirectory()){await o(l);continue}let m=await xe(l);n.push({key:ve(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},s=await xe(t);return s.isDirectory()?await o(t):n.push({key:ve(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as Nt,GetObjectCommand as Kt,HeadObjectCommand as Dt,ListObjectsV2Command as $t,PutObjectCommand as zt,S3Client as Lt}from"@aws-sdk/client-s3";import{getSignedUrl as Ht}from"@aws-sdk/s3-request-presigner";var T=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 zt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Ht(this.client,new Kt({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 Dt({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 Nt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new $t({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 Z(r,e){return console.warn(e),new C(r)}function Me(r){let e=r.localRoot??Ft(Vt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new T({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Z(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 T({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Z(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 L({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Z(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new C(e)}var H=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")}};function Bt(r){return new Promise(e=>setTimeout(e,r))}async function je(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(s=c,a>=t)break;let d=Math.min(o,n*2**(a-1)),l=Math.floor(Math.random()*Math.max(1,d*.2));await Bt(d+l)}throw s}var Wt=new Set(["put","get","getText","delete","list"]);function Re(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:Wt.has(n)?(...s)=>je(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function Ae(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 Ie(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 V=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=Ae(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 a;try{a=JSON.parse(o)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(n=a.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=Ie(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))}};import{join as Te}from"node:path";import{mkdirSync as Zt}from"node:fs";import{createHash as Jt}from"node:crypto";import{dirname as Gt}from"node:path";import{mkdirSync as Ut,readFileSync as Po,renameSync as Yt,writeFileSync as qt}from"node:fs";function Pe(r){return Jt("sha256").update(r).digest("hex")}function Ce(r,e){Ut(Gt(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;qt(t,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),Yt(t,r)}function Oe(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function y(r,e=20){let t=[],n=new Set;for(let o of r.slice().reverse()){let s=Oe(o);if(!(!s||n.has(s))&&(n.add(s),t.push(o),t.length>=e))break}return t.reverse()}function Qt(r,e=20){let t=new Map;for(let n of r){let o=`${n.kind}|${Oe(n.command)}`;t.delete(o),t.set(o,n)}return Array.from(t.values()).slice(-e)}function Xt(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function Ee(r,e){let t=e.status??r?.status??"pending",n=t;r&&(r.status==="completed"&&t!=="completed"?n="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(n=r.status));let o=r&&Xt(e)?r.title:e.text;return{id:r?.id??Pe(e.key).slice(0,24),title:o,status:n,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function _e(r,e){let t=`projects/${r.id}/work/observations/`,n=await e.list(t),o=[];for(let s of n.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(s.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&o.push(c)}catch{}}return o}async function er(r,e){let n=(await _e(r,e)).flatMap(i=>i.observations).sort((i,f)=>{let ie=i.occurredAt.localeCompare(f.occurredAt);if(ie!==0)return ie;let ae=i.sequence-f.sequence;return ae!==0?ae:i.id.localeCompare(f.id)}),o=new Map,s=new Map,a,c,d,l,m,g=[],u=[],p=[],S=[],M=[],j=new Map,X=[],ee=[],te=[],re=[],ne=[],oe=[];for(let i of n)switch(i.kind){case"request":a=i.text;break;case"activity":c=i.text;break;case"goal":d=i.text;break;case"plan":l=i.text;break;case"phase":o.set(i.key,Ee(o.get(i.key),i));break;case"task":s.set(i.key,Ee(s.get(i.key),i));break;case"decision":g.push(i.text);break;case"blocker":u.push(i.text);break;case"warning":p.push(i.text);break;case"next_action":S.push(i.text);break;case"file":{M.push(i.text);let f=i.fileAction??"active";j.delete(i.text),j.set(i.text,f),f==="modified"?X.push(i.text):f==="created"?ee.push(i.text):f==="deleted"&&te.push(i.text);break}case"command":re.push(i.text);break;case"test":ne.push(i.text),i.checkKind&&oe.push({kind:i.checkKind,command:i.text,status:i.checkStatus??"unknown",updatedAt:i.occurredAt,agent:i.agent,nativeSessionId:i.nativeSessionId});break;case"session":m={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let b=Array.from(o.values()).sort((i,f)=>(i.order??Number.MAX_SAFE_INTEGER)-(f.order??Number.MAX_SAFE_INTEGER)),h=Array.from(s.values()).sort((i,f)=>(i.order??Number.MAX_SAFE_INTEGER)-(f.order??Number.MAX_SAFE_INTEGER)),J=b.find(i=>i.status==="in_progress")??b.find(i=>i.status==="blocked")??b.find(i=>i.status==="pending"),E=h.find(i=>i.status==="in_progress")??h.find(i=>i.status==="blocked")??h.find(i=>i.status==="pending"),We=y([...S,...E?[E.title]:[],...!E&&J?[J.title]:[],...h.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Je=y([...u,...b.filter(i=>i.status==="blocked").map(i=>i.title),...h.filter(i=>i.status==="blocked").map(i=>i.title)],20),G={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:d,plan:l,phases:b,tasks:h,decisions:y(g,20),blockers:Je,warnings:y(p,20),nextActions:We,filesTouched:y(M,30),activeFiles:Array.from(j.entries()).filter(([,i])=>i!=="deleted").map(([i])=>i).slice(-5),modifiedFiles:y(X,30),createdFiles:y(ee,30),deletedFiles:y(te,30),commands:y(re,20),tests:y(ne,20),checks:Qt(oe,20),currentPhase:J,currentTask:E,progress:{phasesTotal:b.length,phasesCompleted:b.filter(i=>i.status==="completed").length,tasksTotal:h.length,tasksCompleted:h.filter(i=>i.status==="completed").length,blocked:b.filter(i=>i.status==="blocked").length+h.filter(i=>i.status==="blocked").length},lastSession:m,updatedAt:n.length?n[n.length-1].occurredAt:new Date().toISOString()},se=Te(r.rootPath,".toolnet","work");return Zt(se,{recursive:!0}),Ce(Te(se,"current.json"),G),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(G,null,2)+`
6
- `,"application/json"),G}async function Ne(r,e){if((await _e(r,e)).length>0)return er(r,e);let n=await e.getText(`projects/${r.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}import{createHash as ar}from"node:crypto";import{hostname as cr}from"node:os";import{createHash as tr,randomUUID as rr}from"node:crypto";function x(r,e){let t=r.trim();if(!t)throw new Error(`${e} is required`);return t}function F(r,e){return encodeURIComponent(x(r,e))}function nr(r){let e=JSON.stringify(r);if(e===void 0)throw new Error("Multi-host operation payload must be JSON serializable");return e}function De(r){return tr("sha256").update(r).digest("hex")}function $e(r){return De(nr(r))}function ze(r){return Number.isFinite(Date.parse(r))}function or(r){return De(JSON.stringify({version:r.version,operationId:r.operationId,projectId:r.projectId,scope:r.scope,hostId:r.hostId,occurredAt:r.occurredAt,payloadSha256:r.payloadSha256,payload:r.payload}))}function Le(r){let e=x(r.projectId,"projectId"),t=x(r.scope,"scope"),n=x(r.hostId,"hostId"),o=x(r.operationId??rr(),"operationId"),s=r.occurredAt??new Date().toISOString();if(!ze(s))throw new Error(`Invalid operation timestamp: ${s}`);return{version:1,operationId:o,projectId:e,scope:t,hostId:n,occurredAt:s,payloadSha256:$e(r.payload),payload:r.payload}}function He(r,e){let t=["projects",F(r,"projectId"),"operations"];return e?`${[...t,F(e,"scope")].join("/")}/`:`${t.join("/")}/`}function sr(r){return[He(r.projectId,r.scope).replace(/\/$/,""),F(r.hostId,"hostId"),`${F(r.operationId,"operationId")}-${r.payloadSha256}.json`].join("/")}async function Ve(r,e){let t=sr(e);return await r.put(t,`${JSON.stringify(e,null,2)}
7
- `,"application/json"),t}function ir(r){let e;try{e=JSON.parse(r)}catch{return null}return e.version!==1||typeof e.operationId!="string"||typeof e.projectId!="string"||typeof e.scope!="string"||typeof e.hostId!="string"||typeof e.occurredAt!="string"||!ze(e.occurredAt)||typeof e.payloadSha256!="string"||$e(e.payload)!==e.payloadSha256?null:e}function Ke(r,e){let t=r.occurredAt.localeCompare(e.occurredAt);if(t!==0)return t;let n=r.hostId.localeCompare(e.hostId);if(n!==0)return n;let o=r.operationId.localeCompare(e.operationId);return o!==0?o:r.payloadSha256.localeCompare(e.payloadSha256)}async function Fe(r,e,t){let n=x(e,"projectId"),o=x(t,"scope"),s=He(n,o),a=await r.list(s),c=[],d=[];for(let u of a){let p=await r.getText(u.key);if(!p){c.push(u.key);continue}let S=ir(p);if(!S){c.push(u.key);continue}if(S.projectId!==n){c.push(u.key);continue}if(S.scope!==o){c.push(u.key);continue}d.push(S)}let l=new Map;for(let u of d){let p=l.get(u.operationId);if(!p){l.set(u.operationId,[u]);continue}p.push(u)}let m=[],g=[];for(let[u,p]of l){if(new Set(p.map(j=>or(j))).size>1){g.push({operationId:u,variants:[...p].sort(Ke)});continue}let M=p[0];M&&m.push(M)}return m.sort(Ke),g.sort((u,p)=>u.operationId.localeCompare(p.operationId)),c.sort(),{operations:m,conflicts:g,invalidKeys:c}}function ur(r){let t=(r??process.env.TOOLNET_HOST_ID??cr()).trim();return t||`pid-${process.pid}`}function dr(r){let e=t=>{if(t===null||typeof t!="object")return t;if(Array.isArray(t))return t.map(o=>e(o));let n=t;return Object.fromEntries(Object.keys(n).sort().map(o=>[o,e(n[o])]))};return JSON.stringify(e(r))}function B(r){return ar("sha256").update(dr(r)).digest("hex")}function lr(r,e){let t=B(r).slice(0,12),n=B(e);return["memory",t,n].join("-")}function pr(r,e){let t=r.updatedAt.localeCompare(e.updatedAt);if(t!==0)return t;let n=r.createdAt.localeCompare(e.createdAt);return n!==0?n:B(r).localeCompare(B(e))}function mr(r,e){return pr(r,e)>=0?r:e}function Q(r,e){let t=new Map;for(let n of r)t.set(n.id,n);for(let n of e){if(n.payload.kind!=="upsert")continue;let o=n.payload.memory,s=t.get(o.id);if(!s){t.set(o.id,o);continue}t.set(o.id,mr(s,o))}return[...t.values()].sort((n,o)=>n.id.localeCompare(o.id))}var W=class{constructor(e,t={}){this.storage=e;this.legacy=new H(e),this.hostId=ur(t.hostId)}storage;legacy;hostId;diagnostics={operationCount:0,conflicts:0,invalidKeys:0};getDiagnostics(){return{...this.diagnostics}}async operations(e){let t=await Fe(this.storage,e,"memory");return this.diagnostics={operationCount:t.operations.length,conflicts:t.conflicts.length,invalidKeys:t.invalidKeys.length},t.operations}async load(e){let t=await this.legacy.load(e),n=await this.operations(e);return Q(t,n)}async appendMemory(e,t){let n=Le({projectId:e,scope:"memory",hostId:this.hostId,operationId:lr(this.hostId,t),occurredAt:t.updatedAt,payload:{kind:"upsert",memory:t}});await Ve(this.storage,n)}async refreshProjection(e){let t=await this.legacy.load(e),n=await this.operations(e),o=Q(t,n);return await this.legacy.save(e,o),o}async save(e,t){let n=[...t].sort((a,c)=>a.id.localeCompare(c.id));for(let a of n)await this.appendMemory(e,a);let o=await this.operations(e),s=Q(t,o);await this.legacy.save(e,s)}};async function Be(r,e){let t=new Date().toISOString(),o=await new W(e).refreshProjection(r.id),s=await Ne(r,e);return{startedAt:t,finishedAt:new Date().toISOString(),memories:o.length,workAvailable:s!==null}}function fr(r,e){let t=r.indexOf(e);if(!(t<0))return r[t+1]}function gr(r){return{projectPath:fr(r,"--project"),json:r.includes("--json"),quiet:r.includes("--quiet")}}async function yr(r){let e=ce(),t=Re(Me({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new V(t,r.id,r.name,r.remote??r.name)}async function hr(){let r=gr(process.argv.slice(2)),e=r.projectPath??process.cwd(),t=new D().detect(e);if(!t){r.quiet||console.error(`ToolNet project not found: ${e}`),process.exitCode=2;return}let n;try{n=await yr(t)}catch(o){r.quiet||console.error(o instanceof Error?o.message:String(o)),process.exitCode=3;return}try{let o=await Be(t,n);if(r.quiet)return;if(r.json){console.log(JSON.stringify(o));return}console.log(["ToolNet Memory refreshed",`memory=${o.memories}`,`work=${o.workAvailable?"yes":"no"}`].join(" "))}catch(o){r.quiet||console.error(o instanceof Error?o.message:String(o)),process.exitCode=4}}hr().then(()=>{process.exit(process.exitCode??0)});
1
+ import{existsSync as mt,readFileSync as ft}from"node:fs";import{homedir as gt}from"node:os";import{join as yt}from"node:path";function ht(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 St(){let r=process.env.TOOLNET_GLOBAL_ENV??yt(gt(),".config","toolnet-memory",".env");if(!mt(r))return;let e=ft(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]=ht(n.slice(o+1)))}}St();function A(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function j(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function Se(){return{memory:{autoCapture:A(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:A(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:A(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:A(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:j(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:j(process.env.MEMORY_RERANK_TOP,10),finalContext:j(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:j(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:A(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:j(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Et}from"node:crypto";import{existsSync as H,mkdirSync as Mt,readFileSync as It,renameSync as At,writeFileSync as jt}from"node:fs";import{basename as Pt,dirname as z,join as T,parse as Me,resolve as k}from"node:path";import{createHash as xe}from"node:crypto";import{spawnSync as bt}from"node:child_process";var P="git-remote-v1",wt=new Set(["github.com","gitlab.com","bitbucket.org"]);function ke(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:(wt.has(r)&&(t=t.toLowerCase()),t)}function xt(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=ke(t,e.pathname);return s?`${o}/${s}`:null}function kt(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=ke(t,e[2]??"");return n?`${t}/${n}`:null}function be(r){let e=r.trim();return e?e.includes("://")?xt(e):kt(e):null}function vt(r){return xe("sha256").update(`${P}:${r}`).digest("hex")}function ve(r){return xe("sha256").update(`toolnet-project:${P}:${r}`).digest("hex").slice(0,16)}function Rt(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function X(r,e){let t=bt("git",["-C",r,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function we(r,e){let t=Rt(r);return t?{scheme:P,canonicalRemote:r,fingerprint:vt(r),repositoryName:t,source:e}:null}function Re(r){let e=X(r,["remote","get-url","origin"]);if(e){let o=be(e);if(o)return we(o,"origin")}let t=X(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=X(r,["remote","get-url",o]);if(!s)continue;let a=be(s);a&&n.add(a)}return n.size!==1?null:we([...n][0],"unique-remote")}var Ie=".toolnet",Tt="project.json";function Ot(r){return Et("sha256").update(r).digest("hex").slice(0,16)}function E(r){return T(r,Ie,Tt)}function Ae(r){return H(E(r))}function Ee(r,e){let t=k(r),n=Me(t).root;for(;;){if(Ae(t))return t;if(t===n||e&&t===k(e))break;let o=z(t);if(o===t)break;t=o}return null}function ee(r){let e=k(r),t=Me(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>H(T(e,s))))return e;if(e===t)break;let o=z(e);if(o===e)break;e=o}return k(r)}function $(r){let e;try{e=JSON.parse(It(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:z(z(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 L(r,e){let t=T(r,Ie);Mt(t,{recursive:!0});let n=E(r),o=`${n}.tmp-${process.pid}`;jt(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),At(o,n)}function x(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 te(r){return{version:1,scheme:P,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function Ct(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 B=class{adopt(e,t){let n=ee(k(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(Ae(n)){let c=$(E(n));if(c.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${c.id}`,`requested=${t.id}`].join(" "));return x(c,n)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=te(t.gitIdentity));let a={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 L(n,a),x(a,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),s=E(o.rootPath),a=$(s),c=Ct(a);if(c&&c!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${c}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let u=a.metadata?.toolnetIdentity;return u&&typeof u=="object"&&!Array.isArray(u)&&u.fingerprint===t.fingerprint||(a.metadata={...a.metadata,toolnetIdentity:te(t)},a.updatedAt=new Date().toISOString(),L(o.rootPath,a)),x(a,o.rootPath)}findExisting(e=process.cwd()){let t=k(e),n=ee(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>H(T(n,u))),a=Ee(t,s?n:void 0);if(!a)return null;let c=$(E(a));return x(c,a)}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=k(e),n=ee(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>H(T(n,m))),a=Ee(t,s?n:void 0);if(a){let m=E(a),l=$(m);return l.rootPath!==a&&(l.rootPath=a,l.updatedAt=new Date().toISOString(),L(a,l)),x(l,a)}let c=new Date().toISOString(),u=Pt(n),d=Re(n),f={version:1,id:d?ve(d.canonicalRemote):Ot(n),name:u,remote:d?.repositoryName??u,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0,metadata:d?{toolnetIdentity:te(d)}:void 0};return L(n,f),x(f,n)}};var _t=[{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"}],Nt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function je(r){return r.normalize("NFKC").trim().toLowerCase()}function Kt(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 Dt(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function $t(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 Lt(r,e){return r.start<e.end&&e.start<r.end}function Pe(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var V=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=je(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of _t){let a=new RegExp(s.regex.source,s.regex.flags);for(let c of e.matchAll(a))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:s.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=Pe(t),o=[];for(let s of n)o.some(a=>Lt(a,s))||o.push(s);return Pe(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=je(e);return Nt.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)||Dt(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||$t(e,o.index,o.index+s.length)&&(Kt(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var Y=class{scanner;constructor(e={}){this.scanner=new V(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((a,c)=>c.start-a.start),s=new Set;for(let a of o)s.add(a.type),n=n.slice(0,a.start)+`[REDACTED:${a.type}]`+n.slice(a.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 pn=new Y;import{homedir as yr}from"node:os";import{join as hr}from"node:path";import{DeleteObjectCommand as Ht,GetObjectCommand as zt,HeadObjectCommand as Bt,ListObjectsV2Command as Vt,PutObjectCommand as Yt,S3Client as Ft}from"@aws-sdk/client-s3";import{getSignedUrl as Ut}from"@aws-sdk/s3-request-presigner";var F=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ft({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 Yt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Ut(this.client,new zt({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 Bt({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 Ht({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Vt({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 Te,mkdir as Gt,readFile as Wt,readdir as Jt,rm as qt,stat as Oe,writeFile as Zt}from"node:fs/promises";import{dirname as Qt,join as Xt,relative as Ce,resolve as er}from"node:path";var O=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return er(this.root,t)}async put(e,t){let n=this.path(e);await Gt(Qt(n),{recursive:!0}),await Zt(n,t)}async get(e){try{return await Wt(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 Te(this.path(e)),!0}catch{return!1}}async delete(e){await qt(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await Te(t)}catch{return n}let o=async a=>{let c=await Jt(a,{withFileTypes:!0});for(let u of c){let d=Xt(a,u.name);if(u.isDirectory()){await o(d);continue}let f=await Oe(d);n.push({key:Ce(this.root,d),size:f.size,updatedAt:f.mtime.toISOString()})}},s=await Oe(t);return s.isDirectory()?await o(t):n.push({key:Ce(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as tr,GetObjectCommand as rr,HeadObjectCommand as nr,ListObjectsV2Command as or,PutObjectCommand as sr,S3Client as ir}from"@aws-sdk/client-s3";import{getSignedUrl as ar}from"@aws-sdk/s3-request-presigner";var C=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ir({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 sr({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await ar(this.client,new rr({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 nr({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 tr({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new or({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 cr,createDecipheriv as ur,createHash as dr,randomBytes as lr,timingSafeEqual as pr}from"node:crypto";import{readFileSync as mr}from"node:fs";var v=Buffer.from("TNMEME01","ascii"),Ne=1,_=8,N=12,re=16,Ke=v.length+1+_+N+re,fr="toolnet-memory:remote-encryption:v1:",De="aes-256-gcm",ne=32,p=class extends Error{constructor(t,n){super(n);this.code=t;this.name="RemoteEncryptionError"}code};function gr(r){return r?["1","true","yes","on","enabled"].includes(r.trim().toLowerCase()):!1}function oe(r=process.env){return gr(r.TOOLNET_REMOTE_ENCRYPTION)}function _e(r){let e=r.trim();if(!e)throw new p("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 p("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 p("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!==ne)throw new p("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH",`Remote encryption key must decode to exactly ${ne} bytes.`);return t}function $e(r=process.env){let e=r.TOOLNET_REMOTE_ENCRYPTION_KEY?.trim(),t=r.TOOLNET_REMOTE_ENCRYPTION_KEY_FILE?.trim();if(e&&t)throw new p("REMOTE_ENCRYPTION_KEY_AMBIGUOUS","Configure either TOOLNET_REMOTE_ENCRYPTION_KEY or TOOLNET_REMOTE_ENCRYPTION_KEY_FILE, not both.");if(e)return _e(e);if(t){let n;try{n=mr(t,"utf8")}catch(o){throw new p("REMOTE_ENCRYPTION_KEY_FILE_READ_FAILED",[`Unable to read remote encryption key file: ${t}.`,o instanceof Error?o.message:String(o)].join(" "))}return _e(n)}}function Le(r){return dr("sha256").update(r).digest().subarray(0,_)}function He(r){return Buffer.from(`${fr}${r}`,"utf8")}function se(r){return r.byteLength<v.length?!1:Buffer.from(r).subarray(0,v.length).equals(v)}function ze(r,e,t){if(t.byteLength!==ne)throw new p("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=lr(N),s=cr(De,t,o);s.setAAD(He(r));let a=Buffer.concat([s.update(n),s.final()]),c=s.getAuthTag(),u=Buffer.alloc(Ke),d=0;return v.copy(u,d),d+=v.length,u.writeUInt8(Ne,d),d+=1,Le(t).copy(u,d),d+=_,o.copy(u,d),d+=N,c.copy(u,d),Buffer.concat([u,a])}function Be(r,e,t){let n=Buffer.from(e);if(!se(n))throw new p("REMOTE_ENCRYPTION_ENVELOPE_REQUIRED","Payload is not a ToolNet encrypted remote object.");if(n.length<Ke)throw new p("REMOTE_ENCRYPTION_ENVELOPE_TRUNCATED","Encrypted remote payload is truncated.");let o=v.length,s=n.readUInt8(o);if(o+=1,s!==Ne)throw new p("REMOTE_ENCRYPTION_VERSION_UNSUPPORTED",`Unsupported remote encryption envelope version: ${s}.`);let a=n.subarray(o,o+_);o+=_;let c=Le(t);if(!pr(a,c))throw new p("REMOTE_ENCRYPTION_KEY_MISMATCH","Configured remote encryption key does not match this encrypted object.");let u=n.subarray(o,o+N);o+=N;let d=n.subarray(o,o+re);o+=re;let f=n.subarray(o),m=ur(De,t,u);m.setAAD(He(r)),m.setAuthTag(d);try{return Buffer.concat([m.update(f),m.final()])}catch{throw new p("REMOTE_ENCRYPTION_AUTH_FAILED","Encrypted remote object failed AES-GCM authentication.")}}var ie=class{constructor(e,t){this.inner=e;this.options=t;if(this.name=e.name,t.enabled&&!t.key)throw new p("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 p("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote encryption key is unavailable.");let s=ze(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(!se(t))return t;if(!this.options.enabled)throw new p("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 p("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote object is encrypted but no decryption key is configured.");return Be(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 Ve(r,e=process.env){if(r.name==="local")return oe(e)&&console.warn("[storage] Remote encryption requested but active storage provider is local; local data remains unchanged."),r;let t=oe(e),n=t?$e(e):void 0;return new ie(r,{enabled:t,key:n})}function K(r){return Ve(r)}function ae(r,e){return console.warn(e),K(new O(r))}function Ye(r){let e=r.localRoot??hr(yr(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?K(new C({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):ae(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?K(new C({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):ae(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?K(new F({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):ae(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return K(new O(e))}var U=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")}};function Sr(r){return new Promise(e=>setTimeout(e,r))}async function Fe(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(s=c,a>=t)break;let u=Math.min(o,n*2**(a-1)),d=Math.floor(Math.random()*Math.max(1,u*.2));await Sr(u+d)}throw s}var br=new Set(["put","get","getText","delete","list"]);function Ue(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:br.has(n)?(...s)=>Fe(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function Ge(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 We(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 G=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=Ge(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 a;try{a=JSON.parse(o)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(n=a.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=We(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))}};import{join as Ze}from"node:path";import{mkdirSync as Er}from"node:fs";import{createHash as wr}from"node:crypto";import{dirname as xr}from"node:path";import{mkdirSync as kr,readFileSync as ds,renameSync as vr,writeFileSync as Rr}from"node:fs";function Je(r){return wr("sha256").update(r).digest("hex")}function qe(r,e){kr(xr(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;Rr(t,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),vr(t,r)}function Xe(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function h(r,e=20){let t=[],n=new Set;for(let o of r.slice().reverse()){let s=Xe(o);if(!(!s||n.has(s))&&(n.add(s),t.push(o),t.length>=e))break}return t.reverse()}function Mr(r,e=20){let t=new Map;for(let n of r){let o=`${n.kind}|${Xe(n.command)}`;t.delete(o),t.set(o,n)}return Array.from(t.values()).slice(-e)}function Ir(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function Qe(r,e){let t=e.status??r?.status??"pending",n=t;r&&(r.status==="completed"&&t!=="completed"?n="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(n=r.status));let o=r&&Ir(e)?r.title:e.text;return{id:r?.id??Je(e.key).slice(0,24),title:o,status:n,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function et(r,e){let t=`projects/${r.id}/work/observations/`,n=await e.list(t),o=[];for(let s of n.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(s.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&o.push(c)}catch{}}return o}async function Ar(r,e){let n=(await et(r,e)).flatMap(i=>i.observations).sort((i,y)=>{let ye=i.occurredAt.localeCompare(y.occurredAt);if(ye!==0)return ye;let he=i.sequence-y.sequence;return he!==0?he:i.id.localeCompare(y.id)}),o=new Map,s=new Map,a,c,u,d,f,m=[],l=[],g=[],b=[],M=[],I=new Map,ue=[],de=[],le=[],pe=[],me=[],fe=[];for(let i of n)switch(i.kind){case"request":a=i.text;break;case"activity":c=i.text;break;case"goal":u=i.text;break;case"plan":d=i.text;break;case"phase":o.set(i.key,Qe(o.get(i.key),i));break;case"task":s.set(i.key,Qe(s.get(i.key),i));break;case"decision":m.push(i.text);break;case"blocker":l.push(i.text);break;case"warning":g.push(i.text);break;case"next_action":b.push(i.text);break;case"file":{M.push(i.text);let y=i.fileAction??"active";I.delete(i.text),I.set(i.text,y),y==="modified"?ue.push(i.text):y==="created"?de.push(i.text):y==="deleted"&&le.push(i.text);break}case"command":pe.push(i.text);break;case"test":me.push(i.text),i.checkKind&&fe.push({kind:i.checkKind,command:i.text,status:i.checkStatus??"unknown",updatedAt:i.occurredAt,agent:i.agent,nativeSessionId:i.nativeSessionId});break;case"session":f={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let w=Array.from(o.values()).sort((i,y)=>(i.order??Number.MAX_SAFE_INTEGER)-(y.order??Number.MAX_SAFE_INTEGER)),S=Array.from(s.values()).sort((i,y)=>(i.order??Number.MAX_SAFE_INTEGER)-(y.order??Number.MAX_SAFE_INTEGER)),Z=w.find(i=>i.status==="in_progress")??w.find(i=>i.status==="blocked")??w.find(i=>i.status==="pending"),D=S.find(i=>i.status==="in_progress")??S.find(i=>i.status==="blocked")??S.find(i=>i.status==="pending"),lt=h([...b,...D?[D.title]:[],...!D&&Z?[Z.title]:[],...S.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),pt=h([...l,...w.filter(i=>i.status==="blocked").map(i=>i.title),...S.filter(i=>i.status==="blocked").map(i=>i.title)],20),Q={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:u,plan:d,phases:w,tasks:S,decisions:h(m,20),blockers:pt,warnings:h(g,20),nextActions:lt,filesTouched:h(M,30),activeFiles:Array.from(I.entries()).filter(([,i])=>i!=="deleted").map(([i])=>i).slice(-5),modifiedFiles:h(ue,30),createdFiles:h(de,30),deletedFiles:h(le,30),commands:h(pe,20),tests:h(me,20),checks:Mr(fe,20),currentPhase:Z,currentTask:D,progress:{phasesTotal:w.length,phasesCompleted:w.filter(i=>i.status==="completed").length,tasksTotal:S.length,tasksCompleted:S.filter(i=>i.status==="completed").length,blocked:w.filter(i=>i.status==="blocked").length+S.filter(i=>i.status==="blocked").length},lastSession:f,updatedAt:n.length?n[n.length-1].occurredAt:new Date().toISOString()},ge=Ze(r.rootPath,".toolnet","work");return Er(ge,{recursive:!0}),qe(Ze(ge,"current.json"),Q),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(Q,null,2)+`
6
+ `,"application/json"),Q}async function tt(r,e){if((await et(r,e)).length>0)return Ar(r,e);let n=await e.getText(`projects/${r.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}import{createHash as Nr}from"node:crypto";import{hostname as Kr}from"node:os";import{createHash as jr,randomUUID as Pr}from"node:crypto";function R(r,e){let t=r.trim();if(!t)throw new Error(`${e} is required`);return t}function W(r,e){return encodeURIComponent(R(r,e))}function Tr(r){let e=JSON.stringify(r);if(e===void 0)throw new Error("Multi-host operation payload must be JSON serializable");return e}function nt(r){return jr("sha256").update(r).digest("hex")}function ot(r){return nt(Tr(r))}function st(r){return Number.isFinite(Date.parse(r))}function Or(r){return nt(JSON.stringify({version:r.version,operationId:r.operationId,projectId:r.projectId,scope:r.scope,hostId:r.hostId,occurredAt:r.occurredAt,payloadSha256:r.payloadSha256,payload:r.payload}))}function it(r){let e=R(r.projectId,"projectId"),t=R(r.scope,"scope"),n=R(r.hostId,"hostId"),o=R(r.operationId??Pr(),"operationId"),s=r.occurredAt??new Date().toISOString();if(!st(s))throw new Error(`Invalid operation timestamp: ${s}`);return{version:1,operationId:o,projectId:e,scope:t,hostId:n,occurredAt:s,payloadSha256:ot(r.payload),payload:r.payload}}function at(r,e){let t=["projects",W(r,"projectId"),"operations"];return e?`${[...t,W(e,"scope")].join("/")}/`:`${t.join("/")}/`}function Cr(r){return[at(r.projectId,r.scope).replace(/\/$/,""),W(r.hostId,"hostId"),`${W(r.operationId,"operationId")}-${r.payloadSha256}.json`].join("/")}async function ct(r,e){let t=Cr(e);return await r.put(t,`${JSON.stringify(e,null,2)}
7
+ `,"application/json"),t}function _r(r){let e;try{e=JSON.parse(r)}catch{return null}return e.version!==1||typeof e.operationId!="string"||typeof e.projectId!="string"||typeof e.scope!="string"||typeof e.hostId!="string"||typeof e.occurredAt!="string"||!st(e.occurredAt)||typeof e.payloadSha256!="string"||ot(e.payload)!==e.payloadSha256?null:e}function rt(r,e){let t=r.occurredAt.localeCompare(e.occurredAt);if(t!==0)return t;let n=r.hostId.localeCompare(e.hostId);if(n!==0)return n;let o=r.operationId.localeCompare(e.operationId);return o!==0?o:r.payloadSha256.localeCompare(e.payloadSha256)}async function ut(r,e,t){let n=R(e,"projectId"),o=R(t,"scope"),s=at(n,o),a=await r.list(s),c=[],u=[];for(let l of a){let g=await r.getText(l.key);if(!g){c.push(l.key);continue}let b=_r(g);if(!b){c.push(l.key);continue}if(b.projectId!==n){c.push(l.key);continue}if(b.scope!==o){c.push(l.key);continue}u.push(b)}let d=new Map;for(let l of u){let g=d.get(l.operationId);if(!g){d.set(l.operationId,[l]);continue}g.push(l)}let f=[],m=[];for(let[l,g]of d){if(new Set(g.map(I=>Or(I))).size>1){m.push({operationId:l,variants:[...g].sort(rt)});continue}let M=g[0];M&&f.push(M)}return f.sort(rt),m.sort((l,g)=>l.operationId.localeCompare(g.operationId)),c.sort(),{operations:f,conflicts:m,invalidKeys:c}}function Dr(r){let t=(r??process.env.TOOLNET_HOST_ID??Kr()).trim();return t||`pid-${process.pid}`}function $r(r){let e=t=>{if(t===null||typeof t!="object")return t;if(Array.isArray(t))return t.map(o=>e(o));let n=t;return Object.fromEntries(Object.keys(n).sort().map(o=>[o,e(n[o])]))};return JSON.stringify(e(r))}function J(r){return Nr("sha256").update($r(r)).digest("hex")}function Lr(r,e){let t=J(r).slice(0,12),n=J(e);return["memory",t,n].join("-")}function Hr(r,e){let t=r.updatedAt.localeCompare(e.updatedAt);if(t!==0)return t;let n=r.createdAt.localeCompare(e.createdAt);return n!==0?n:J(r).localeCompare(J(e))}function zr(r,e){return Hr(r,e)>=0?r:e}function ce(r,e){let t=new Map;for(let n of r)t.set(n.id,n);for(let n of e){if(n.payload.kind!=="upsert")continue;let o=n.payload.memory,s=t.get(o.id);if(!s){t.set(o.id,o);continue}t.set(o.id,zr(s,o))}return[...t.values()].sort((n,o)=>n.id.localeCompare(o.id))}var q=class{constructor(e,t={}){this.storage=e;this.legacy=new U(e),this.hostId=Dr(t.hostId)}storage;legacy;hostId;diagnostics={operationCount:0,conflicts:0,invalidKeys:0};getDiagnostics(){return{...this.diagnostics}}async operations(e){let t=await ut(this.storage,e,"memory");return this.diagnostics={operationCount:t.operations.length,conflicts:t.conflicts.length,invalidKeys:t.invalidKeys.length},t.operations}async load(e){let t=await this.legacy.load(e),n=await this.operations(e);return ce(t,n)}async appendMemory(e,t){let n=it({projectId:e,scope:"memory",hostId:this.hostId,operationId:Lr(this.hostId,t),occurredAt:t.updatedAt,payload:{kind:"upsert",memory:t}});await ct(this.storage,n)}async refreshProjection(e){let t=await this.legacy.load(e),n=await this.operations(e),o=ce(t,n);return await this.legacy.save(e,o),o}async save(e,t){let n=[...t].sort((a,c)=>a.id.localeCompare(c.id));for(let a of n)await this.appendMemory(e,a);let o=await this.operations(e),s=ce(t,o);await this.legacy.save(e,s)}};async function dt(r,e){let t=new Date().toISOString(),o=await new q(e).refreshProjection(r.id),s=await tt(r,e);return{startedAt:t,finishedAt:new Date().toISOString(),memories:o.length,workAvailable:s!==null}}function Br(r,e){let t=r.indexOf(e);if(!(t<0))return r[t+1]}function Vr(r){return{projectPath:Br(r,"--project"),json:r.includes("--json"),quiet:r.includes("--quiet")}}async function Yr(r){let e=Se(),t=Ue(Ye({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new G(t,r.id,r.name,r.remote??r.name)}async function Fr(){let r=Vr(process.argv.slice(2)),e=r.projectPath??process.cwd(),t=new B().detect(e);if(!t){r.quiet||console.error(`ToolNet project not found: ${e}`),process.exitCode=2;return}let n;try{n=await Yr(t)}catch(o){r.quiet||console.error(o instanceof Error?o.message:String(o)),process.exitCode=3;return}try{let o=await dt(t,n);if(r.quiet)return;if(r.json){console.log(JSON.stringify(o));return}console.log(["ToolNet Memory refreshed",`memory=${o.memories}`,`work=${o.workAvailable?"yes":"no"}`].join(" "))}catch(o){r.quiet||console.error(o instanceof Error?o.message:String(o)),process.exitCode=4}}Fr().then(()=>{process.exit(process.exitCode??0)});
@@ -0,0 +1,2 @@
1
+ var n={supported:!0,structural:!0,lexicalSearch:!0,engine:"typescript-compiler-api",lexicalEngine:"file-chunk-fts5-bm25"},t={supported:!1,structural:!1,lexicalSearch:!0,engine:"unsupported",lexicalEngine:"file-chunk-fts5-bm25"},r=[{language:"typescript",extensions:[".ts"],...n},{language:"tsx",extensions:[".tsx"],...n},{language:"javascript",extensions:[".js"],...n},{language:"jsx",extensions:[".jsx"],...n},{language:"mts",extensions:[".mts"],...n},{language:"cts",extensions:[".cts"],...n},{language:"mjs",extensions:[".mjs"],...n},{language:"cjs",extensions:[".cjs"],...n},{language:"python",extensions:[".py"],...t,lspServer:"pyright-langserver"},{language:"go",extensions:[".go"],...t,lspServer:"gopls"},{language:"rust",extensions:[".rs"],...t,lspServer:"rust-analyzer"},{language:"c",extensions:[".c",".h"],...t,lspServer:"clangd"},{language:"cpp",extensions:[".cc",".cpp",".cxx",".hpp",".hh"],...t,lspServer:"clangd"}];import{spawnSync as p}from"node:child_process";var g=[{language:"python",command:"pyright-langserver"},{language:"go",command:"gopls"},{language:"rust",command:"rust-analyzer"},{language:"c",command:"clangd"},{language:"cpp",command:"clangd"}];function u(e){return e.split(/\r?\n/u).map(a=>a.trim()).find(Boolean)||void 0}function x(e,s){let a=p(s,["--version"],{encoding:"utf8",timeout:2e3,windowsHide:!0}),l=!a.error&&a.status===0,c=[a.stdout??"",a.stderr??""].join(`
2
+ `);return{language:e,command:s,installed:l,...l?{version:u(c)}:{},mode:"external-optional",activeInStructuralGraph:!1}}function o(){return g.map(e=>x(e.language,e.command))}var d=process.argv.includes("--json"),i=o(),f={structuralParser:{engine:"typescript-compiler-api",languages:r.filter(e=>e.structural).map(e=>e.language)},lexicalSearch:{engine:"sqlite-fts5-bm25",languages:r.filter(e=>e.lexicalSearch).map(e=>e.language)},lspFoundation:{mode:"detection-only",automaticDownload:!1,structuralGraphIntegration:!1,servers:i}};if(d)console.log(JSON.stringify(f,null,2));else{console.log("ToolNet Code Intelligence Capabilities"),console.log(""),console.log("Structural parser: TypeScript Compiler API");for(let e of r)console.log([e.language.padEnd(12),e.structural?"structural=yes":"structural=no",e.lexicalSearch?"lexical=yes":"lexical=no",e.lspServer?`lsp=${e.lspServer}`:""].filter(Boolean).join(" "));console.log(""),console.log("LSP detection:");for(let e of i)console.log([e.language.padEnd(12),e.command.padEnd(22),e.installed?"available":"not-installed"].join(" "))}