toolnet-memory 0.3.15 → 0.3.17

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 (48) hide show
  1. package/.env.example +74 -0
  2. package/.release-target +1 -1
  3. package/README.md +316 -6
  4. package/bin/toolnet-memory +12 -0
  5. package/bundle/agy-hook.js +66 -66
  6. package/bundle/agy.js +56 -56
  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/claude-hook.js +49 -49
  11. package/bundle/code-capabilities.js +2 -0
  12. package/bundle/codex-context.js +29 -29
  13. package/bundle/codex.js +71 -71
  14. package/bundle/context-runtime.js +39 -39
  15. package/bundle/context.js +15 -15
  16. package/bundle/copilot-hook.js +78 -78
  17. package/bundle/cursor-hook.js +78 -78
  18. package/bundle/docker-healthcheck.js +3 -0
  19. package/bundle/doctor.js +4 -4
  20. package/bundle/full-index.js +22 -21
  21. package/bundle/gc.js +5 -3
  22. package/bundle/graph-cli.js +1 -1
  23. package/bundle/graph-index.js +5 -4
  24. package/bundle/graph-ui.js +4 -3
  25. package/bundle/grok-hook.js +56 -56
  26. package/bundle/handoff-refresh.js +10 -10
  27. package/bundle/help-cli.js +4 -4
  28. package/bundle/impact.js +5 -4
  29. package/bundle/incremental.js +5 -5
  30. package/bundle/init.js +36 -35
  31. package/bundle/kiro-hook.js +85 -85
  32. package/bundle/learner.js +8 -6
  33. package/bundle/mcp.js +19 -17
  34. package/bundle/memory-agent.js +6 -6
  35. package/bundle/memory-query.js +7 -7
  36. package/bundle/opencode.js +77 -77
  37. package/bundle/project-manual.js +7 -7
  38. package/bundle/public/index.html +51 -2
  39. package/bundle/recovery-certify.js +9 -9
  40. package/bundle/runtime.js +16 -13
  41. package/bundle/semantic.js +6 -5
  42. package/bundle/service.js +11 -6
  43. package/bundle/snapshot.js +6 -4
  44. package/bundle/status-cli.js +4 -4
  45. package/bundle/toolnet-cli.js +46 -46
  46. package/bundle/work-continuity.js +7 -7
  47. package/package.json +38 -2
  48. package/release-manifest.json +143 -4
package/bundle/gc.js CHANGED
@@ -1,3 +1,5 @@
1
- import"dotenv/config";import{existsSync as re,readFileSync as oe}from"node:fs";import{homedir as se}from"node:os";import{join as ne}from"node:path";function ie(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 ae(){let r=process.env.TOOLNET_GLOBAL_ENV??ne(se(),".config","toolnet-memory",".env");if(!re(r))return;let e=oe(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let n=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=ie(o.slice(s+1)))}}ae();function m(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function f(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function C(){return{memory:{autoCapture:m(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:m(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:m(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:m(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:f(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:f(process.env.MEMORY_RERANK_TOP,10),finalContext:f(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:f(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:m(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:f(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{homedir as Ae}from"node:os";import{join as Oe}from"node:path";import{DeleteObjectCommand as ce,GetObjectCommand as pe,HeadObjectCommand as ue,ListObjectsV2Command as le,PutObjectCommand as de,S3Client as ge}from"@aws-sdk/client-s3";import{getSignedUrl as me}from"@aws-sdk/s3-request-presigner";var S=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ge({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new de({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await me(this.client,new pe({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new ue({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 ce({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new le({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as R,mkdir as fe,readFile as ye,readdir as he,rm as Se,stat as E,writeFile as je}from"node:fs/promises";import{dirname as ve,join as Pe,relative as A,resolve as xe}from"node:path";var y=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return xe(this.root,t)}async put(e,t){let o=this.path(e);await fe(ve(o),{recursive:!0}),await je(o,t)}async get(e){try{return await ye(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await R(this.path(e)),!0}catch{return!1}}async delete(e){await Se(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await R(t)}catch{return o}let s=async i=>{let c=await he(i,{withFileTypes:!0});for(let p of c){let a=Pe(i,p.name);if(p.isDirectory()){await s(a);continue}let u=await E(a);o.push({key:A(this.root,a),size:u.size,updatedAt:u.mtime.toISOString()})}},n=await E(t);return n.isDirectory()?await s(t):o.push({key:A(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),o}};import{DeleteObjectCommand as we,GetObjectCommand as ke,HeadObjectCommand as be,ListObjectsV2Command as Me,PutObjectCommand as Ce,S3Client as Re}from"@aws-sdk/client-s3";import{getSignedUrl as Ee}from"@aws-sdk/s3-request-presigner";var h=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Re({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ce({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Ee(this.client,new ke({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`${this.name} download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new be({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new Me({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};function b(r,e){return console.warn(e),new y(r)}function O(r){let e=r.localRoot??Oe(Ae(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new h({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 h({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 S({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):b(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new y(e)}function Ie(r){return new Promise(e=>setTimeout(e,r))}async function I(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let i=1;i<=t;i++)try{return await r()}catch(c){if(n=c,i>=t)break;let p=Math.min(s,o*2**(i-1)),a=Math.floor(Math.random()*Math.max(1,p*.2));await Ie(p+a)}throw n}var Te=new Set(["put","get","getText","delete","list"]);function T(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:Te.has(o)?(...n)=>I(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}function $(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 _(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 o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var j=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=$(s??o),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(),o=t,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}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"&&(o=i.createdAt)}let n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(n,null,2)+`
3
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=_(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,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}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 $e={keepSnapshots:10,runtimeDays:30,staleLockMinutes:10};function v(r,e,t){if(!Number.isSafeInteger(r)||r<e)throw new Error(`${t} must be an integer >= ${e}`);return r}function _e(r){let e=v(r.keepSnapshots,1,"keepSnapshots"),t=v(r.runtimeDays,1,"runtimeDays"),o=v(r.staleLockMinutes,1,"staleLockMinutes"),s;return r.snapshotMaxAgeDays!==void 0&&(s=v(r.snapshotMaxAgeDays,1,"snapshotMaxAgeDays")),{keepSnapshots:e,runtimeDays:t,staleLockMinutes:o,...s!==void 0?{snapshotMaxAgeDays:s}:{}}}function N(r={}){return _e({...$e,...r})}import{existsSync as K,readFileSync as Ne}from"node:fs";import{dirname as P,join as D,parse as G,resolve as L}from"node:path";var Ke=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];function De(r){return Ke.some(e=>K(D(r,e)))}function Ge(r){let e=L(r),t=G(e).root;for(;;){if(De(e))return e;if(e===t)return null;let o=P(e);if(o===e)return null;e=o}}function Le(r){let e=L(r),t=Ge(e),o=G(e).root;for(;;){let s=D(e,".toolnet","project.json");if(K(s))return s;if(t&&e===t||e===o)return null;let n=P(e);if(n===e)return null;e=n}}function F(r=process.cwd()){let e=Le(r);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");let t;try{t=JSON.parse(Ne(e,"utf8"))}catch{throw new Error(`INVALID_PROJECT_MANIFEST: ${e}`)}if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`INVALID_PROJECT_MANIFEST: ${e}`);let o=t;if(typeof o.id!="string"||!o.id.trim())throw new Error("INVALID_PROJECT_MANIFEST: missing id");if(typeof o.name!="string"||!o.name.trim())throw new Error("INVALID_PROJECT_MANIFEST: missing name");let s=P(P(e));return{id:o.id,name:o.name,remote:typeof o.remote=="string"&&o.remote.trim()?o.remote:o.name,rootPath:s,createdAt:typeof o.createdAt=="string"?o.createdAt:new Date(0).toISOString(),updatedAt:typeof o.updatedAt=="string"?o.updatedAt:new Date(0).toISOString(),graphVersion:typeof o.graphVersion=="number"?o.graphVersion:0,memoryVersion:typeof o.memoryVersion=="number"?o.memoryVersion:0,metadata:o.metadata&&typeof o.metadata=="object"?o.metadata:void 0}}var Fe=["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"],x=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let s=new Date().toISOString(),n=s.replace(/[:.]/g,"-"),i=this.projectPrefix(e),c=this.snapshotPrefix(e,n),p=[];for(let u of Fe){let l=`${i}/${u}`,g=await this.storage.get(l);g&&(await this.storage.put(`${c}/${u}`,g,"application/json"),p.push(u))}if(p.length===0)return null;let a={version:1,id:n,projectId:e,createdAt:s,reason:t,objects:p,metadata:o};return await this.storage.put(`${c}/snapshot.json`,JSON.stringify(a,null,2),"application/json"),a}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),s=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),n=[];for(let i of s){let c=await this.storage.getText(i.key);if(c)try{n.push(JSON.parse(c))}catch{}}return n.sort((i,c)=>c.createdAt.localeCompare(i.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),s=await this.storage.getText(`${o}/snapshot.json`);if(!s)throw new Error(`Snapshot not found: ${t}`);let n=JSON.parse(s);if(n.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),c=[];for(let p of n.objects){let a=await this.storage.get(`${o}/${p}`);a&&(await this.storage.put(`${i}/${p}`,a,"application/json"),c.push(p))}return{restored:c}}async remove(e,t){let o=this.snapshotPrefix(e,t),s=await this.storage.list(o);for(let n of s)await this.storage.delete(n.key);return s.length}async prune(e,t=10){let s=(await this.list(e)).slice(t),n=0;for(let i of s)await this.remove(e,i.id),n++;return n}};import{existsSync as Ye,rmSync as He}from"node:fs";import{existsSync as U,lstatSync as V,readFileSync as Je,readdirSync as Be}from"node:fs";import{basename as z,join as d,relative as Ue,resolve as J}from"node:path";function M(r,e){return Math.max(0,e-r)}function Ve(r){if(!Number.isInteger(r)||r<=0)return!1;try{return process.kill(r,0),!0}catch(e){return e?.code!=="ESRCH"}}function W(r){let e="";try{e=Je(r,"utf8").trim()}catch{return!1}if(!e)return!1;try{let t=JSON.parse(e);return typeof t.pid!="number"?!1:Ve(t.pid)}catch{return!1}}function Y(r){return r==="journal.lock"||r===".current.lock"||r.endsWith(".lock")}function H(r){return r.startsWith(".tmp-")||r.includes(".tmp-")||r.endsWith(".tmp")||r.endsWith(".partial")}function q(r){if(!U(r))return[];let e=[];for(let t of Be(r,{withFileTypes:!0})){let o=d(r,t.name);if(!t.isSymbolicLink()){if(t.isDirectory()){e.push(...q(o));continue}t.isFile()&&e.push(o)}}return e.sort()}function B(r,e){return[r,e].join(":")}function ze(r){return d(r.rootPath,".toolnet","runtime")}function We(r,e){let t=J(ze(r)),o=J(e),s=Ue(t,o);return!!s&&s!==".."&&!s.startsWith("../")&&!s.startsWith("..\\")}function Z(r,e,t,o=Date.now()){if(e.scope!=="local")return{safe:!1,detail:"candidate is not local"};if(!We(r,e.target))return{safe:!1,detail:"target escaped .toolnet/runtime"};if(!U(e.target))return{safe:!1,detail:"target disappeared"};let s;try{s=V(e.target)}catch{return{safe:!1,detail:"cannot stat target"}}if(!s.isFile()||s.isSymbolicLink())return{safe:!1,detail:"target is not a regular file"};if(e.expectedMtimeMs!==void 0&&s.mtimeMs!==e.expectedMtimeMs)return{safe:!1,detail:"target changed after planning"};let n=z(e.target);if(e.category==="runtime-lock"){if(!Y(n))return{safe:!1,detail:"lock name no longer matches policy"};let i=t.staleLockMinutes*6e4;return M(s.mtimeMs,o)<i?{safe:!1,detail:"lock is no longer stale"}:W(e.target)?{safe:!1,detail:"lock owner is alive"}:{safe:!0}}if(e.category==="runtime-temp"){if(!H(n))return{safe:!1,detail:"temporary file name no longer matches policy"};let i=t.runtimeDays*864e5;return M(s.mtimeMs,o)<i?{safe:!1,detail:"temporary file is too new"}:{safe:!0}}return{safe:!1,detail:"category is protected from local deletion"}}function Q(r,e,t=Date.now()){let o=d(r.rootPath,".toolnet"),s=d(o,"runtime"),n=[],i=[{scope:"local",category:"protected-memory",target:d(o,"memory"),reason:"durable semantic memory is never age-GCed"},{scope:"local",category:"protected-work",target:d(o,"work"),reason:"current work continuity is authoritative state"},{scope:"local",category:"protected-context",target:d(o,"context"),reason:"context is not deleted by retention policy"},{scope:"local",category:"protected-journal",target:d(o,"journal","events.jsonl"),reason:"shared project journal is durable continuity data"},{scope:"local",category:"protected-legacy-session",target:d(o,"sessions"),reason:"legacy sessions remain read/protected and are never automatically removed"},{scope:"local",category:"protected-wal",target:d(s,"sources"),reason:"events.jsonl and state.json remain authoritative crash-recovery WAL/state"}],c=e.staleLockMinutes*6e4,p=e.runtimeDays*864e5;for(let a of q(s)){let u;try{u=V(a)}catch{continue}if(!u.isFile()||u.isSymbolicLink())continue;let l=z(a),g=M(u.mtimeMs,t);if(Y(l)){if(g<c||W(a))continue;n.push({id:B("runtime-lock",a),scope:"local",category:"runtime-lock",target:a,reason:`stale runtime lock older than ${e.staleLockMinutes} minutes with no live owner`,action:"delete-file",ageMs:g,size:u.size,expectedMtimeMs:u.mtimeMs});continue}l==="events.jsonl"||l==="state.json"||H(l)&&(g<p||n.push({id:B("runtime-temp",a),scope:"local",category:"runtime-temp",target:a,reason:`temporary runtime artifact older than ${e.runtimeDays} days`,action:"delete-file",ageMs:g,size:u.size,expectedMtimeMs:u.mtimeMs}))}return n.sort((a,u)=>a.target.localeCompare(u.target)),{version:1,generatedAt:new Date(t).toISOString(),projectId:r.id,projectRoot:r.rootPath,policy:e,candidates:n,protected:i,estimatedBytes:n.reduce((a,u)=>a+(u.size??0),0)}}async function X(r,e,t,o){let s=[],n=0,i=0,c=0,p=0;for(let a of t){if(o.dryRun){s.push({candidate:a,status:"skipped",detail:"dry-run"}),i+=1;continue}if(a.action==="delete-file"){let u=Z(r,a,e);if(!u.safe){s.push({candidate:a,status:"skipped",detail:u.detail??"safety check rejected target"}),i+=1;continue}try{if(!Ye(a.target)){s.push({candidate:a,status:"skipped",detail:"target already absent"}),i+=1;continue}He(a.target,{force:!0}),s.push({candidate:a,status:"deleted"}),n+=1,p+=a.size??0}catch(l){s.push({candidate:a,status:"failed",detail:l instanceof Error?l.message:String(l)}),c+=1}continue}if(a.action==="delete-snapshot"){if(a.scope!=="remote"||!a.snapshotId){s.push({candidate:a,status:"skipped",detail:"invalid snapshot candidate"}),i+=1;continue}if(!o.snapshotManager){s.push({candidate:a,status:"skipped",detail:"remote snapshot manager unavailable"}),i+=1;continue}try{await o.snapshotManager.remove(r.id,a.snapshotId),s.push({candidate:a,status:"deleted"}),n+=1}catch(u){s.push({candidate:a,status:"failed",detail:u instanceof Error?u.message:String(u)}),c+=1}continue}s.push({candidate:a,status:"skipped",detail:"unsupported GC action"}),i+=1}return{dryRun:o.dryRun,deleted:n,skipped:i,failed:c,bytesFreed:p,items:s}}function qe(r,e){let t=Date.parse(r);return Number.isFinite(t)?Math.max(0,e-t):null}function ee(r,e,t=Date.now()){let o=[...r].sort((c,p)=>p.createdAt.localeCompare(c.createdAt)),s=[],n=[],i=e.snapshotMaxAgeDays===void 0?void 0:e.snapshotMaxAgeDays*864e5;for(let c=0;c<o.length;c+=1){let p=o[c],a=qe(p.createdAt,t);if(c<e.keepSnapshots){n.push({scope:"remote",category:"snapshot",target:p.id,reason:`one of newest ${e.keepSnapshots} snapshots`});continue}if(a===null){n.push({scope:"remote",category:"snapshot",target:p.id,reason:"snapshot timestamp is invalid; uncertain data is retained"});continue}if(i!==void 0&&a<i){n.push({scope:"remote",category:"snapshot",target:p.id,reason:`snapshot has not reached ${e.snapshotMaxAgeDays} day age guard`});continue}s.push({id:`snapshot:${p.id}`,scope:"remote",category:"snapshot",target:p.id,snapshotId:p.id,reason:e.snapshotMaxAgeDays===void 0?`snapshot exceeds keep limit ${e.keepSnapshots}`:`snapshot exceeds keep limit ${e.keepSnapshots} and age guard ${e.snapshotMaxAgeDays} days`,action:"delete-snapshot",ageMs:a})}return n.push({scope:"remote",category:"protected-remote-operation",target:"projects/<project>/operations/**",reason:"append-only multi-host operations are outside GC authority"}),{candidates:s,protected:n}}var w=class{constructor(e,t,o={}){this.project=e;this.policy=t;o.remoteStorage&&(this.snapshotManager=new x(o.remoteStorage))}project;policy;snapshotManager;async plan(e=!1){let t=Q(this.project,this.policy);if(!e)return t;if(!this.snapshotManager)throw new Error("REMOTE_GC_STORAGE_NOT_CONFIGURED");let o=await this.snapshotManager.list(this.project.id),s=ee(o,this.policy);return{...t,candidates:[...t.candidates,...s.candidates],protected:[...t.protected,...s.protected]}}async execute(e,t){if(e.projectId!==this.project.id)throw new Error("GC_PROJECT_MISMATCH");if(e.projectRoot!==this.project.rootPath)throw new Error("GC_PROJECT_ROOT_MISMATCH");if(!t&&e.candidates.some(o=>o.scope==="remote")){if(!this.snapshotManager)throw new Error("REMOTE_GC_STORAGE_NOT_CONFIGURED");e=await this.plan(!0)}return X(this.project,this.policy,e.candidates,{dryRun:t,snapshotManager:this.snapshotManager})}};function k(r,e){let t=`${e}=`,o=r.find(i=>i.startsWith(t)),s;if(o)s=o.slice(t.length);else{let i=r.indexOf(e);i>=0&&(s=r[i+1])}if(s===void 0)return;let n=Number(s);if(!Number.isSafeInteger(n))throw new Error(`Invalid ${e}: ${s}`);return n}function Ze(r,e){let t=`${e}=`,o=r.find(i=>i.startsWith(t));if(o)return o.slice(t.length).trim()||void 0;let s=r.indexOf(e);if(s<0)return;let n=r[s+1];if(!(!n||n.startsWith("--")))return n}function Qe(r){let e=r.includes("--apply"),t=r.includes("--dry-run");if(e&&t)throw new Error("Choose only one of --apply or --dry-run");return{apply:e,includeRemote:r.includes("--remote"),json:r.includes("--json"),project:Ze(r,"--project"),keepSnapshots:k(r,"--keep-snapshots"),snapshotMaxAgeDays:k(r,"--snapshot-days"),runtimeDays:k(r,"--runtime-days"),staleLockMinutes:k(r,"--stale-lock-minutes")}}function Xe(r){return N({...r.keepSnapshots!==void 0?{keepSnapshots:r.keepSnapshots}:{},...r.snapshotMaxAgeDays!==void 0?{snapshotMaxAgeDays:r.snapshotMaxAgeDays}:{},...r.runtimeDays!==void 0?{runtimeDays:r.runtimeDays}:{},...r.staleLockMinutes!==void 0?{staleLockMinutes:r.staleLockMinutes}:{}})}function te(r){return r<1024?`${r} B`:r<1024*1024?`${(r/1024).toFixed(1)} KiB`:`${(r/1024/1024).toFixed(1)} MiB`}function et(r,e,t){if(console.log("ToolNet Memory GC"),console.log(`Project: ${r.projectRoot}`),console.log(`Mode: ${e?"APPLY":"DRY-RUN"}`),console.log(`Remote snapshots: ${t?"included":"not requested"}`),console.log(`Candidates: ${r.candidates.length}`),console.log(`Estimated local bytes: ${te(r.estimatedBytes)}`),r.candidates.length===0){console.log("Nothing eligible for garbage collection.");return}console.log("");for(let o of r.candidates){let s=o.ageMs===void 0?"":` age=${(o.ageMs/864e5).toFixed(1)}d`;console.log(`[${o.scope}] ${o.category} ${o.target}${s}`),console.log(` ${o.reason}`)}}async function tt(r){let e=C(),t=T(O({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new j(t,r.id,r.name,r.remote??r.name)}async function rt(){let r=Qe(process.argv.slice(2)),e=F(r.project??process.cwd()),t=Xe(r),o=r.includeRemote?await tt(e):void 0,s=new w(e,t,{...o?{remoteStorage:o}:{}}),n=await s.plan(r.includeRemote);if(r.json){if(!r.apply){console.log(JSON.stringify({mode:"dry-run",plan:n},null,2));return}let c=await s.execute(n,!1);console.log(JSON.stringify({mode:"apply",plan:n,result:c},null,2)),c.failed>0&&(process.exitCode=1);return}if(et(n,r.apply,r.includeRemote),!r.apply){console.log(""),console.log("No data changed. Use --apply to execute this exact policy against a freshly re-planned state.");return}let i=await s.execute(n,!1);console.log(""),console.log(`Deleted: ${i.deleted}`),console.log(`Skipped: ${i.skipped}`),console.log(`Failed: ${i.failed}`),console.log(`Local bytes freed: ${te(i.bytesFreed)}`),i.failed>0&&(process.exitCode=1)}rt().catch(r=>{console.error(r instanceof Error?r.message:String(r)),process.exitCode=1});
1
+ import"dotenv/config";import{existsSync as Ue,readFileSync as ze}from"node:fs";import{homedir as Ye}from"node:os";import{join as Be}from"node:path";function Fe(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 Ve(){let r=process.env.TOOLNET_GLOBAL_ENV??Be(Ye(),".config","toolnet-memory",".env");if(!Ue(r))return;let e=ze(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]=Fe(n.slice(o+1)))}}Ve();function y(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function h(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function B(){return{memory:{autoCapture:y(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:y(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:y(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:y(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:h(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:h(process.env.MEMORY_RERANK_TOP,10),finalContext:h(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:h(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:y(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:h(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{homedir as bt}from"node:os";import{join as vt}from"node:path";import{DeleteObjectCommand as He,GetObjectCommand as Je,HeadObjectCommand as We,ListObjectsV2Command as Ze,PutObjectCommand as qe,S3Client as Qe}from"@aws-sdk/client-s3";import{getSignedUrl as Xe}from"@aws-sdk/s3-request-presigner";var b=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Qe({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 qe({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Xe(this.client,new Je({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 We({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 He({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Ze({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 F,mkdir as et,readFile as tt,readdir as rt,rm as nt,stat as V,writeFile as ot}from"node:fs/promises";import{dirname as st,join as it,relative as H,resolve as at}from"node:path";var E=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return at(this.root,t)}async put(e,t){let n=this.path(e);await et(st(n),{recursive:!0}),await ot(n,t)}async get(e){try{return await tt(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 F(this.path(e)),!0}catch{return!1}}async delete(e){await nt(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await F(t)}catch{return n}let o=async i=>{let c=await rt(i,{withFileTypes:!0});for(let u of c){let a=it(i,u.name);if(u.isDirectory()){await o(a);continue}let p=await V(a);n.push({key:H(this.root,a),size:p.size,updatedAt:p.mtime.toISOString()})}},s=await V(t);return s.isDirectory()?await o(t):n.push({key:H(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as ct,GetObjectCommand as ut,HeadObjectCommand as pt,ListObjectsV2Command as dt,PutObjectCommand as lt,S3Client as ft}from"@aws-sdk/client-s3";import{getSignedUrl as gt}from"@aws-sdk/s3-request-presigner";var S=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ft({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 lt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await gt(this.client,new ut({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 pt({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 ct({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new dt({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 mt,createDecipheriv as yt,createHash as ht,randomBytes as Et,timingSafeEqual as St}from"node:crypto";import{readFileSync as Pt}from"node:fs";var m=Buffer.from("TNMEME01","ascii"),W=1,P=8,x=12,I=16,Z=m.length+1+P+x+I,xt="toolnet-memory:remote-encryption:v1:",q="aes-256-gcm",C=32,d=class extends Error{constructor(t,n){super(n);this.code=t;this.name="RemoteEncryptionError"}code};function wt(r){return r?["1","true","yes","on","enabled"].includes(r.trim().toLowerCase()):!1}function N(r=process.env){return wt(r.TOOLNET_REMOTE_ENCRYPTION)}function J(r){let e=r.trim();if(!e)throw new d("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 d("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 d("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!==C)throw new d("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH",`Remote encryption key must decode to exactly ${C} bytes.`);return t}function Q(r=process.env){let e=r.TOOLNET_REMOTE_ENCRYPTION_KEY?.trim(),t=r.TOOLNET_REMOTE_ENCRYPTION_KEY_FILE?.trim();if(e&&t)throw new d("REMOTE_ENCRYPTION_KEY_AMBIGUOUS","Configure either TOOLNET_REMOTE_ENCRYPTION_KEY or TOOLNET_REMOTE_ENCRYPTION_KEY_FILE, not both.");if(e)return J(e);if(t){let n;try{n=Pt(t,"utf8")}catch(o){throw new d("REMOTE_ENCRYPTION_KEY_FILE_READ_FAILED",[`Unable to read remote encryption key file: ${t}.`,o instanceof Error?o.message:String(o)].join(" "))}return J(n)}}function X(r){return ht("sha256").update(r).digest().subarray(0,P)}function ee(r){return Buffer.from(`${xt}${r}`,"utf8")}function $(r){return r.byteLength<m.length?!1:Buffer.from(r).subarray(0,m.length).equals(m)}function te(r,e,t){if(t.byteLength!==C)throw new d("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=Et(x),s=mt(q,t,o);s.setAAD(ee(r));let i=Buffer.concat([s.update(n),s.final()]),c=s.getAuthTag(),u=Buffer.alloc(Z),a=0;return m.copy(u,a),a+=m.length,u.writeUInt8(W,a),a+=1,X(t).copy(u,a),a+=P,o.copy(u,a),a+=x,c.copy(u,a),Buffer.concat([u,i])}function re(r,e,t){let n=Buffer.from(e);if(!$(n))throw new d("REMOTE_ENCRYPTION_ENVELOPE_REQUIRED","Payload is not a ToolNet encrypted remote object.");if(n.length<Z)throw new d("REMOTE_ENCRYPTION_ENVELOPE_TRUNCATED","Encrypted remote payload is truncated.");let o=m.length,s=n.readUInt8(o);if(o+=1,s!==W)throw new d("REMOTE_ENCRYPTION_VERSION_UNSUPPORTED",`Unsupported remote encryption envelope version: ${s}.`);let i=n.subarray(o,o+P);o+=P;let c=X(t);if(!St(i,c))throw new d("REMOTE_ENCRYPTION_KEY_MISMATCH","Configured remote encryption key does not match this encrypted object.");let u=n.subarray(o,o+x);o+=x;let a=n.subarray(o,o+I);o+=I;let p=n.subarray(o),l=yt(q,t,u);l.setAAD(ee(r)),l.setAuthTag(a);try{return Buffer.concat([l.update(p),l.final()])}catch{throw new d("REMOTE_ENCRYPTION_AUTH_FAILED","Encrypted remote object failed AES-GCM authentication.")}}var D=class{constructor(e,t){this.inner=e;this.options=t;if(this.name=e.name,t.enabled&&!t.key)throw new d("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 d("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote encryption key is unavailable.");let s=te(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(!$(t))return t;if(!this.options.enabled)throw new d("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 d("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote object is encrypted but no decryption key is configured.");return re(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 ne(r,e=process.env){if(r.name==="local")return N(e)&&console.warn("[storage] Remote encryption requested but active storage provider is local; local data remains unchanged."),r;let t=N(e),n=t?Q(e):void 0;return new D(r,{enabled:t,key:n})}function w(r){return ne(r)}function K(r,e){return console.warn(e),w(new E(r))}function oe(r){let e=r.localRoot??vt(bt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?w(new S({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):K(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?w(new S({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):K(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?w(new b({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):K(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return w(new E(e))}function jt(r){return new Promise(e=>setTimeout(e,r))}async function se(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(c){if(s=c,i>=t)break;let u=Math.min(o,n*2**(i-1)),a=Math.floor(Math.random()*Math.max(1,u*.2));await jt(u+a)}throw s}var kt=new Set(["put","get","getText","delete","list"]);function ie(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:kt.has(n)?(...s)=>se(()=>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 ce(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 i;try{i=JSON.parse(o)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}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)+`
3
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ce(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 Rt={keepSnapshots:10,runtimeDays:30,staleLockMinutes:10};function j(r,e,t){if(!Number.isSafeInteger(r)||r<e)throw new Error(`${t} must be an integer >= ${e}`);return r}function At(r){let e=j(r.keepSnapshots,1,"keepSnapshots"),t=j(r.runtimeDays,1,"runtimeDays"),n=j(r.staleLockMinutes,1,"staleLockMinutes"),o;return r.snapshotMaxAgeDays!==void 0&&(o=j(r.snapshotMaxAgeDays,1,"snapshotMaxAgeDays")),{keepSnapshots:e,runtimeDays:t,staleLockMinutes:n,...o!==void 0?{snapshotMaxAgeDays:o}:{}}}function ue(r={}){return At({...Rt,...r})}import{existsSync as pe,readFileSync as _t}from"node:fs";import{dirname as k,join as de,parse as le,resolve as fe}from"node:path";var Ot=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];function Tt(r){return Ot.some(e=>pe(de(r,e)))}function Mt(r){let e=fe(r),t=le(e).root;for(;;){if(Tt(e))return e;if(e===t)return null;let n=k(e);if(n===e)return null;e=n}}function It(r){let e=fe(r),t=Mt(e),n=le(e).root;for(;;){let o=de(e,".toolnet","project.json");if(pe(o))return o;if(t&&e===t||e===n)return null;let s=k(e);if(s===e)return null;e=s}}function ge(r=process.cwd()){let e=It(r);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");let t;try{t=JSON.parse(_t(e,"utf8"))}catch{throw new Error(`INVALID_PROJECT_MANIFEST: ${e}`)}if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`INVALID_PROJECT_MANIFEST: ${e}`);let n=t;if(typeof n.id!="string"||!n.id.trim())throw new Error("INVALID_PROJECT_MANIFEST: missing id");if(typeof n.name!="string"||!n.name.trim())throw new Error("INVALID_PROJECT_MANIFEST: missing name");let o=k(k(e));return{id:n.id,name:n.name,remote:typeof n.remote=="string"&&n.remote.trim()?n.remote:n.name,rootPath:o,createdAt:typeof n.createdAt=="string"?n.createdAt:new Date(0).toISOString(),updatedAt:typeof n.updatedAt=="string"?n.updatedAt:new Date(0).toISOString(),graphVersion:typeof n.graphVersion=="number"?n.graphVersion:0,memoryVersion:typeof n.memoryVersion=="number"?n.memoryVersion:0,metadata:n.metadata&&typeof n.metadata=="object"?n.metadata:void 0}}var Ct=["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"],R=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),c=this.snapshotPrefix(e,s),u=[];for(let p of Ct){let l=`${i}/${p}`,g=await this.storage.get(l);g&&(await this.storage.put(`${c}/${p}`,g,"application/json"),u.push(p))}if(u.length===0)return null;let a={version:1,id:s,projectId:e,createdAt:o,reason:t,objects:u,metadata:n};return await this.storage.put(`${c}/snapshot.json`,JSON.stringify(a,null,2),"application/json"),a}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 c=await this.storage.getText(i.key);if(c)try{s.push(JSON.parse(c))}catch{}}return s.sort((i,c)=>c.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),c=[];for(let u of s.objects){let a=await this.storage.get(`${n}/${u}`);a&&(await this.storage.put(`${i}/${u}`,a,"application/json"),c.push(u))}return{restored:c}}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}};import{existsSync as Ut,rmSync as zt}from"node:fs";import{existsSync as he,lstatSync as Ee,readFileSync as Nt,readdirSync as $t}from"node:fs";import{basename as Se,join as f,relative as Dt,resolve as me}from"node:path";function L(r,e){return Math.max(0,e-r)}function Kt(r){if(!Number.isInteger(r)||r<=0)return!1;try{return process.kill(r,0),!0}catch(e){return e?.code!=="ESRCH"}}function Pe(r){let e="";try{e=Nt(r,"utf8").trim()}catch{return!1}if(!e)return!1;try{let t=JSON.parse(e);return typeof t.pid!="number"?!1:Kt(t.pid)}catch{return!1}}function xe(r){return r==="journal.lock"||r===".current.lock"||r.endsWith(".lock")}function we(r){return r.startsWith(".tmp-")||r.includes(".tmp-")||r.endsWith(".tmp")||r.endsWith(".partial")}function be(r){if(!he(r))return[];let e=[];for(let t of $t(r,{withFileTypes:!0})){let n=f(r,t.name);if(!t.isSymbolicLink()){if(t.isDirectory()){e.push(...be(n));continue}t.isFile()&&e.push(n)}}return e.sort()}function ye(r,e){return[r,e].join(":")}function Lt(r){return f(r.rootPath,".toolnet","runtime")}function Gt(r,e){let t=me(Lt(r)),n=me(e),o=Dt(t,n);return!!o&&o!==".."&&!o.startsWith("../")&&!o.startsWith("..\\")}function ve(r,e,t,n=Date.now()){if(e.scope!=="local")return{safe:!1,detail:"candidate is not local"};if(!Gt(r,e.target))return{safe:!1,detail:"target escaped .toolnet/runtime"};if(!he(e.target))return{safe:!1,detail:"target disappeared"};let o;try{o=Ee(e.target)}catch{return{safe:!1,detail:"cannot stat target"}}if(!o.isFile()||o.isSymbolicLink())return{safe:!1,detail:"target is not a regular file"};if(e.expectedMtimeMs!==void 0&&o.mtimeMs!==e.expectedMtimeMs)return{safe:!1,detail:"target changed after planning"};let s=Se(e.target);if(e.category==="runtime-lock"){if(!xe(s))return{safe:!1,detail:"lock name no longer matches policy"};let i=t.staleLockMinutes*6e4;return L(o.mtimeMs,n)<i?{safe:!1,detail:"lock is no longer stale"}:Pe(e.target)?{safe:!1,detail:"lock owner is alive"}:{safe:!0}}if(e.category==="runtime-temp"){if(!we(s))return{safe:!1,detail:"temporary file name no longer matches policy"};let i=t.runtimeDays*864e5;return L(o.mtimeMs,n)<i?{safe:!1,detail:"temporary file is too new"}:{safe:!0}}return{safe:!1,detail:"category is protected from local deletion"}}function je(r,e,t=Date.now()){let n=f(r.rootPath,".toolnet"),o=f(n,"runtime"),s=[],i=[{scope:"local",category:"protected-memory",target:f(n,"memory"),reason:"durable semantic memory is never age-GCed"},{scope:"local",category:"protected-work",target:f(n,"work"),reason:"current work continuity is authoritative state"},{scope:"local",category:"protected-context",target:f(n,"context"),reason:"context is not deleted by retention policy"},{scope:"local",category:"protected-journal",target:f(n,"journal","events.jsonl"),reason:"shared project journal is durable continuity data"},{scope:"local",category:"protected-audit",target:f(n,"audit","events.jsonl"),reason:"tamper-evident audit history is durable security data"},{scope:"local",category:"protected-legacy-session",target:f(n,"sessions"),reason:"legacy sessions remain read/protected and are never automatically removed"},{scope:"local",category:"protected-wal",target:f(o,"sources"),reason:"events.jsonl and state.json remain authoritative crash-recovery WAL/state"}],c=e.staleLockMinutes*6e4,u=e.runtimeDays*864e5;for(let a of be(o)){let p;try{p=Ee(a)}catch{continue}if(!p.isFile()||p.isSymbolicLink())continue;let l=Se(a),g=L(p.mtimeMs,t);if(xe(l)){if(g<c||Pe(a))continue;s.push({id:ye("runtime-lock",a),scope:"local",category:"runtime-lock",target:a,reason:`stale runtime lock older than ${e.staleLockMinutes} minutes with no live owner`,action:"delete-file",ageMs:g,size:p.size,expectedMtimeMs:p.mtimeMs});continue}l==="events.jsonl"||l==="state.json"||we(l)&&(g<u||s.push({id:ye("runtime-temp",a),scope:"local",category:"runtime-temp",target:a,reason:`temporary runtime artifact older than ${e.runtimeDays} days`,action:"delete-file",ageMs:g,size:p.size,expectedMtimeMs:p.mtimeMs}))}return s.sort((a,p)=>a.target.localeCompare(p.target)),{version:1,generatedAt:new Date(t).toISOString(),projectId:r.id,projectRoot:r.rootPath,policy:e,candidates:s,protected:i,estimatedBytes:s.reduce((a,p)=>a+(p.size??0),0)}}async function ke(r,e,t,n){let o=[],s=0,i=0,c=0,u=0;for(let a of t){if(n.dryRun){o.push({candidate:a,status:"skipped",detail:"dry-run"}),i+=1;continue}if(a.action==="delete-file"){let p=ve(r,a,e);if(!p.safe){o.push({candidate:a,status:"skipped",detail:p.detail??"safety check rejected target"}),i+=1;continue}try{if(!Ut(a.target)){o.push({candidate:a,status:"skipped",detail:"target already absent"}),i+=1;continue}zt(a.target,{force:!0}),o.push({candidate:a,status:"deleted"}),s+=1,u+=a.size??0}catch(l){o.push({candidate:a,status:"failed",detail:l instanceof Error?l.message:String(l)}),c+=1}continue}if(a.action==="delete-snapshot"){if(a.scope!=="remote"||!a.snapshotId){o.push({candidate:a,status:"skipped",detail:"invalid snapshot candidate"}),i+=1;continue}if(!n.snapshotManager){o.push({candidate:a,status:"skipped",detail:"remote snapshot manager unavailable"}),i+=1;continue}try{await n.snapshotManager.remove(r.id,a.snapshotId),o.push({candidate:a,status:"deleted"}),s+=1}catch(p){o.push({candidate:a,status:"failed",detail:p instanceof Error?p.message:String(p)}),c+=1}continue}o.push({candidate:a,status:"skipped",detail:"unsupported GC action"}),i+=1}return{dryRun:n.dryRun,deleted:s,skipped:i,failed:c,bytesFreed:u,items:o}}function Yt(r,e){let t=Date.parse(r);return Number.isFinite(t)?Math.max(0,e-t):null}function Re(r,e,t=Date.now()){let n=[...r].sort((c,u)=>u.createdAt.localeCompare(c.createdAt)),o=[],s=[],i=e.snapshotMaxAgeDays===void 0?void 0:e.snapshotMaxAgeDays*864e5;for(let c=0;c<n.length;c+=1){let u=n[c],a=Yt(u.createdAt,t);if(c<e.keepSnapshots){s.push({scope:"remote",category:"snapshot",target:u.id,reason:`one of newest ${e.keepSnapshots} snapshots`});continue}if(a===null){s.push({scope:"remote",category:"snapshot",target:u.id,reason:"snapshot timestamp is invalid; uncertain data is retained"});continue}if(i!==void 0&&a<i){s.push({scope:"remote",category:"snapshot",target:u.id,reason:`snapshot has not reached ${e.snapshotMaxAgeDays} day age guard`});continue}o.push({id:`snapshot:${u.id}`,scope:"remote",category:"snapshot",target:u.id,snapshotId:u.id,reason:e.snapshotMaxAgeDays===void 0?`snapshot exceeds keep limit ${e.keepSnapshots}`:`snapshot exceeds keep limit ${e.keepSnapshots} and age guard ${e.snapshotMaxAgeDays} days`,action:"delete-snapshot",ageMs:a})}return s.push({scope:"remote",category:"protected-remote-operation",target:"projects/<project>/operations/**",reason:"append-only multi-host operations are outside GC authority"}),{candidates:o,protected:s}}var A=class{constructor(e,t,n={}){this.project=e;this.policy=t;n.remoteStorage&&(this.snapshotManager=new R(n.remoteStorage))}project;policy;snapshotManager;async plan(e=!1){let t=je(this.project,this.policy);if(!e)return t;if(!this.snapshotManager)throw new Error("REMOTE_GC_STORAGE_NOT_CONFIGURED");let n=await this.snapshotManager.list(this.project.id),o=Re(n,this.policy);return{...t,candidates:[...t.candidates,...o.candidates],protected:[...t.protected,...o.protected]}}async execute(e,t){if(e.projectId!==this.project.id)throw new Error("GC_PROJECT_MISMATCH");if(e.projectRoot!==this.project.rootPath)throw new Error("GC_PROJECT_ROOT_MISMATCH");if(!t&&e.candidates.some(n=>n.scope==="remote")){if(!this.snapshotManager)throw new Error("REMOTE_GC_STORAGE_NOT_CONFIGURED");e=await this.plan(!0)}return ke(this.project,this.policy,e.candidates,{dryRun:t,snapshotManager:this.snapshotManager})}};import{appendFileSync as qt,closeSync as Qt,existsSync as Oe,mkdirSync as Te,openSync as Xt,readFileSync as Me,statSync as er,unlinkSync as Ie,writeFileSync as tr}from"node:fs";import{createHash as rr,randomUUID as Ce}from"node:crypto";import{dirname as Ne,join as z}from"node:path";var Bt=[{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"}],Ft=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function Ae(r){return r.normalize("NFKC").trim().toLowerCase()}function Vt(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 Jt(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 Wt(r,e){return r.start<e.end&&e.start<r.end}function _e(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=Ae(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of Bt){let i=new RegExp(s.regex.source,s.regex.flags);for(let c of e.matchAll(i))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=_e(t),o=[];for(let s of n)o.some(i=>Wt(i,s))||o.push(s);return _e(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=Ae(e);return Ft.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)||Jt(e,o.index,o.index+s.length)&&(Vt(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var O=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((i,c)=>c.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 Zt=new O;function T(r){return Zt.sanitizeValue(r)}var G="0".repeat(64),nr=3e4,or=100,sr=20;function ir(r){return new Promise(e=>{setTimeout(e,r)})}function ar(r){return z(r.rootPath,".toolnet","audit")}function $e(r){return z(ar(r),"events.jsonl")}function De(r){return z(r.rootPath,".toolnet","runtime","locks","audit.lock")}function U(r){if(Array.isArray(r))return r.map(U);if(!r||typeof r!="object")return r;let e=r;return Object.fromEntries(Object.keys(e).sort().map(t=>[t,U(e[t])]))}function cr(r){return JSON.stringify(U(r))}function Ke(r){return rr("sha256").update(cr(r),"utf8").digest("hex")}function ur(){let r=process.env.TOOLNET_AGENT_ID?.trim()||process.env.TOOLNET_AGENT?.trim();return r?{kind:"agent",id:r}:{kind:"system",id:`pid:${process.pid}`}}function Le(r){let e=$e(r);if(!Oe(e))return[];let t=Me(e,"utf8"),n=[];for(let o of t.split(/\r?\n/u)){let s=o.trim();s&&n.push(JSON.parse(s))}return n}function pr(r){try{return Date.now()-er(r).mtimeMs>nr}catch{return!0}}async function dr(r){let e=De(r);Te(Ne(e),{recursive:!0,mode:448});for(let t=0;t<or;t+=1){let n=Ce();try{let o=Xt(e,"wx",384);try{tr(o,JSON.stringify({token:n,pid:process.pid,createdAt:new Date().toISOString()})+`
4
+ `)}finally{Qt(o)}return n}catch(o){if(o.code!=="EEXIST")throw o;if(pr(e)){try{Ie(e)}catch{}continue}await ir(sr)}}throw new Error("AUDIT_LOCK_TIMEOUT")}function lr(r,e){let t=De(r);if(Oe(t))try{if(JSON.parse(Me(t,"utf8")).token!==e)return;Ie(t)}catch{}}function fr(r){return Le(r).at(-1)}async function gr(r,e){let t=await dr(r);try{let n=fr(r);if(n){let p=mr(r);if(!p.valid)throw new Error(["AUDIT_LOG_INTEGRITY_FAILED",p.error??""].filter(Boolean).join(" "))}let o=e.details?T(e.details):void 0,s=e.target?T(e.target):void 0,i=T(e.actor??ur()),c={version:1,sequence:(n?.sequence??0)+1,id:Ce(),at:e.at??new Date().toISOString(),projectId:r.id,action:e.action,outcome:e.outcome,actor:i,...s?{target:s}:{},...o?{details:o}:{},previousHash:n?.hash??G},u={...c,hash:Ke(c)},a=$e(r);return Te(Ne(a),{recursive:!0,mode:448}),qt(a,JSON.stringify(u)+`
5
+ `,{encoding:"utf8",mode:384}),u}finally{lr(r,t)}}async function Y(r,e){try{return await gr(r,e),!0}catch(t){return console.warn(`[audit] ${t instanceof Error?t.message:String(t)}`),!1}}function mr(r){let e;try{e=Le(r)}catch(o){return{valid:!1,records:0,lastHash:G,firstInvalidLine:1,error:o instanceof Error?o.message:String(o)}}let t=G,n=1;for(let o=0;o<e.length;o+=1){let s=e[o];if(s.sequence!==n)return{valid:!1,records:e.length,lastHash:t,firstInvalidLine:o+1,error:"AUDIT_SEQUENCE_INVALID"};if(s.previousHash!==t)return{valid:!1,records:e.length,lastHash:t,firstInvalidLine:o+1,error:"AUDIT_PREVIOUS_HASH_INVALID"};let{hash:i,...c}=s,u=Ke(c);if(i!==u)return{valid:!1,records:e.length,lastHash:t,firstInvalidLine:o+1,error:"AUDIT_HASH_INVALID"};t=i,n+=1}return{valid:!0,records:e.length,lastHash:t}}function M(r,e){let t=`${e}=`,n=r.find(i=>i.startsWith(t)),o;if(n)o=n.slice(t.length);else{let i=r.indexOf(e);i>=0&&(o=r[i+1])}if(o===void 0)return;let s=Number(o);if(!Number.isSafeInteger(s))throw new Error(`Invalid ${e}: ${o}`);return s}function yr(r,e){let t=`${e}=`,n=r.find(i=>i.startsWith(t));if(n)return n.slice(t.length).trim()||void 0;let o=r.indexOf(e);if(o<0)return;let s=r[o+1];if(!(!s||s.startsWith("--")))return s}function hr(r){let e=r.includes("--apply"),t=r.includes("--dry-run");if(e&&t)throw new Error("Choose only one of --apply or --dry-run");return{apply:e,includeRemote:r.includes("--remote"),json:r.includes("--json"),project:yr(r,"--project"),keepSnapshots:M(r,"--keep-snapshots"),snapshotMaxAgeDays:M(r,"--snapshot-days"),runtimeDays:M(r,"--runtime-days"),staleLockMinutes:M(r,"--stale-lock-minutes")}}function Er(r){return ue({...r.keepSnapshots!==void 0?{keepSnapshots:r.keepSnapshots}:{},...r.snapshotMaxAgeDays!==void 0?{snapshotMaxAgeDays:r.snapshotMaxAgeDays}:{},...r.runtimeDays!==void 0?{runtimeDays:r.runtimeDays}:{},...r.staleLockMinutes!==void 0?{staleLockMinutes:r.staleLockMinutes}:{}})}function Ge(r){return r<1024?`${r} B`:r<1024*1024?`${(r/1024).toFixed(1)} KiB`:`${(r/1024/1024).toFixed(1)} MiB`}function Sr(r,e,t){if(console.log("ToolNet Memory GC"),console.log(`Project: ${r.projectRoot}`),console.log(`Mode: ${e?"APPLY":"DRY-RUN"}`),console.log(`Remote snapshots: ${t?"included":"not requested"}`),console.log(`Candidates: ${r.candidates.length}`),console.log(`Estimated local bytes: ${Ge(r.estimatedBytes)}`),r.candidates.length===0){console.log("Nothing eligible for garbage collection.");return}console.log("");for(let n of r.candidates){let o=n.ageMs===void 0?"":` age=${(n.ageMs/864e5).toFixed(1)}d`;console.log(`[${n.scope}] ${n.category} ${n.target}${o}`),console.log(` ${n.reason}`)}}async function Pr(r){let e=B(),t=ie(oe({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 xr(){let r=hr(process.argv.slice(2)),e=ge(r.project??process.cwd()),t=Er(r),n=r.includeRemote?await Pr(e):void 0,o=new A(e,t,{...n?{remoteStorage:n}:{}}),s=await o.plan(r.includeRemote);if(r.json){if(!r.apply){console.log(JSON.stringify({mode:"dry-run",plan:s},null,2));return}let c=await o.execute(s,!1);await Y(e,{action:"gc.manual",outcome:c.failed>0?"failed":"success",actor:{kind:"user",id:process.env.TOOLNET_AGENT_ID?.trim()||"cli"},details:{includeRemote:r.includeRemote,deleted:c.deleted,skipped:c.skipped,failed:c.failed,bytesFreed:c.bytesFreed}}),console.log(JSON.stringify({mode:"apply",plan:s,result:c},null,2)),c.failed>0&&(process.exitCode=1);return}if(Sr(s,r.apply,r.includeRemote),!r.apply){console.log(""),console.log("No data changed. Use --apply to execute this exact policy against a freshly re-planned state.");return}let i=await o.execute(s,!1);await Y(e,{action:"gc.manual",outcome:i.failed>0?"failed":"success",actor:{kind:"user",id:process.env.TOOLNET_AGENT_ID?.trim()||"cli"},details:{includeRemote:r.includeRemote,deleted:i.deleted,skipped:i.skipped,failed:i.failed,bytesFreed:i.bytesFreed}}),console.log(""),console.log(`Deleted: ${i.deleted}`),console.log(`Skipped: ${i.skipped}`),console.log(`Failed: ${i.failed}`),console.log(`Local bytes freed: ${Ge(i.bytesFreed)}`),i.failed>0&&(process.exitCode=1)}xr().catch(r=>{console.error(r instanceof Error?r.message:String(r)),process.exitCode=1});
@@ -1 +1 @@
1
- import{spawn as U}from"node:child_process";import{dirname as T,resolve as v}from"node:path";import{fileURLToPath as E}from"node:url";var h={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},C={spinner:[".","*","+","x","*","+"],barFilled:"#",barEmpty:"-",phaseDone:"[OK]",phaseActive:"[>>]",rail:"|",branch:"|",corner:"\\",dash:"-"};function b(){if(process.env.TOOLNET_ASCII==="1")return!1;if(process.env.TOOLNET_UNICODE==="1")return!0;if(process.platform==="win32"){let n=process.env.TERM_PROGRAM,r=process.env.WT_SESSION,e=process.env.VSCODE_PID,t=process.env.ConEmuPID;return!!(r||e||t||n==="vscode")}return process.env.TERM!=="linux"}var u;function a(){return u||(u=b()?h:C),u}var i={reset:"\x1B[0m",green:"\x1B[32m",cyan:"\x1B[36m",red:"\x1B[31m",yellow:"\x1B[33m",amber:"\x1B[38;5;214m",white:"\x1B[97m",dim:"\x1B[2m",bold:"\x1B[1m"};function x(n){return n.noColor||process.env.NO_COLOR?!1:n.tty??process.stdout.isTTY??!1}function l(n,r,e){return x(e)?`${r}${n}${i.reset}`:n}function c(n,r){return l(n,i.dim,r)}function g(n,r){return l(n,i.cyan,r)}function G(n,r){return l(n,i.green,r)}function y(n,r){return l(n,i.red,r)}function m(n,r,e){let t=a(),s=r?` ${c(`v${r}`,e)}`:"";return`${g(t.phaseDone,e)} ${n}${s}`}function d(n){let r=a();return G(r.phaseDone,n)}function O(n){return y("\u2717",n)}function S(n){return{tty:n.tty,noColor:n.noColor}}async function R(n){let r=S(n);console.log(""),console.log(m("Code Graph",void 0,r)),console.log("");let e=T(E(import.meta.url)),t=v(e,"graph-ui.js"),s=process.env.TOOLNET_GRAPH_PORT??"9749",f=process.env.TOOLNET_GRAPH_HOST??"127.0.0.1";console.log(c(" Starting visualization server...",r)),console.log("");let p=U(process.execPath,[t],{stdio:"inherit",env:{...process.env,TOOLNET_GRAPH_PORT:s,TOOLNET_GRAPH_HOST:f}});await new Promise(o=>setTimeout(o,1e3)),console.log(d(r)+" Graph UI started"),console.log(""),console.log(` ${g(`http://${f}:${s}`,r)}`),console.log(""),console.log(c(" Press Ctrl+C to stop",r)),console.log(""),process.on("SIGINT",()=>{p.kill("SIGTERM"),process.exit(0)}),process.on("SIGTERM",()=>{p.kill("SIGTERM"),process.exit(0)}),p.on("exit",o=>{o!==0&&o!==null&&(console.log(""),console.log(O(r)+" Graph UI stopped unexpectedly"),console.log(""),process.exit(o))})}async function $(){let n=process.argv.slice(2),r={tty:process.stdout.isTTY,noColor:process.env.NO_COLOR!==void 0||n.includes("--no-color")};await R(r)}$().catch(n=>{console.error(""),console.error(n instanceof Error?n.message:String(n)),console.error(""),process.exitCode=1});
1
+ import{spawn as A}from"node:child_process";import{dirname as H,resolve as S}from"node:path";import{fileURLToPath as N}from"node:url";var G=24;function C(n){return n.trim().toLowerCase().replace(/^\[/u,"").replace(/\]$/u,"")}function m(n){let r=C(n);return!!(r==="localhost"||r==="::1"||r==="0:0:0:0:0:0:0:1"||/^127(?:\.\d{1,3}){3}$/u.test(r)||r==="::ffff:127.0.0.1")}function h(n){return n?Buffer.byteLength(n,"utf8")>=G:!1}var y={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},T={spinner:[".","*","+","x","*","+"],barFilled:"#",barEmpty:"-",phaseDone:"[OK]",phaseActive:"[>>]",rail:"|",branch:"|",corner:"\\",dash:"-"};function U(){if(process.env.TOOLNET_ASCII==="1")return!1;if(process.env.TOOLNET_UNICODE==="1")return!0;if(process.platform==="win32"){let n=process.env.TERM_PROGRAM,r=process.env.WT_SESSION,e=process.env.VSCODE_PID,t=process.env.ConEmuPID;return!!(r||e||t||n==="vscode")}return process.env.TERM!=="linux"}var f;function g(){return f||(f=U()?y:T),f}var s={reset:"\x1B[0m",green:"\x1B[32m",cyan:"\x1B[36m",red:"\x1B[31m",yellow:"\x1B[33m",amber:"\x1B[38;5;214m",white:"\x1B[97m",dim:"\x1B[2m",bold:"\x1B[1m"};function E(n){return n.noColor||process.env.NO_COLOR?!1:n.tty??process.stdout.isTTY??!1}function l(n,r,e){return E(e)?`${r}${n}${s.reset}`:n}function u(n,r){return l(n,s.dim,r)}function d(n,r){return l(n,s.cyan,r)}function R(n,r){return l(n,s.green,r)}function w(n,r){return l(n,s.red,r)}function O(n,r,e){let t=g(),o=r?` ${u(`v${r}`,e)}`:"";return`${d(t.phaseDone,e)} ${n}${o}`}function b(n){let r=g();return R(r.phaseDone,n)}function x(n){return w("\u2717",n)}function v(n){return{tty:n.tty,noColor:n.noColor}}async function _(n){let r=v(n);console.log(""),console.log(O("Code Graph",void 0,r)),console.log("");let e=H(N(import.meta.url)),t=S(e,"graph-ui.js"),o=process.env.TOOLNET_GRAPH_PORT??"9749",c=process.env.TOOLNET_GRAPH_HOST??"127.0.0.1",a=process.env.TOOLNET_GRAPH_TOKEN?.trim();m(c)||(console.warn(` WARNING: Graph UI is exposed beyond localhost at ${c}:${o}`),a?console.warn(" Graph API bearer authentication: enabled"):(console.warn(" WARNING: Graph API bearer authentication: disabled"),console.warn(" Set TOOLNET_GRAPH_TOKEN before exposing this port to an untrusted network.")),console.log("")),a&&!h(a)&&(console.warn(" WARNING: TOOLNET_GRAPH_TOKEN should contain at least 24 random bytes."),console.log("")),console.log(u(" Starting visualization server...",r)),console.log("");let p=A(process.execPath,[t],{stdio:"inherit",env:{...process.env,TOOLNET_GRAPH_PORT:o,TOOLNET_GRAPH_HOST:c}});await new Promise(i=>setTimeout(i,1e3)),console.log(b(r)+" Graph UI started"),console.log(""),console.log(` ${d(`http://${c}:${o}`,r)}`),console.log(""),console.log(u(" Press Ctrl+C to stop",r)),console.log(""),process.on("SIGINT",()=>{p.kill("SIGTERM"),process.exit(0)}),process.on("SIGTERM",()=>{p.kill("SIGTERM"),process.exit(0)}),p.on("exit",i=>{i!==0&&i!==null&&(console.log(""),console.log(x(r)+" Graph UI stopped unexpectedly"),console.log(""),process.exit(i))})}async function $(){let n=process.argv.slice(2),r={tty:process.stdout.isTTY,noColor:process.env.NO_COLOR!==void 0||n.includes("--no-color")};await _(r)}$().catch(n=>{console.error(""),console.error(n instanceof Error?n.message:String(n)),console.error(""),process.exitCode=1});
@@ -1,4 +1,5 @@
1
- import"dotenv/config";import{existsSync as xe,readFileSync as Ce}from"node:fs";import{homedir as Ee}from"node:os";import{join as we}from"node:path";function ve(s){let e=s.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 ke(){let s=process.env.TOOLNET_GLOBAL_ENV??we(Ee(),".config","toolnet-memory",".env");if(!xe(s))return;let e=Ce(s,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let n=r.indexOf("=");if(n<=0)continue;let o=r.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=ve(r.slice(n+1)))}}ke();function M(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function T(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function Z(){return{memory:{autoCapture:M(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:M(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:M(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:M(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:T(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:T(process.env.MEMORY_RERANK_TOP,10),finalContext:T(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:T(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:M(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:T(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Pe}from"node:crypto";import{existsSync as _,mkdirSync as Re,readFileSync as Me,renameSync as Te,writeFileSync as Ae}from"node:fs";import{basename as je,dirname as F,join as A,parse as re,resolve as R}from"node:path";var se=".toolnet",Ie="project.json";function Le(s){return Pe("sha256").update(s).digest("hex").slice(0,16)}function D(s){return A(s,se,Ie)}function Ne(s){return _(D(s))}function Q(s,e){let t=R(s),r=re(t).root;for(;;){if(Ne(t))return t;if(t===r||e&&t===R(e))break;let n=F(t);if(n===t)break;t=n}return null}function X(s){let e=R(s),t=re(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>_(A(e,o))))return e;if(e===t)break;let n=F(e);if(n===e)break;e=n}return R(s)}function ee(s){let e;try{e=JSON.parse(Me(s,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${s}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${s}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${s}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${s}`);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:F(F(s)),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 te(s,e){let t=A(s,se);Re(t,{recursive:!0});let r=D(s),n=`${r}.tmp-${process.pid}`;Ae(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Te(n,r)}function H(s,e){return{id:s.id,name:s.name,remote:s.remote,rootPath:e,createdAt:s.createdAt,updatedAt:s.updatedAt,graphVersion:s.graphVersion,memoryVersion:s.memoryVersion,metadata:s.metadata}}var $=class{findExisting(e=process.cwd()){let t=R(e),r=X(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>_(A(r,p))),i=Q(t,o?r:void 0);if(!i)return null;let a=ee(D(i));return H(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=R(e),r=X(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>_(A(r,l))),i=Q(t,o?r:void 0);if(i){let l=D(i),u=ee(l);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),te(i,u)),H(u,i)}let a=new Date().toISOString(),p=je(r),c={version:1,id:Le(r),name:p,remote:p,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return te(r,c),H(c,r)}};var Oe=[{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"}],_e=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ne(s){return s.normalize("NFKC").trim().toLowerCase()}function Fe(s){if(s.length===0)return 0;let e=new Map;for(let r of s)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let n=r/s.length;t-=n*Math.log2(n)}return t}function De(s){return/^[a-f0-9]{32}$/iu.test(s)||/^[a-f0-9]{40}$/iu.test(s)||/^[a-f0-9]{64}$/iu.test(s)}function $e(s,e,t){let r=s.slice(Math.max(0,e-48),e),n=s.slice(t,Math.min(s.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${n}`)}function Ge(s,e){return s.start<e.end&&e.start<s.end}function oe(s){return s.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var G=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=ne(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of Oe){let i=new RegExp(o.regex.source,o.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:o.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=oe(t),n=[];for(let o of r)n.some(i=>Ge(i,o))||n.push(o);return oe(n)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ne(e);return _e.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let n of e.matchAll(r)){if(n.index===void 0||!n[0])continue;let o=n[0];this.allowed(o)||De(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||$e(e,n.index,n.index+o.length)&&(Fe(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:n.index,end:n.index+o.length,confidence:"heuristic"}))}return t}};var j=class{scanner;constructor(e={}){this.scanner=new G(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,n=[...t].sort((i,a)=>a.start-i.start),o=new Set;for(let i of n)o.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...o].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,n]of Object.entries(e)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(n)}return t}return e}};var nr=new j;import{lstat as We,readdir as Ue}from"node:fs/promises";import{extname as He,join as Ve,relative as Ye,resolve as Je}from"node:path";import{basename as ze}from"node:path";var Ke=new Set([".env",".env.local",".env.production",".env.development","id_rsa","id_ed25519","credentials","credentials.json","service-account.json"]),Be=new Set([".pem",".key",".p12",".pfx"]);function ie(s){let e=ze(s).toLowerCase();if(Ke.has(e))return!0;for(let t of Be)if(e.endsWith(t))return!0;return!1}var qe=2*1024*1024,Ze=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),Qe=new Set(["node_modules",".git",".toolnet",".toolnet-memory","dist","build","out","coverage",".next",".nuxt",".cache",".parcel-cache",".turbo","vendor","target"]);function ae(s,e){if(!Number.isSafeInteger(s)||s<1)throw new Error(`${e} must be a positive integer`);return s}function ce(s){if(s?.aborted)throw new Error("Repository scan aborted")}function Xe(s){let e=s.trim().toLowerCase();if(!e)throw new Error("Repository scan extension cannot be empty");return e.startsWith(".")?e:`.${e}`}function et(s){let e=s.toLowerCase();return/\.min\.(?:js|mjs|cjs)$/u.test(e)||/\.bundle\.(?:js|mjs|cjs)$/u.test(e)}function tt(s){return s.replaceAll("\\","/")}async function le(s,e={}){let t=Je(s),r=e.maxFileBytes??qe;if(!Number.isSafeInteger(r)||r<1)throw new Error("maxFileBytes must be a positive integer");let n=e.maxFiles??Number.MAX_SAFE_INTEGER;ae(n,"maxFiles");let o=e.progressInterval??1e3;ae(o,"progressInterval");let i=new Set(e.extensions?[...e.extensions].map(Xe):Ze),a=new Set(Qe);for(let u of e.extraIgnoredDirectories??[]){let f=u.trim();f&&a.add(f)}let p=[],c={directories:0,entries:0,accepted:0,skippedIgnoredDirectories:0,skippedSymlinks:0,skippedGenerated:0,skippedSensitive:0,skippedOversized:0,skippedUnreadable:0},l=[t];for(;l.length>0;){ce(e.signal);let u=l.pop(),f;try{f=await Ue(u,{withFileTypes:!0})}catch{c.skippedUnreadable+=1;continue}c.directories+=1;for(let h of f){ce(e.signal),c.entries+=1,c.entries%o===0&&e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted});let C=Ve(u,h.name);if(h.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(h.isDirectory()){if(a.has(h.name)){c.skippedIgnoredDirectories+=1;continue}l.push(C);continue}if(!h.isFile())continue;let k=He(h.name).toLowerCase();if(!i.has(k))continue;if(et(h.name)){c.skippedGenerated+=1;continue}if(ie(C)){c.skippedSensitive+=1;continue}let P;try{P=await We(C)}catch{c.skippedUnreadable+=1;continue}if(P.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(P.isFile()){if(P.size>r){c.skippedOversized+=1;continue}if(p.length>=n)throw new Error(`Repository scan file limit exceeded: ${n}`);p.push(tt(Ye(t,C))),c.accepted+=1}}}return p.sort(),e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted}),{files:p,stats:c}}import{createHash as rt}from"node:crypto";import{dirname as st,extname as nt,normalize as ot,posix as it}from"node:path";var z=class{symbols=new Map;edges=new Map;addSymbol(e){this.symbols.set(e.id,e)}addEdge(e){this.edges.set(e.id,e)}getSymbol(e){return this.symbols.get(e)}findByName(e,t){return[...this.symbols.values()].filter(r=>r.projectId===e&&(r.name===t||r.qualifiedName===t))}allSymbols(e){return[...this.symbols.values()].filter(t=>t.projectId===e)}allEdges(e){return[...this.edges.values()].filter(t=>t.projectId===e)}import(e,t){for(let r of e)this.addSymbol(r);for(let r of t)this.addEdge(r)}clearProject(e){for(let[t,r]of this.symbols)r.projectId===e&&this.symbols.delete(t);for(let[t,r]of this.edges)r.projectId===e&&this.edges.delete(t)}};function at(s,e,t,r){return rt("sha256").update(`${s}:${e}:${t}:${r}`).digest("hex").slice(0,24)}function E(s){return ot(s).replaceAll("\\","/")}function ct(s,e,t){if(!e.startsWith("."))return;let r=E(it.join(st(s),e)),n=nt(r),o;if(n===".js"){let i=r.slice(0,-3);o=[`${i}.ts`,`${i}.tsx`,`${i}.js`,`${i}.jsx`]}else if(n===".mjs"){let i=r.slice(0,-4);o=[`${i}.mts`,`${i}.ts`,`${i}.mjs`]}else if(n===".cjs"){let i=r.slice(0,-4);o=[`${i}.cts`,`${i}.ts`,`${i}.cjs`]}else n?o=[r]:o=[`${r}.ts`,`${r}.tsx`,`${r}.mts`,`${r}.cts`,`${r}.js`,`${r}.jsx`,`${r}.mjs`,`${r}.cjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.mts`,`${r}/index.cts`,`${r}/index.js`,`${r}/index.jsx`,`${r}/index.mjs`,`${r}/index.cjs`];return o.find(i=>t.has(E(i)))}function V(s,e,t,r){let n=r?.(s,e,t);if(n){let o=E(n);if(t.has(o))return o}return ct(s,e,t)}var I=class{build(e,t,r={}){let n=new z;for(let a of r.seedSymbols??[])n.addSymbol(a);for(let a of t)for(let p of a.symbols)n.addSymbol(p);let o=new Map;for(let a of n.allSymbols(e))a.type==="file"&&o.set(E(a.filePath),a);let i=new Set(o.keys());for(let a of t){let p=E(a.filePath),c=o.get(p);if(c){for(let l of a.symbols)l.id!==c.id&&n.addEdge(this.edge(e,c.id,"DEFINES",l.id));for(let l of a.imports){let u=V(p,l.source,i,r.resolveModule);if(!u)continue;let f=o.get(u);f&&n.addEdge(this.edge(e,c.id,"IMPORTS",f.id,{source:l.source,resolvedFile:u}))}for(let l of a.heritage){let u=n.findByName(e,l.targetName).filter(f=>f.type==="class"||f.type==="interface");for(let f of u)n.addEdge(this.edge(e,l.fromId,l.type,f.id))}for(let l of a.calls){if(!l.callerId)continue;let u=this.resolveCallTargets(e,a,l.calleeName,l.qualifier,n,i,r.resolveModule);for(let f of u)f.id!==l.callerId&&n.addEdge(this.edge(e,l.callerId,"CALLS",f.id,{line:l.line,qualifier:l.qualifier}))}}}return n}resolveCallTargets(e,t,r,n,o,i,a){let p=E(t.filePath),c=o.findByName(e,r).filter(l=>E(l.filePath)===p);if(!n&&c.length)return c;if(n)for(let l of t.imports){if(!l.bindings.find(h=>h.kind==="namespace"&&h.localName===n))continue;let f=V(p,l.source,i,a);if(f)return o.findByName(e,r).filter(h=>E(h.filePath)===f)}for(let l of t.imports){let u=l.bindings.find(k=>k.localName===r);if(!u)continue;let f=V(p,l.source,i,a);if(!f)continue;let h=u.importedName==="default"?r:u.importedName,C=o.findByName(e,h).filter(k=>E(k.filePath)===f);if(C.length)return C}return o.findByName(e,r).filter(l=>l.type==="function"||l.type==="method")}edge(e,t,r,n,o){return{id:at(e,t,r,n),projectId:e,from:t,to:n,type:r,metadata:o}}};import{readFile as lt}from"node:fs/promises";import{join as dt}from"node:path";import{createHash as pt}from"node:crypto";import*as m from"typescript";function de(s,e){return pt("sha256").update(`${s}:${e}`).digest("hex").slice(0,24)}function Y(s,e){return s.getLineAndCharacterOfPosition(e.getStart(s)).line+1}async function J(s,e,t){let r=dt(e,t),n=await lt(r,"utf8"),o=m.createSourceFile(t,n,m.ScriptTarget.Latest,!0,t.endsWith(".tsx")||t.endsWith(".jsx")?m.ScriptKind.TSX:m.ScriptKind.TS),i=[],a=[],p=[],c=[],l={id:de(s,`file:${t}`),projectId:s,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:o.getLineAndCharacterOfPosition(o.end).line+1};i.push(l);let u=[],f=[];function h(d,b,S,y){let w=de(s,`${t}:${S}:${y??b}:${d.pos}`);return i.push({id:w,projectId:s,name:b,qualifiedName:y??b,type:S,filePath:t,startLine:Y(o,d),endLine:o.getLineAndCharacterOfPosition(d.end).line+1}),w}function C(d){if(!m.isStringLiteral(d.moduleSpecifier))return;let b=[],S=d.importClause;if(S?.name&&b.push({localName:S.name.text,importedName:"default",kind:"default"}),S?.namedBindings&&m.isNamedImports(S.namedBindings))for(let y of S.namedBindings.elements)b.push({localName:y.name.text,importedName:y.propertyName?.text??y.name.text,kind:"named"});S?.namedBindings&&m.isNamespaceImport(S.namedBindings)&&b.push({localName:S.namedBindings.name.text,importedName:"*",kind:"namespace"}),a.push({source:d.moduleSpecifier.text,bindings:b})}function k(d,b){for(let S of d.heritageClauses??[])for(let y of S.types){let w=y.expression.getText(o).split(".").at(-1)??"";w&&c.push({fromId:b,targetName:w,type:S.token===m.SyntaxKind.ExtendsKeyword?"INHERITS":"IMPLEMENTS"})}}function P(d){let b=!1,S=!1;if(m.isImportDeclaration(d)&&C(d),m.isInterfaceDeclaration(d)&&h(d,d.name.text,"interface",d.name.text),m.isClassDeclaration(d)&&d.name){let y=h(d,d.name.text,"class",d.name.text);k(d,y),f.push({id:y,name:d.name.text}),S=!0}if(m.isFunctionDeclaration(d)&&d.name){let y=h(d,d.name.text,"function",d.name.text);u.push(y),b=!0}if(m.isMethodDeclaration(d)&&d.name){let y=d.name.getText(o),w=f.at(-1)?.name,be=h(d,y,"method",w?`${w}.${y}`:y);u.push(be),b=!0}if(m.isCallExpression(d)&&(m.isIdentifier(d.expression)&&p.push({callerId:u.at(-1),calleeName:d.expression.text,line:Y(o,d)}),m.isPropertyAccessExpression(d.expression))){let y=d.expression;p.push({callerId:u.at(-1),qualifier:y.expression.getText(o),calleeName:y.name.text,line:Y(o,d)})}m.forEachChild(d,P),b&&u.pop(),S&&f.pop()}return P(o),{filePath:t,symbols:i,imports:a,calls:p,heritage:c}}function ut(s){let e=s??4;if(!Number.isSafeInteger(e)||e<1||e>64)throw new Error("concurrency must be an integer between 1 and 64");return e}function ft(s){if(s?.aborted)throw new Error("Operation aborted")}async function K(s,e,t={}){if(s.length===0)return[];let r=Math.min(ut(t.concurrency),s.length),n=new Array(s.length),o=0,i=0,a=async()=>{for(;;){ft(t.signal);let c=o;if(o+=1,c>=s.length)return;n[c]=await e(s[c],c),i+=1,t.onProgress?.({completed:i,total:s.length,index:c})}},p=Array.from({length:r},()=>a());return await Promise.all(p),n}var B=class{async index(e,t,r={}){let n={...r.scan};r.signal&&(n.signal=r.signal);let o=await le(t,n),i=o.files;r.onProgress?.({phase:"scan",current:i.length,total:i.length});let a=r.maxWarnings??20;if(!Number.isSafeInteger(a)||a<0)throw new Error("maxWarnings must be a non-negative integer");let p=0,c=await K(i,async f=>{try{return await J(e,t,f)}catch(h){return p+=1,p<=a&&console.warn(`[indexer] skipped ${f}:`,h instanceof Error?h.message:h),null}},{concurrency:r.concurrency??4,signal:r.signal,onProgress:({completed:f,total:h,index:C})=>{r.onProgress?.({phase:"parse",current:f,total:h,file:i[C]})}});p>a&&console.warn(`[indexer] ${p-a} additional parse warnings suppressed`);let l=c.filter(f=>f!==null),u=new I().build(e,l);return{files:l.length,symbols:u.allSymbols(e).length,edges:u.allEdges(e).length,parseFailures:p,scan:o.stats,graph:u}}};function ue(s,e){let t=s.allSymbols(e),r=s.allEdges(e),n=i=>t.filter(a=>a.type===i).length,o=i=>r.filter(a=>a.type===i).length;return{files:n("file"),classes:n("class"),interfaces:n("interface"),functions:n("function"),methods:n("method"),properties:n("property"),routes:n("route"),symbols:t.length,edges:r.length,calls:o("CALLS"),callReferences:o("CALL_REFERENCE"),imports:o("IMPORTS"),inherits:o("INHERITS"),implements:o("IMPLEMENTS"),usesType:o("USES_TYPE"),tests:o("TESTS"),routeEdges:o("ROUTE"),writes:o("WRITES")}}import{execFile as mt}from"node:child_process";import{promisify as gt}from"node:util";var ps=gt(mt);var L=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")}};import*as v from"typescript";import{DatabaseSync as an}from"node:sqlite";import*as x from"typescript";import*as g from"typescript";var Tn=new Set([g.SyntaxKind.EqualsToken,g.SyntaxKind.PlusEqualsToken,g.SyntaxKind.MinusEqualsToken,g.SyntaxKind.AsteriskEqualsToken,g.SyntaxKind.SlashEqualsToken,g.SyntaxKind.PercentEqualsToken,g.SyntaxKind.QuestionQuestionEqualsToken,g.SyntaxKind.AmpersandAmpersandEqualsToken,g.SyntaxKind.BarBarEqualsToken]);import{homedir as Gt}from"node:os";import{join as zt}from"node:path";import{DeleteObjectCommand as St,GetObjectCommand as bt,HeadObjectCommand as xt,ListObjectsV2Command as Ct,PutObjectCommand as Et,S3Client as wt}from"@aws-sdk/client-s3";import{getSignedUrl as vt}from"@aws-sdk/s3-request-presigner";var W=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new wt({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Et({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await vt(this.client,new bt({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new 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 St({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new Ct({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of n.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};import{access as fe,mkdir as kt,readFile as Pt,readdir as Rt,rm as Mt,stat as me,writeFile as Tt}from"node:fs/promises";import{dirname as At,join as jt,relative as ge,resolve as It}from"node:path";var N=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return It(this.root,t)}async put(e,t){let r=this.path(e);await kt(At(r),{recursive:!0}),await Tt(r,t)}async get(e){try{return await Pt(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 fe(this.path(e)),!0}catch{return!1}}async delete(e){await Mt(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await fe(t)}catch{return r}let n=async i=>{let a=await Rt(i,{withFileTypes:!0});for(let p of a){let c=jt(i,p.name);if(p.isDirectory()){await n(c);continue}let l=await me(c);r.push({key:ge(this.root,c),size:l.size,updatedAt:l.mtime.toISOString()})}},o=await me(t);return o.isDirectory()?await n(t):r.push({key:ge(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as Lt,GetObjectCommand as Nt,HeadObjectCommand as Ot,ListObjectsV2Command as _t,PutObjectCommand as Ft,S3Client as Dt}from"@aws-sdk/client-s3";import{getSignedUrl as $t}from"@aws-sdk/s3-request-presigner";var O=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Dt({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ft({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await $t(this.client,new Nt({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Ot({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Lt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new _t({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of n.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};function q(s,e){return console.warn(e),new N(s)}function he(s){let e=s.localRoot??zt(Gt(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new O({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):q(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(s.provider==="s3"){let t=s.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new O({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):q(e,"[storage] S3 credentials missing. Using local fallback.")}if(s.provider==="huggingface"){let t=s.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new W({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):q(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new N(e)}function ye(s){let e=s.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 Se(s){let e=s.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var U=class{constructor(e,t,r,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=ye(n??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,n=await this.provider.getText(e);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(o,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Se(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,r){return await this.ensureRegistered(),this.provider.put(this.key(e),t,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};async function Kt(){let s=Z(),e=new $().detect(),t=he({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),r=new U(t,e.id,e.name,e.remote??e.name),n=await new B().index(e.id,e.rootPath),o=ue(n.graph,e.id);await new L(r).save({version:1,projectId:e.id,updatedAt:new Date().toISOString(),files:n.files,symbols:n.graph.allSymbols(e.id),edges:n.graph.allEdges(e.id)}),console.log({ok:!0,storage:r.name,...o})}Kt().catch(s=>{console.error(s),process.exit(1)});
1
+ import"dotenv/config";import{existsSync as st,readFileSync as ot}from"node:fs";import{homedir as it}from"node:os";import{join as at}from"node:path";function ct(n){let e=n.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 lt(){let n=process.env.TOOLNET_GLOBAL_ENV??at(it(),".config","toolnet-memory",".env");if(!st(n))return;let e=ot(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=ct(r.slice(s+1)))}}lt();function _(n,e){return n===void 0?e:["1","true","yes","on"].includes(n.toLowerCase())}function O(n,e){if(!n)return e;let t=Number(n);return Number.isFinite(t)?t:e}function ye(){return{memory:{autoCapture:_(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:_(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:_(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:_(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:O(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:O(process.env.MEMORY_RERANK_TOP,10),finalContext:O(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:O(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:_(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:O(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ht}from"node:crypto";import{existsSync as q,mkdirSync as yt,readFileSync as St,renameSync as bt,writeFileSync as xt}from"node:fs";import{basename as Et,dirname as J,join as F,parse as ve,resolve as M}from"node:path";import{createHash as xe}from"node:crypto";import{spawnSync as dt}from"node:child_process";var j="git-remote-v1",pt=new Set(["github.com","gitlab.com","bitbucket.org"]);function Ee(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:(pt.has(n)&&(t=t.toLowerCase()),t)}function ut(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",s=e.port&&!r?`${t}:${e.port}`:t,o=Ee(t,e.pathname);return o?`${s}/${o}`:null}function ft(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=Ee(t,e[2]??"");return r?`${t}/${r}`:null}function Se(n){let e=n.trim();return e?e.includes("://")?ut(e):ft(e):null}function mt(n){return xe("sha256").update(`${j}:${n}`).digest("hex")}function Ce(n){return xe("sha256").update(`toolnet-project:${j}:${n}`).digest("hex").slice(0,16)}function gt(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function se(n,e){let t=dt("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function be(n,e){let t=gt(n);return t?{scheme:j,canonicalRemote:n,fingerprint:mt(n),repositoryName:t,source:e}:null}function we(n){let e=se(n,["remote","get-url","origin"]);if(e){let s=Se(e);if(s)return be(s,"origin")}let t=se(n,["remote"]);if(!t)return null;let r=new Set;for(let s of t.split(/\r?\n/u).map(o=>o.trim()).filter(Boolean)){let o=se(n,["remote","get-url",s]);if(!o)continue;let i=Se(o);i&&r.add(i)}return r.size!==1?null:be([...r][0],"unique-remote")}var Pe=".toolnet",Ct="project.json";function wt(n){return ht("sha256").update(n).digest("hex").slice(0,16)}function N(n){return F(n,Pe,Ct)}function ke(n){return q(N(n))}function Re(n,e){let t=M(n),r=ve(t).root;for(;;){if(ke(t))return t;if(t===r||e&&t===M(e))break;let s=J(t);if(s===t)break;t=s}return null}function oe(n){let e=M(n),t=ve(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>q(F(e,o))))return e;if(e===t)break;let s=J(e);if(s===e)break;e=s}return M(n)}function Y(n){let e;try{e=JSON.parse(St(n,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${n}: ${s instanceof Error?s.message:String(s)}`)}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:J(J(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 V(n,e){let t=F(n,Pe);yt(t,{recursive:!0});let r=N(n),s=`${r}.tmp-${process.pid}`;xt(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),bt(s,r)}function A(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 ie(n){return{version:1,scheme:j,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function Rt(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 Q=class{adopt(e,t){let r=oe(M(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(ke(r)){let a=Y(N(r));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return A(a,r)}let s=new Date().toISOString(),o={...t.metadata};t.gitIdentity&&(o.toolnetIdentity=ie(t.gitIdentity));let i={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:r,createdAt:t.createdAt??s,updatedAt:s,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(o).length?o:void 0};return V(r,i),A(i,r)}recordGitIdentity(e,t,r={}){let s=this.requireExisting(e),o=N(s.rootPath),i=Y(o),a=Rt(i);if(a&&a!==t.fingerprint&&!r.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 l=i.metadata?.toolnetIdentity;return l&&typeof l=="object"&&!Array.isArray(l)&&l.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:ie(t)},i.updatedAt=new Date().toISOString(),V(s.rootPath,i)),A(i,s.rootPath)}findExisting(e=process.cwd()){let t=M(e),r=oe(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>q(F(r,l))),i=Re(t,o?r:void 0);if(!i)return null;let a=Y(N(i));return A(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=M(e),r=oe(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>q(F(r,f))),i=Re(t,o?r:void 0);if(i){let f=N(i),u=Y(f);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),V(i,u)),A(u,i)}let a=new Date().toISOString(),l=Et(r),c=we(r),d={version:1,id:c?Ce(c.canonicalRemote):wt(r),name:l,remote:c?.repositoryName??l,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:c?{toolnetIdentity:ie(c)}:void 0};return V(r,d),A(d,r)}};var vt=[{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"}],Pt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function Te(n){return n.normalize("NFKC").trim().toLowerCase()}function kt(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 s=r/n.length;t-=s*Math.log2(s)}return t}function Tt(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function At(n,e,t){let r=n.slice(Math.max(0,e-48),e),s=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} ${s}`)}function Mt(n,e){return n.start<e.end&&e.start<n.end}function Ae(n){return n.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var Z=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=Te(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of vt){let i=new RegExp(o.regex.source,o.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:o.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=Ae(t),s=[];for(let o of r)s.some(i=>Mt(i,o))||s.push(o);return Ae(s)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=Te(e);return Pt.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let s of e.matchAll(r)){if(s.index===void 0||!s[0])continue;let o=s[0];this.allowed(o)||Tt(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||At(e,s.index,s.index+o.length)&&(kt(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return t}};var D=class{scanner;constructor(e={}){this.scanner=new Z(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,s=[...t].sort((i,a)=>a.start-i.start),o=new Set;for(let i of s)o.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...o].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,s]of Object.entries(e)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(s)}return t}return e}};var bn=new D;import{lstat as _t,readdir as Ot}from"node:fs/promises";import{extname as jt,join as Ft,relative as Dt,resolve as $t}from"node:path";import{basename as It}from"node:path";var Nt=new Set([".env",".env.local",".env.production",".env.development","id_rsa","id_ed25519","credentials","credentials.json","service-account.json"]),Lt=new Set([".pem",".key",".p12",".pfx"]);function Me(n){let e=It(n).toLowerCase();if(Nt.has(e))return!0;for(let t of Lt)if(e.endsWith(t))return!0;return!1}var Gt=2*1024*1024,Kt=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),Bt=new Set(["node_modules",".git",".toolnet",".toolnet-memory","dist","build","out","coverage",".next",".nuxt",".cache",".parcel-cache",".turbo","vendor","target"]);function Ie(n,e){if(!Number.isSafeInteger(n)||n<1)throw new Error(`${e} must be a positive integer`);return n}function Ne(n){if(n?.aborted)throw new Error("Repository scan aborted")}function zt(n){let e=n.trim().toLowerCase();if(!e)throw new Error("Repository scan extension cannot be empty");return e.startsWith(".")?e:`.${e}`}function Ut(n){let e=n.toLowerCase();return/\.min\.(?:js|mjs|cjs)$/u.test(e)||/\.bundle\.(?:js|mjs|cjs)$/u.test(e)}function Ht(n){return n.replaceAll("\\","/")}async function Le(n,e={}){let t=$t(n),r=e.maxFileBytes??Gt;if(!Number.isSafeInteger(r)||r<1)throw new Error("maxFileBytes must be a positive integer");let s=e.maxFiles??Number.MAX_SAFE_INTEGER;Ie(s,"maxFiles");let o=e.progressInterval??1e3;Ie(o,"progressInterval");let i=new Set(e.extensions?[...e.extensions].map(zt):Kt),a=new Set(Bt);for(let f of e.extraIgnoredDirectories??[]){let u=f.trim();u&&a.add(u)}let l=[],c={directories:0,entries:0,accepted:0,skippedIgnoredDirectories:0,skippedSymlinks:0,skippedGenerated:0,skippedSensitive:0,skippedOversized:0,skippedUnreadable:0},d=[t];for(;d.length>0;){Ne(e.signal);let f=d.pop(),u;try{u=await Ot(f,{withFileTypes:!0})}catch{c.skippedUnreadable+=1;continue}c.directories+=1;for(let h of u){Ne(e.signal),c.entries+=1,c.entries%o===0&&e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted});let C=Ft(f,h.name);if(h.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(h.isDirectory()){if(a.has(h.name)){c.skippedIgnoredDirectories+=1;continue}d.push(C);continue}if(!h.isFile())continue;let k=jt(h.name).toLowerCase();if(!i.has(k))continue;if(Ut(h.name)){c.skippedGenerated+=1;continue}if(Me(C)){c.skippedSensitive+=1;continue}let T;try{T=await _t(C)}catch{c.skippedUnreadable+=1;continue}if(T.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(T.isFile()){if(T.size>r){c.skippedOversized+=1;continue}if(l.length>=s)throw new Error(`Repository scan file limit exceeded: ${s}`);l.push(Ht(Dt(t,C))),c.accepted+=1}}}return l.sort(),e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted}),{files:l,stats:c}}import{createHash as Wt}from"node:crypto";import{dirname as Yt,extname as Vt,normalize as qt,posix as Jt}from"node:path";var X=class{symbols=new Map;edges=new Map;addSymbol(e){this.symbols.set(e.id,e)}addEdge(e){this.edges.set(e.id,e)}getSymbol(e){return this.symbols.get(e)}findByName(e,t){return[...this.symbols.values()].filter(r=>r.projectId===e&&(r.name===t||r.qualifiedName===t))}allSymbols(e){return[...this.symbols.values()].filter(t=>t.projectId===e)}allEdges(e){return[...this.edges.values()].filter(t=>t.projectId===e)}import(e,t){for(let r of e)this.addSymbol(r);for(let r of t)this.addEdge(r)}clearProject(e){for(let[t,r]of this.symbols)r.projectId===e&&this.symbols.delete(t);for(let[t,r]of this.edges)r.projectId===e&&this.edges.delete(t)}};function Qt(n,e,t,r){return Wt("sha256").update(`${n}:${e}:${t}:${r}`).digest("hex").slice(0,24)}function w(n){return qt(n).replaceAll("\\","/")}function Zt(n,e,t){if(!e.startsWith("."))return;let r=w(Jt.join(Yt(n),e)),s=Vt(r),o;if(s===".js"){let i=r.slice(0,-3);o=[`${i}.ts`,`${i}.tsx`,`${i}.js`,`${i}.jsx`]}else if(s===".mjs"){let i=r.slice(0,-4);o=[`${i}.mts`,`${i}.ts`,`${i}.mjs`]}else if(s===".cjs"){let i=r.slice(0,-4);o=[`${i}.cts`,`${i}.ts`,`${i}.cjs`]}else s?o=[r]:o=[`${r}.ts`,`${r}.tsx`,`${r}.mts`,`${r}.cts`,`${r}.js`,`${r}.jsx`,`${r}.mjs`,`${r}.cjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.mts`,`${r}/index.cts`,`${r}/index.js`,`${r}/index.jsx`,`${r}/index.mjs`,`${r}/index.cjs`];return o.find(i=>t.has(w(i)))}function ae(n,e,t,r){let s=r?.(n,e,t);if(s){let o=w(s);if(t.has(o))return o}return Zt(n,e,t)}var $=class{build(e,t,r={}){let s=new X;for(let a of r.seedSymbols??[])s.addSymbol(a);for(let a of t)for(let l of a.symbols)s.addSymbol(l);let o=new Map;for(let a of s.allSymbols(e))a.type==="file"&&o.set(w(a.filePath),a);let i=new Set(o.keys());for(let a of t){let l=w(a.filePath),c=o.get(l);if(c){for(let d of a.symbols)d.id!==c.id&&s.addEdge(this.edge(e,c.id,"DEFINES",d.id));for(let d of a.imports){let f=ae(l,d.source,i,r.resolveModule);if(!f)continue;let u=o.get(f);u&&s.addEdge(this.edge(e,c.id,"IMPORTS",u.id,{source:d.source,resolvedFile:f}))}for(let d of a.heritage){let f=s.findByName(e,d.targetName).filter(u=>u.type==="class"||u.type==="interface");for(let u of f)s.addEdge(this.edge(e,d.fromId,d.type,u.id))}for(let d of a.calls){if(!d.callerId)continue;let f=this.resolveCallTargets(e,a,d.calleeName,d.qualifier,s,i,r.resolveModule);for(let u of f)u.id!==d.callerId&&s.addEdge(this.edge(e,d.callerId,"CALLS",u.id,{line:d.line,qualifier:d.qualifier}))}}}return s}resolveCallTargets(e,t,r,s,o,i,a){let l=w(t.filePath),c=o.findByName(e,r).filter(d=>w(d.filePath)===l);if(!s&&c.length)return c;if(s)for(let d of t.imports){if(!d.bindings.find(h=>h.kind==="namespace"&&h.localName===s))continue;let u=ae(l,d.source,i,a);if(u)return o.findByName(e,r).filter(h=>w(h.filePath)===u)}for(let d of t.imports){let f=d.bindings.find(k=>k.localName===r);if(!f)continue;let u=ae(l,d.source,i,a);if(!u)continue;let h=f.importedName==="default"?r:f.importedName,C=o.findByName(e,h).filter(k=>w(k.filePath)===u);if(C.length)return C}return o.findByName(e,r).filter(d=>d.type==="function"||d.type==="method")}edge(e,t,r,s,o){return{id:Qt(e,t,r,s),projectId:e,from:t,to:s,type:r,metadata:o}}};import{createHash as nr}from"node:crypto";import{readFile as sr}from"node:fs/promises";import{join as or}from"node:path";import{extname as Xt}from"node:path";var v={supported:!0,structural:!0,lexicalSearch:!0,engine:"typescript-compiler-api",lexicalEngine:"file-chunk-fts5-bm25"},G={supported:!1,structural:!1,lexicalSearch:!0,engine:"unsupported",lexicalEngine:"file-chunk-fts5-bm25"},L=[{language:"typescript",extensions:[".ts"],...v},{language:"tsx",extensions:[".tsx"],...v},{language:"javascript",extensions:[".js"],...v},{language:"jsx",extensions:[".jsx"],...v},{language:"mts",extensions:[".mts"],...v},{language:"cts",extensions:[".cts"],...v},{language:"mjs",extensions:[".mjs"],...v},{language:"cjs",extensions:[".cjs"],...v},{language:"python",extensions:[".py"],...G,lspServer:"pyright-langserver"},{language:"go",extensions:[".go"],...G,lspServer:"gopls"},{language:"rust",extensions:[".rs"],...G,lspServer:"rust-analyzer"},{language:"c",extensions:[".c",".h"],...G,lspServer:"clangd"},{language:"cpp",extensions:[".cc",".cpp",".cxx",".hpp",".hh"],...G,lspServer:"clangd"}];function ce(n){let e=Xt(n).toLowerCase();return L.find(t=>t.extensions.includes(e))}function _e(){return[...new Set(L.filter(n=>n.lexicalSearch).flatMap(n=>n.extensions))]}import{readFile as er}from"node:fs/promises";import{join as tr}from"node:path";import{createHash as rr}from"node:crypto";import*as m from"typescript";function Oe(n,e){return rr("sha256").update(`${n}:${e}`).digest("hex").slice(0,24)}function le(n,e){return n.getLineAndCharacterOfPosition(e.getStart(n)).line+1}async function de(n,e,t){let r=tr(e,t),s=await er(r,"utf8"),o=m.createSourceFile(t,s,m.ScriptTarget.Latest,!0,t.endsWith(".tsx")||t.endsWith(".jsx")?m.ScriptKind.TSX:m.ScriptKind.TS),i=[],a=[],l=[],c=[],d={id:Oe(n,`file:${t}`),projectId:n,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:o.getLineAndCharacterOfPosition(o.end).line+1};i.push(d);let f=[],u=[];function h(p,x,b,y){let R=Oe(n,`${t}:${b}:${y??x}:${p.pos}`);return i.push({id:R,projectId:n,name:x,qualifiedName:y??x,type:b,filePath:t,startLine:le(o,p),endLine:o.getLineAndCharacterOfPosition(p.end).line+1}),R}function C(p){if(!m.isStringLiteral(p.moduleSpecifier))return;let x=[],b=p.importClause;if(b?.name&&x.push({localName:b.name.text,importedName:"default",kind:"default"}),b?.namedBindings&&m.isNamedImports(b.namedBindings))for(let y of b.namedBindings.elements)x.push({localName:y.name.text,importedName:y.propertyName?.text??y.name.text,kind:"named"});b?.namedBindings&&m.isNamespaceImport(b.namedBindings)&&x.push({localName:b.namedBindings.name.text,importedName:"*",kind:"namespace"}),a.push({source:p.moduleSpecifier.text,bindings:x})}function k(p,x){for(let b of p.heritageClauses??[])for(let y of b.types){let R=y.expression.getText(o).split(".").at(-1)??"";R&&c.push({fromId:x,targetName:R,type:b.token===m.SyntaxKind.ExtendsKeyword?"INHERITS":"IMPLEMENTS"})}}function T(p){let x=!1,b=!1;if(m.isImportDeclaration(p)&&C(p),m.isInterfaceDeclaration(p)&&h(p,p.name.text,"interface",p.name.text),m.isClassDeclaration(p)&&p.name){let y=h(p,p.name.text,"class",p.name.text);k(p,y),u.push({id:y,name:p.name.text}),b=!0}if(m.isFunctionDeclaration(p)&&p.name){let y=h(p,p.name.text,"function",p.name.text);f.push(y),x=!0}if(m.isMethodDeclaration(p)&&p.name){let y=p.name.getText(o),R=u.at(-1)?.name,nt=h(p,y,"method",R?`${R}.${y}`:y);f.push(nt),x=!0}if(m.isCallExpression(p)&&(m.isIdentifier(p.expression)&&l.push({callerId:f.at(-1),calleeName:p.expression.text,line:le(o,p)}),m.isPropertyAccessExpression(p.expression))){let y=p.expression;l.push({callerId:f.at(-1),qualifier:y.expression.getText(o),calleeName:y.name.text,line:le(o,p)})}m.forEachChild(p,T),x&&f.pop(),b&&u.pop()}return T(o),{filePath:t,symbols:i,imports:a,calls:l,heritage:c}}function ir(n,e){return nr("sha256").update(`${n}:${e}`).digest("hex").slice(0,24)}async function ar(n,e,t){let r=ce(t);if(!r||!r.lexicalSearch)throw new Error(`Unsupported code file: ${t}`);let s=await sr(or(e,t),"utf8"),o=Math.max(1,s.split(/\r?\n/u).length),i={id:ir(n,`file:${t}`),projectId:n,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:o,metadata:{language:r.language,structuralParser:!1,lexicalSearch:!0,lexicalEngine:r.lexicalEngine,...r.lspServer?{lspServer:r.lspServer}:{}}};return{filePath:t,symbols:[i],imports:[],calls:[],heritage:[]}}async function je(n,e,t){let r=ce(t);if(!r)throw new Error(`No parser capability for: ${t}`);if(r.supported)return de(n,e,t);if(r.lexicalSearch)return ar(n,e,t);throw new Error(`Structural and lexical parsing unsupported for: ${t}`)}function cr(n){let e=n??4;if(!Number.isSafeInteger(e)||e<1||e>64)throw new Error("concurrency must be an integer between 1 and 64");return e}function lr(n){if(n?.aborted)throw new Error("Operation aborted")}async function ee(n,e,t={}){if(n.length===0)return[];let r=Math.min(cr(t.concurrency),n.length),s=new Array(n.length),o=0,i=0,a=async()=>{for(;;){lr(t.signal);let c=o;if(o+=1,c>=n.length)return;s[c]=await e(n[c],c),i+=1,t.onProgress?.({completed:i,total:n.length,index:c})}},l=Array.from({length:r},()=>a());return await Promise.all(l),s}var te=class{async index(e,t,r={}){let s={...r.scan,extensions:r.scan?.extensions??_e()};r.signal&&(s.signal=r.signal);let o=await Le(t,s),i=o.files;r.onProgress?.({phase:"scan",current:i.length,total:i.length});let a=r.maxWarnings??20;if(!Number.isSafeInteger(a)||a<0)throw new Error("maxWarnings must be a non-negative integer");let l=0,c=await ee(i,async u=>{try{return await je(e,t,u)}catch(h){return l+=1,l<=a&&console.warn(`[indexer] skipped ${u}:`,h instanceof Error?h.message:h),null}},{concurrency:r.concurrency??4,signal:r.signal,onProgress:({completed:u,total:h,index:C})=>{r.onProgress?.({phase:"parse",current:u,total:h,file:i[C]})}});l>a&&console.warn(`[indexer] ${l-a} additional parse warnings suppressed`);let d=c.filter(u=>u!==null),f=new $().build(e,d);return{files:d.length,symbols:f.allSymbols(e).length,edges:f.allEdges(e).length,parseFailures:l,scan:o.stats,graph:f}}};function De(n,e){let t=n.allSymbols(e),r=n.allEdges(e),s=i=>t.filter(a=>a.type===i).length,o=i=>r.filter(a=>a.type===i).length;return{files:s("file"),classes:s("class"),interfaces:s("interface"),functions:s("function"),methods:s("method"),properties:s("property"),routes:s("route"),symbols:t.length,edges:r.length,calls:o("CALLS"),callReferences:o("CALL_REFERENCE"),imports:o("IMPORTS"),inherits:o("INHERITS"),implements:o("IMPLEMENTS"),usesType:o("USES_TYPE"),tests:o("TESTS"),routeEdges:o("ROUTE"),writes:o("WRITES")}}import{execFile as dr}from"node:child_process";import{promisify as pr}from"node:util";var Ds=pr(dr);var K=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")}};import*as P from"typescript";import{DatabaseSync as _o}from"node:sqlite";import*as E from"typescript";import*as g from"typescript";var ci=new Set([g.SyntaxKind.EqualsToken,g.SyntaxKind.PlusEqualsToken,g.SyntaxKind.MinusEqualsToken,g.SyntaxKind.AsteriskEqualsToken,g.SyntaxKind.SlashEqualsToken,g.SyntaxKind.PercentEqualsToken,g.SyntaxKind.QuestionQuestionEqualsToken,g.SyntaxKind.AmpersandAmpersandEqualsToken,g.SyntaxKind.BarBarEqualsToken]);import{spawnSync as mr}from"node:child_process";var gr=[{language:"python",command:"pyright-langserver"},{language:"go",command:"gopls"},{language:"rust",command:"rust-analyzer"},{language:"c",command:"clangd"},{language:"cpp",command:"clangd"}];function hr(n){return n.split(/\r?\n/u).map(t=>t.trim()).find(Boolean)||void 0}function yr(n,e){let t=mr(e,["--version"],{encoding:"utf8",timeout:2e3,windowsHide:!0}),r=!t.error&&t.status===0,s=[t.stdout??"",t.stderr??""].join(`
4
+ `);return{language:n,command:e,installed:r,...r?{version:hr(s)}:{},mode:"external-optional",activeInStructuralGraph:!1}}function $e(){return gr.map(n=>yr(n.language,n.command))}var Sr=process.argv.includes("--json"),Ge=$e(),br={structuralParser:{engine:"typescript-compiler-api",languages:L.filter(n=>n.structural).map(n=>n.language)},lexicalSearch:{engine:"sqlite-fts5-bm25",languages:L.filter(n=>n.lexicalSearch).map(n=>n.language)},lspFoundation:{mode:"detection-only",automaticDownload:!1,structuralGraphIntegration:!1,servers:Ge}};if(Sr)console.log(JSON.stringify(br,null,2));else{console.log("ToolNet Code Intelligence Capabilities"),console.log(""),console.log("Structural parser: TypeScript Compiler API");for(let n of L)console.log([n.language.padEnd(12),n.structural?"structural=yes":"structural=no",n.lexicalSearch?"lexical=yes":"lexical=no",n.lspServer?`lsp=${n.lspServer}`:""].filter(Boolean).join(" "));console.log(""),console.log("LSP detection:");for(let n of Ge)console.log([n.language.padEnd(12),n.command.padEnd(22),n.installed?"available":"not-installed"].join(" "))}import{homedir as Jr}from"node:os";import{join as Qr}from"node:path";import{DeleteObjectCommand as xr,GetObjectCommand as Er,HeadObjectCommand as Cr,ListObjectsV2Command as wr,PutObjectCommand as Rr,S3Client as vr}from"@aws-sdk/client-s3";import{getSignedUrl as Pr}from"@aws-sdk/s3-request-presigner";var re=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new vr({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Rr({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await Pr(this.client,new Er({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Cr({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 xr({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new wr({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};import{access as Ke,mkdir as kr,readFile as Tr,readdir as Ar,rm as Mr,stat as Be,writeFile as Ir}from"node:fs/promises";import{dirname as Nr,join as Lr,relative as ze,resolve as _r}from"node:path";var B=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _r(this.root,t)}async put(e,t){let r=this.path(e);await kr(Nr(r),{recursive:!0}),await Ir(r,t)}async get(e){try{return await Tr(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 Ke(this.path(e)),!0}catch{return!1}}async delete(e){await Mr(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await Ke(t)}catch{return r}let s=async i=>{let a=await Ar(i,{withFileTypes:!0});for(let l of a){let c=Lr(i,l.name);if(l.isDirectory()){await s(c);continue}let d=await Be(c);r.push({key:ze(this.root,c),size:d.size,updatedAt:d.mtime.toISOString()})}},o=await Be(t);return o.isDirectory()?await s(t):r.push({key:ze(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as Or,GetObjectCommand as jr,HeadObjectCommand as Fr,ListObjectsV2Command as Dr,PutObjectCommand as $r,S3Client as Gr}from"@aws-sdk/client-s3";import{getSignedUrl as Kr}from"@aws-sdk/s3-request-presigner";var z=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Gr({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new $r({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await Kr(this.client,new jr({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Fr({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 Or({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new Dr({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};import{createCipheriv as Br,createDecipheriv as zr,createHash as Ur,randomBytes as Hr,timingSafeEqual as Wr}from"node:crypto";import{readFileSync as Yr}from"node:fs";var I=Buffer.from("TNMEME01","ascii"),He=1,U=8,H=12,pe=16,We=I.length+1+U+H+pe,Vr="toolnet-memory:remote-encryption:v1:",Ye="aes-256-gcm",ue=32,S=class extends Error{constructor(t,r){super(r);this.code=t;this.name="RemoteEncryptionError"}code};function qr(n){return n?["1","true","yes","on","enabled"].includes(n.trim().toLowerCase()):!1}function fe(n=process.env){return qr(n.TOOLNET_REMOTE_ENCRYPTION)}function Ue(n){let e=n.trim();if(!e)throw new S("REMOTE_ENCRYPTION_KEY_EMPTY","Remote encryption key is empty.");let t;if(e.startsWith("hex:")){let r=e.slice(4);if(!/^[0-9a-f]{64}$/iu.test(r))throw new S("REMOTE_ENCRYPTION_KEY_INVALID","hex: remote encryption key must contain exactly 64 hexadecimal characters.");t=Buffer.from(r,"hex")}else if(/^[0-9a-f]{64}$/iu.test(e))t=Buffer.from(e,"hex");else{let r=e.startsWith("base64:")?e.slice(7):e;if(!/^[A-Za-z0-9+/_-]+={0,2}$/u.test(r))throw new S("REMOTE_ENCRYPTION_KEY_INVALID","Remote encryption key must be 32 raw bytes encoded as hexadecimal or base64.");t=Buffer.from(r,r.includes("-")||r.includes("_")?"base64url":"base64")}if(t.length!==ue)throw new S("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH",`Remote encryption key must decode to exactly ${ue} bytes.`);return t}function Ve(n=process.env){let e=n.TOOLNET_REMOTE_ENCRYPTION_KEY?.trim(),t=n.TOOLNET_REMOTE_ENCRYPTION_KEY_FILE?.trim();if(e&&t)throw new S("REMOTE_ENCRYPTION_KEY_AMBIGUOUS","Configure either TOOLNET_REMOTE_ENCRYPTION_KEY or TOOLNET_REMOTE_ENCRYPTION_KEY_FILE, not both.");if(e)return Ue(e);if(t){let r;try{r=Yr(t,"utf8")}catch(s){throw new S("REMOTE_ENCRYPTION_KEY_FILE_READ_FAILED",[`Unable to read remote encryption key file: ${t}.`,s instanceof Error?s.message:String(s)].join(" "))}return Ue(r)}}function qe(n){return Ur("sha256").update(n).digest().subarray(0,U)}function Je(n){return Buffer.from(`${Vr}${n}`,"utf8")}function me(n){return n.byteLength<I.length?!1:Buffer.from(n).subarray(0,I.length).equals(I)}function Qe(n,e,t){if(t.byteLength!==ue)throw new S("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH","AES-256-GCM requires a 32-byte key.");let r=typeof e=="string"?Buffer.from(e,"utf8"):Buffer.from(e),s=Hr(H),o=Br(Ye,t,s);o.setAAD(Je(n));let i=Buffer.concat([o.update(r),o.final()]),a=o.getAuthTag(),l=Buffer.alloc(We),c=0;return I.copy(l,c),c+=I.length,l.writeUInt8(He,c),c+=1,qe(t).copy(l,c),c+=U,s.copy(l,c),c+=H,a.copy(l,c),Buffer.concat([l,i])}function Ze(n,e,t){let r=Buffer.from(e);if(!me(r))throw new S("REMOTE_ENCRYPTION_ENVELOPE_REQUIRED","Payload is not a ToolNet encrypted remote object.");if(r.length<We)throw new S("REMOTE_ENCRYPTION_ENVELOPE_TRUNCATED","Encrypted remote payload is truncated.");let s=I.length,o=r.readUInt8(s);if(s+=1,o!==He)throw new S("REMOTE_ENCRYPTION_VERSION_UNSUPPORTED",`Unsupported remote encryption envelope version: ${o}.`);let i=r.subarray(s,s+U);s+=U;let a=qe(t);if(!Wr(i,a))throw new S("REMOTE_ENCRYPTION_KEY_MISMATCH","Configured remote encryption key does not match this encrypted object.");let l=r.subarray(s,s+H);s+=H;let c=r.subarray(s,s+pe);s+=pe;let d=r.subarray(s),f=zr(Ye,t,l);f.setAAD(Je(n)),f.setAuthTag(c);try{return Buffer.concat([f.update(d),f.final()])}catch{throw new S("REMOTE_ENCRYPTION_AUTH_FAILED","Encrypted remote object failed AES-GCM authentication.")}}var ge=class{constructor(e,t){this.inner=e;this.options=t;if(this.name=e.name,t.enabled&&!t.key)throw new S("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote client-side encryption is enabled but no encryption key is configured.")}inner;options;name;async put(e,t,r){if(!this.options.enabled){await this.inner.put(e,t,r);return}let s=this.options.key;if(!s)throw new S("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote encryption key is unavailable.");let o=Qe(e,t,s);await this.inner.put(e,o,"application/octet-stream")}async get(e){let t=await this.inner.get(e);if(!t)return null;if(!me(t))return t;if(!this.options.enabled)throw new S("REMOTE_ENCRYPTION_REQUIRED",["Remote object is client-side encrypted.","Enable TOOLNET_REMOTE_ENCRYPTION and configure the matching key."].join(" "));let r=this.options.key;if(!r)throw new S("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote object is encrypted but no decryption key is configured.");return Ze(e,t,r)}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 Xe(n,e=process.env){if(n.name==="local")return fe(e)&&console.warn("[storage] Remote encryption requested but active storage provider is local; local data remains unchanged."),n;let t=fe(e),r=t?Ve(e):void 0;return new ge(n,{enabled:t,key:r})}function W(n){return Xe(n)}function he(n,e){return console.warn(e),W(new B(n))}function et(n){let e=n.localRoot??Qr(Jr(),".toolnet-memory","storage");if(n.provider==="r2"){let t=n.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?W(new z({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):he(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(n.provider==="s3"){let t=n.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?W(new z({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):he(e,"[storage] S3 credentials missing. Using local fallback.")}if(n.provider==="huggingface"){let t=n.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?W(new re({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey})):he(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return W(new B(e))}function tt(n){let e=n.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 rt(n){let e=n.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var ne=class{constructor(e,t,r,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=tt(s??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(o,null,2)+`
5
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=rt(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,r){return await this.ensureRegistered(),this.provider.put(this.key(e),t,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};async function Zr(){let n=ye(),e=new Q().detect(),t=et({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),r=new ne(t,e.id,e.name,e.remote??e.name),s=await new te().index(e.id,e.rootPath),o=De(s.graph,e.id);await new K(r).save({version:1,projectId:e.id,updatedAt:new Date().toISOString(),files:s.files,symbols:s.graph.allSymbols(e.id),edges:s.graph.allEdges(e.id)}),console.log({ok:!0,storage:r.name,...o})}Zr().catch(n=>{console.error(n),process.exit(1)});