toolnet-memory 0.3.15 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
- import*as u from"fs";import*as c from"path";import{existsSync as A,mkdirSync as K,readFileSync as M,renameSync as G,writeFileSync as W}from"node:fs";import{dirname as Y,join as R}from"node:path";import{createHash as B}from"node:crypto";function k(n){return B("sha256").update(n).digest("hex")}function E(n){return R(n.rootPath,".toolnet","context","handoff.md")}function C(n){return R(n.rootPath,".toolnet","context","handoff.json")}function T(n,e){K(Y(n),{recursive:!0});let t=`${n}.tmp-${process.pid}-${Date.now()}`;W(t,e.endsWith(`
1
+ import*as f from"fs";import*as u from"path";import{existsSync as _,mkdirSync as te,readFileSync as O,renameSync as ne,writeFileSync as re}from"node:fs";import{dirname as oe,join as j}from"node:path";import{createHash as ee}from"node:crypto";function R(n){return ee("sha256").update(n).digest("hex")}function P(n){return j(n.rootPath,".toolnet","context","handoff.md")}function N(n){return j(n.rootPath,".toolnet","context","handoff.json")}function D(n,e){te(oe(n),{recursive:!0});let t=`${n}.tmp-${process.pid}-${Date.now()}`;re(t,e.endsWith(`
2
2
  `)?e:`${e}
3
- `,{encoding:"utf8",mode:384}),G(t,n)}function J(n,e){T(n,`${JSON.stringify(e,null,2)}
4
- `)}function O(n,e){let t=e.replace(/\r\n/g,`
5
- `).trim();if(!t)return null;let r={version:1,projectId:n.id,projectName:n.name,text:t,digest:k(t),generatedAt:new Date().toISOString()};return T(E(n),t),J(C(n),r),r}function _(n){let e=E(n);if(!A(e))return null;try{let t=M(e,"utf8").trim();if(!t)return null;let r=new Date(0).toISOString(),s=C(n);if(A(s))try{let o=JSON.parse(M(s,"utf8"));typeof o.generatedAt=="string"&&(r=o.generatedAt)}catch{}return{version:1,projectId:n.id,projectName:n.name,text:t,digest:k(t),generatedAt:r}}catch{return null}}function I(n){let e=c.resolve(n),t=c.parse(e).root;for(;e!==t;){let r=c.join(e,".toolnet");if(u.existsSync(r)&&u.statSync(r).isDirectory())return e;e=c.dirname(e)}return null}import{existsSync as ee,readFileSync as te}from"node:fs";import{join as ne}from"node:path";import{existsSync as U,mkdirSync as Ze,readFileSync as Z,renameSync as qe,writeFileSync as Qe}from"node:fs";import{dirname as et,join as q}from"node:path";function Q(n){return q(n.rootPath,".toolnet","context","session-origin.json")}function X(n){let e=Q(n);if(!U(e))return null;try{let t=JSON.parse(Z(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function j(n){let e=X(n);if(!e)return null;let t=["Previous session:",`- Agent: ${e.agent}`,`- Session: ${e.nativeSessionId}`];return e.currentRequest&&t.push(`- Current request: ${e.currentRequest}`),e.currentActivity&&t.push(`- Current activity: ${e.currentActivity}`),e.currentPhase&&t.push(`- Current phase: ${e.currentPhase}`),e.currentTask&&t.push(`- Current task: ${e.currentTask}`),e.lastTouchedFile&&t.push(`- Last touched file: ${e.lastTouchedFile}`),e.latestBlocker&&t.push(`- Blocker: ${e.latestBlocker}`),e.latestNextAction&&t.push(`- Next action: ${e.latestNextAction}`),e.latestDecision&&t.push(`- Important decision: ${e.latestDecision}`),t.join(`
6
- `)}function re(n){let e=ne(n.rootPath,".toolnet","current.md");if(!ee(e))return null;try{return te(e,"utf8").trim()}catch{return null}}function oe(n,e){let t=e.replace(/\r\n/g,`
7
- `).trim(),r=2400,s=t.length>r?`${t.slice(0,r)}
3
+ `,{encoding:"utf8",mode:384}),ne(t,n)}function ie(n,e){D(n,`${JSON.stringify(e,null,2)}
4
+ `)}function F(n,e){let t=e.replace(/\r\n/g,`
5
+ `).trim();if(!t)return null;let r={version:1,projectId:n.id,projectName:n.name,text:t,digest:R(t),generatedAt:new Date().toISOString()};return D(P(n),t),ie(N(n),r),r}function $(n){let e=P(n);if(!_(e))return null;try{let t=O(e,"utf8").trim();if(!t)return null;let r=new Date(0).toISOString(),i=N(n);if(_(i))try{let o=JSON.parse(O(i,"utf8"));typeof o.generatedAt=="string"&&(r=o.generatedAt)}catch{}return{version:1,projectId:n.id,projectName:n.name,text:t,digest:R(t),generatedAt:r}}catch{return null}}function L(n){let e=u.resolve(n),t=u.parse(e).root;for(;e!==t;){let r=u.join(e,".toolnet");if(f.existsSync(r)&&f.statSync(r).isDirectory())return e;e=u.dirname(e)}return null}import{existsSync as le,readFileSync as fe}from"node:fs";import{join as pe}from"node:path";import{existsSync as se,mkdirSync as pt,readFileSync as ae,renameSync as mt,writeFileSync as gt}from"node:fs";import{dirname as ht,join as ce}from"node:path";function ue(n){return ce(n.rootPath,".toolnet","context","session-origin.json")}function de(n){let e=ue(n);if(!se(e))return null;try{let t=JSON.parse(ae(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function K(n){let e=de(n);if(!e)return null;let t=["Previous session:",`- Agent: ${e.agent}`,`- Session: ${e.nativeSessionId}`];return e.currentRequest&&t.push(`- Current request: ${e.currentRequest}`),e.currentActivity&&t.push(`- Current activity: ${e.currentActivity}`),e.currentPhase&&t.push(`- Current phase: ${e.currentPhase}`),e.currentTask&&t.push(`- Current task: ${e.currentTask}`),e.lastTouchedFile&&t.push(`- Last touched file: ${e.lastTouchedFile}`),e.latestBlocker&&t.push(`- Blocker: ${e.latestBlocker}`),e.latestNextAction&&t.push(`- Next action: ${e.latestNextAction}`),e.latestDecision&&t.push(`- Important decision: ${e.latestDecision}`),t.join(`
6
+ `)}function me(n){let e=pe(n.rootPath,".toolnet","current.md");if(!le(e))return null;try{return fe(e,"utf8").trim()}catch{return null}}function ge(n,e){let t=e.replace(/\r\n/g,`
7
+ `).trim(),r=2400,i=t.length>r?`${t.slice(0,r)}
8
8
 
9
- [Current work truncated for fast handoff]`:t,o=j(n);return["# ToolNet Fast Handoff","",`Project: ${n.name}`,"",...o?[o,""]:[],s,"","---","","Continuation rule:","- Continue unfinished work; do not redo completed steps.","- Query ToolNet Memory only when deeper history is needed."].join(`
10
- `)}function N(n){let e=re(n);if(e===null)return{updated:!1,reason:"missing-current",chars:0};if(!e.trim())return{updated:!1,reason:"empty-current",chars:0};let t=oe(n,e);return _(n)?.text.trim()===t.trim()?{updated:!1,reason:"unchanged",chars:t.length}:(O(n,t),{updated:!0,reason:"updated",chars:t.length})}import{existsSync as se,readFileSync as ie}from"node:fs";import{homedir as ae}from"node:os";import{join as ce}from"node:path";function ue(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
11
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function de(){let n=process.env.TOOLNET_GLOBAL_ENV??ce(ae(),".config","toolnet-memory",".env");if(!se(n))return;let e=ie(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]=ue(r.slice(s+1)))}}de();import{createHash as le}from"node:crypto";import{existsSync as m,mkdirSync as fe,readFileSync as pe,renameSync as me,writeFileSync as ge}from"node:fs";import{basename as ye,dirname as g,join as f,parse as L,resolve as d}from"node:path";var z=".toolnet",he="project.json";function xe(n){return le("sha256").update(n).digest("hex").slice(0,16)}function y(n){return f(n,z,he)}function Se(n){return m(y(n))}function P(n,e){let t=d(n),r=L(t).root;for(;;){if(Se(t))return t;if(t===r||e&&t===d(e))break;let s=g(t);if(s===t)break;t=s}return null}function D(n){let e=d(n),t=L(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>m(f(e,o))))return e;if(e===t)break;let s=g(e);if(s===e)break;e=s}return d(n)}function F(n){let e;try{e=JSON.parse(pe(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:g(g(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 $(n,e){let t=f(n,z);fe(t,{recursive:!0});let r=y(n),s=`${r}.tmp-${process.pid}`;ge(s,JSON.stringify(e,null,2)+`
12
- `,{encoding:"utf8",mode:384}),me(s,r)}function w(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}}var h=class{findExisting(e=process.cwd()){let t=d(e),r=D(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>m(f(r,p))),i=P(t,o?r:void 0);if(!i)return null;let a=F(y(i));return w(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=d(e),r=D(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(b=>m(f(r,b))),i=P(t,o?r:void 0);if(i){let b=y(i),l=F(b);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),$(i,l)),w(l,i)}let a=new Date().toISOString(),p=ye(r),v={version:1,id:xe(r),name:p,remote:p,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return $(r,v),w(v,r)}};var be=[{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"}],ke=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function V(n){return n.normalize("NFKC").trim().toLowerCase()}function we(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 ve(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function Ae(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 Me(n,e){return n.start<e.end&&e.start<n.end}function H(n){return n.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var x=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=V(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of be){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=H(t),s=[];for(let o of r)s.some(i=>Me(i,o))||s.push(o);return H(s)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=V(e);return ke.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)||ve(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||Ae(e,s.index,s.index+o.length)&&(we(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return t}};var S=class{scanner;constructor(e={}){this.scanner=new x(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 wt=new S;function Re(){let n=process.cwd(),e=I(n);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new h().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let r=N(t);console.log(JSON.stringify({project:t.name,...r},null,2))}Re();
9
+ [Current work truncated for fast handoff]`:t,o=K(n);return["# ToolNet Fast Handoff","",`Project: ${n.name}`,"",...o?[o,""]:[],i,"","---","","Continuation rule:","- Continue unfinished work; do not redo completed steps.","- Query ToolNet Memory only when deeper history is needed."].join(`
10
+ `)}function z(n){let e=me(n);if(e===null)return{updated:!1,reason:"missing-current",chars:0};if(!e.trim())return{updated:!1,reason:"empty-current",chars:0};let t=ge(n,e);return $(n)?.text.trim()===t.trim()?{updated:!1,reason:"unchanged",chars:t.length}:(F(n,t),{updated:!0,reason:"updated",chars:t.length})}import{existsSync as ye,readFileSync as he}from"node:fs";import{homedir as xe}from"node:os";import{join as Se}from"node:path";function be(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
11
+ `).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 n=process.env.TOOLNET_GLOBAL_ENV??Se(xe(),".config","toolnet-memory",".env");if(!ye(n))return;let e=he(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 i=r.indexOf("=");if(i<=0)continue;let o=r.slice(0,i).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=be(r.slice(i+1)))}}ve();import{createHash as Ee}from"node:crypto";import{existsSync as b,mkdirSync as Te,readFileSync as Ie,renameSync as _e,writeFileSync as Oe}from"node:fs";import{basename as je,dirname as v,join as h,parse as U,resolve as l}from"node:path";import{createHash as H}from"node:crypto";import{spawnSync as we}from"node:child_process";var y="git-remote-v1",Me=new Set(["github.com","gitlab.com","bitbucket.org"]);function B(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:(Me.has(n)&&(t=t.toLowerCase()),t)}function ke(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",i=e.port&&!r?`${t}:${e.port}`:t,o=B(t,e.pathname);return o?`${i}/${o}`:null}function Ae(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=B(t,e[2]??"");return r?`${t}/${r}`:null}function V(n){let e=n.trim();return e?e.includes("://")?ke(e):Ae(e):null}function Re(n){return H("sha256").update(`${y}:${n}`).digest("hex")}function Y(n){return H("sha256").update(`toolnet-project:${y}:${n}`).digest("hex").slice(0,16)}function Ce(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function C(n,e){let t=we("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function G(n,e){let t=Ce(n);return t?{scheme:y,canonicalRemote:n,fingerprint:Re(n),repositoryName:t,source:e}:null}function W(n){let e=C(n,["remote","get-url","origin"]);if(e){let i=V(e);if(i)return G(i,"origin")}let t=C(n,["remote"]);if(!t)return null;let r=new Set;for(let i of t.split(/\r?\n/u).map(o=>o.trim()).filter(Boolean)){let o=C(n,["remote","get-url",i]);if(!o)continue;let s=V(o);s&&r.add(s)}return r.size!==1?null:G([...r][0],"unique-remote")}var q=".toolnet",Pe="project.json";function Ne(n){return Ee("sha256").update(n).digest("hex").slice(0,16)}function p(n){return h(n,q,Pe)}function Z(n){return b(p(n))}function J(n,e){let t=l(n),r=U(t).root;for(;;){if(Z(t))return t;if(t===r||e&&t===l(e))break;let i=v(t);if(i===t)break;t=i}return null}function E(n){let e=l(n),t=U(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>b(h(e,o))))return e;if(e===t)break;let i=v(e);if(i===e)break;e=i}return l(n)}function x(n){let e;try{e=JSON.parse(Ie(n,"utf8"))}catch(i){throw new Error(`Invalid ToolNet project manifest: ${n}: ${i instanceof Error?i.message:String(i)}`)}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:v(v(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 S(n,e){let t=h(n,q);Te(t,{recursive:!0});let r=p(n),i=`${r}.tmp-${process.pid}`;Oe(i,JSON.stringify(e,null,2)+`
12
+ `,{encoding:"utf8",mode:384}),_e(i,r)}function d(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 T(n){return{version:1,scheme:y,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function De(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 w=class{adopt(e,t){let r=E(l(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(Z(r)){let a=x(p(r));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return d(a,r)}let i=new Date().toISOString(),o={...t.metadata};t.gitIdentity&&(o.toolnetIdentity=T(t.gitIdentity));let s={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:r,createdAt:t.createdAt??i,updatedAt:i,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(o).length?o:void 0};return S(r,s),d(s,r)}recordGitIdentity(e,t,r={}){let i=this.requireExisting(e),o=p(i.rootPath),s=x(o),a=De(s);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 c=s.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===t.fingerprint||(s.metadata={...s.metadata,toolnetIdentity:T(t)},s.updatedAt=new Date().toISOString(),S(i.rootPath,s)),d(s,i.rootPath)}findExisting(e=process.cwd()){let t=l(e),r=E(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>b(h(r,c))),s=J(t,o?r:void 0);if(!s)return null;let a=x(p(s));return d(a,s)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=l(e),r=E(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(A=>b(h(r,A))),s=J(t,o?r:void 0);if(s){let A=p(s),g=x(A);return g.rootPath!==s&&(g.rootPath=s,g.updatedAt=new Date().toISOString(),S(s,g)),d(g,s)}let a=new Date().toISOString(),c=je(r),m=W(r),I={version:1,id:m?Y(m.canonicalRemote):Ne(r),name:c,remote:m?.repositoryName??c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:m?{toolnetIdentity:T(m)}:void 0};return S(r,I),d(I,r)}};var Fe=[{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 Q(n){return n.normalize("NFKC").trim().toLowerCase()}function Le(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 i=r/n.length;t-=i*Math.log2(i)}return t}function Ke(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function ze(n,e,t){let r=n.slice(Math.max(0,e-48),e),i=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} ${i}`)}function Ve(n,e){return n.start<e.end&&e.start<n.end}function X(n){return n.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var M=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=Q(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of Fe){let s=new RegExp(o.regex.source,o.regex.flags);for(let a of e.matchAll(s))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=X(t),i=[];for(let o of r)i.some(s=>Ve(s,o))||i.push(o);return X(i)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=Q(e);return $e.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let i of e.matchAll(r)){if(i.index===void 0||!i[0])continue;let o=i[0];this.allowed(o)||Ke(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||ze(e,i.index,i.index+o.length)&&(Le(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:i.index,end:i.index+o.length,confidence:"heuristic"}))}return t}};var k=class{scanner;constructor(e={}){this.scanner=new M(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,i=[...t].sort((s,a)=>a.start-s.start),o=new Set;for(let s of i)o.add(s.type),r=r.slice(0,s.start)+`[REDACTED:${s.type}]`+r.slice(s.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,i]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(i)}return t}return e}};var Gt=new k;function Ge(){let n=process.cwd(),e=L(n);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new w().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let r=z(t);console.log(JSON.stringify({project:t.name,...r},null,2))}Ge();
@@ -1,4 +1,4 @@
1
- import{readFileSync as A}from"node:fs";import{dirname as M,resolve as w}from"node:path";import{fileURLToPath as D}from"node:url";var I={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},R={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 o=process.env.TERM_PROGRAM,e=process.env.WT_SESSION,n=process.env.VSCODE_PID,t=process.env.ConEmuPID;return!!(e||n||t||o==="vscode")}return process.env.TERM!=="linux"}var h;function k(){return h||(h=U()?I:R),h}var m={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 N(o){return o.noColor||process.env.NO_COLOR?!1:o.tty??process.stdout.isTTY??!1}function f(o,e,n){return N(n)?`${e}${o}${m.reset}`:o}function T(o,e){return f(o,m.dim,e)}function G(o,e){return f(o,m.bold,e)}function b(o,e){return f(o,m.cyan,e)}function g(o,e,n){let t=k(),i=e?` ${T(`v${e}`,n)}`:"";return`${b(t.phaseDone,n)} ${o}${i}`}function a(o,e){return G(o,e)}function l(o,e,n,t){let i=" ".repeat(Math.max(0,n-o.length));return` ${b(o,t)}${i} ${e}`}var u=[{name:"init",description:"Initialize current project",usage:"toolnet-memory init [path]",category:"core"},{name:"doctor",description:"Check system health",category:"core"},{name:"ask",description:"Ask project memory",usage:"toolnet-memory ask <question>",category:"memory"},{name:"context",description:"Show current project context",category:"memory",aliases:["context:print"]},{name:"work",description:"Show current work state",category:"memory",aliases:["work:status"]},{name:"index",description:"Build code intelligence",category:"code",pipeline:["Scanning files","Parsing code","Type Resolution","Rich Graph","Semantic Code Index","Architecture Intelligence","Graph Analysis","3D Visualization Dataset"]},{name:"semantic",description:"Semantic code search",usage:"toolnet-memory semantic <query>",category:"code"},{name:"impact",description:"Analyze change impact",usage:"toolnet-memory impact <file>",category:"code"},{name:"graph",description:"Open code graph UI",category:"code"},{name:"graph:ui",description:"Open code graph UI",category:"code",hidden:!0},{name:"status",description:"Show ToolNet status",category:"system"},{name:"gc",description:"Plan or apply safe retention cleanup",usage:"toolnet-memory gc [--dry-run|--apply] [--remote] [--keep-snapshots N] [--snapshot-days N] [--runtime-days N] [--stale-lock-minutes N] [--project PATH] [--json]",category:"system",examples:["toolnet-memory gc","toolnet-memory gc --remote --dry-run","toolnet-memory gc --apply","toolnet-memory gc --remote --apply --keep-snapshots 10"]},{name:"update",description:"Update ToolNet Memory",category:"system"},{name:"context:print",description:"Print fast project context",category:"context",hidden:!0},{name:"context:sync",description:"Show context hash/size",category:"context"},{name:"context:refresh",description:"Rebuild deep startup brief cache",category:"context"},{name:"brief",description:"Show full project brief",category:"context"},{name:"brief:json",description:"Show brief as JSON",category:"context"},{name:"profile:show",description:"Show .toolnet/profile.md",category:"context"},{name:"profile:sync",description:"Sync profile to agent files",category:"context"},{name:"work:status",description:"Show current work state",category:"work",hidden:!0},{name:"work:json",description:"Show work state as JSON",category:"work"},{name:"work:reconcile",description:"Reconcile work continuity",category:"work"},{name:"handoff:latest",description:"Show latest session handoff",category:"work"},{name:"handoff:refresh",description:"Refresh handoff data",category:"work"},{name:"index:graph",description:"Build graph index only",category:"code"},{name:"incremental",description:"Incremental code indexing",category:"code"},{name:"config",description:"Manage configuration",usage:"toolnet-memory config <get|set|list|open>",category:"system"},{name:"integrate:detect",description:"Detect agent integrations",category:"integration"},{name:"integrate:auto",description:"Auto-enable integrations with safe project scope policy",usage:"toolnet-memory integrate:auto [--all] [--scope global|project|both] [--project <path>] [--json]",category:"integration",examples:["toolnet-memory integrate:auto","toolnet-memory integrate:auto --project /path/to/toolnet-project","toolnet-memory integrate:auto --scope global","toolnet-memory integrate:auto --scope both --project /path/to/project"]},{name:"integrate:agy",description:"Install Agy hooks",category:"integration"},{name:"integrate:codex",description:"Install Codex integration",category:"integration"},{name:"integrate:opencode",description:"Install OpenCode plugin",category:"integration"},{name:"integrate:claude",description:"Install Claude Code integration",category:"integration"},{name:"integrate:kiro",description:"Install Kiro CLI integration",usage:"toolnet-memory integrate:kiro [--status] [--json]",category:"integration"},{name:"integrate:cursor",description:"Install Cursor CLI integration",usage:"toolnet-memory integrate:cursor [--scope global|project|both] [--project <path>] [--status] [--json]",category:"integration",examples:["toolnet-memory integrate:cursor --scope global","toolnet-memory integrate:cursor --scope project --project /path/to/project","toolnet-memory integrate:cursor --scope both --project /path/to/project"]},{name:"integrate:copilot",description:"Install GitHub Copilot CLI integration",usage:"toolnet-memory integrate:copilot [--scope global|project|both] [--project <path>] [--status] [--json]",category:"integration",examples:["toolnet-memory integrate:copilot --scope global","toolnet-memory integrate:copilot --scope project --project /path/to/project","toolnet-memory integrate:copilot --scope both --project /path/to/project"]},{name:"integrate:grok",description:"Install Grok Build integration",usage:"toolnet-memory integrate:grok [--scope global|project|both] [--project <path>] [--status] [--json]",category:"integration",examples:["toolnet-memory integrate:grok --scope global","toolnet-memory integrate:grok --scope project --project /path/to/project","toolnet-memory integrate:grok --scope both --project /path/to/project"]},{name:"integrate:toolnet-cli",description:"Install ToolNet CLI MCP integration",usage:"toolnet-memory integrate:toolnet-cli [--status] [--json] [--force]",category:"integration",examples:["toolnet-memory integrate:toolnet-cli","toolnet-memory integrate:toolnet-cli --status"]},{name:"integrate:kilo",description:"Install Kilo CLI MCP integration",usage:"toolnet-memory integrate:kilo [--status] [--json] [--force]",category:"integration",examples:["toolnet-memory integrate:kilo","toolnet-memory integrate:kilo --status"]},{name:"integrate:all",description:"Auto-enable all detected integrations",usage:"toolnet-memory integrate:all [--json]",category:"integration"},{name:"integrate:status",description:"Show unified Cursor/Copilot/Grok scoped integration status",usage:"toolnet-memory integrate:status [--scope global|project|both] [--project <path>] [--agent cursor|copilot|grok] [--json]",category:"integration",examples:["toolnet-memory integrate:status --scope global","toolnet-memory integrate:status --scope both --project /path/to/project","toolnet-memory integrate:status --scope both --project /path/to/project --agent cursor"]},{name:"session:agy-sync",description:"Sync Agy session",category:"session"},{name:"session:agy-recover",description:"Recover Agy sessions",category:"session"},{name:"session:agy-hook",description:"Agy session hook",category:"session",hidden:!0},{name:"session:codex-sync",description:"Sync Codex session",category:"session"},{name:"session:codex-recover",description:"Recover Codex sessions",category:"session"},{name:"session:codex-notify",description:"Codex notification hook",category:"session",hidden:!0},{name:"session:codex-context",description:"Codex context hook",category:"session",hidden:!0},{name:"session:opencode-sync",description:"Sync OpenCode session",category:"session"},{name:"session:opencode-recover",description:"Recover OpenCode sessions",category:"session"},{name:"session:claude-hook",description:"Claude session hook",category:"session",hidden:!0},{name:"session:kiro-hook",description:"Kiro lifecycle hook",category:"session",hidden:!0},{name:"session:cursor-hook",description:"Cursor lifecycle hook",category:"session",hidden:!0},{name:"session:copilot-hook",description:"Copilot lifecycle hook",category:"session",hidden:!0},{name:"session:grok-hook",description:"Grok lifecycle hook",category:"session",hidden:!0},{name:"memory:review",description:"Review memory entries",category:"session"},{name:"memory:reconcile",description:"Reconcile memory state",category:"session"},{name:"guard:check",description:"Check project rules",category:"guard"},{name:"guard:explain",description:"Show rules and evidence",category:"guard"},{name:"guard:json",description:"Output guard result as JSON",category:"guard",hidden:!0},{name:"project:manual-init",description:"Initialize project manual",category:"project"},{name:"project:manual-show",description:"Show project manual",category:"project"},{name:"project:manual-sync",description:"Sync project manual",category:"project"},{name:"snapshot:list",description:"List snapshots",category:"snapshot"},{name:"snapshot:create",description:"Create snapshot",category:"snapshot"},{name:"snapshot:restore",description:"Restore snapshot",category:"snapshot"},{name:"recover",description:"Recover latest snapshot",category:"snapshot"},{name:"service",description:"Run daemon in foreground",category:"service"},{name:"service:install",description:"Install/start daemon",category:"service"},{name:"service:start",description:"Start daemon",category:"service"},{name:"service:stop",description:"Stop daemon",category:"service"},{name:"service:restart",description:"Restart daemon",category:"service"},{name:"service:status",description:"Show daemon status",category:"service"},{name:"service:remove",description:"Remove daemon",category:"service"},{name:"mcp",description:"Run MCP server",category:"advanced"},{name:"api",description:"Run API server",category:"advanced"},{name:"run",description:"Run ToolNet runtime",category:"advanced",hidden:!0},{name:"production:certify",description:"Verify production runtime",category:"advanced"},{name:"certify:continuity",description:"Certify work continuity",category:"advanced"}];function x(o){return{tty:o.tty,noColor:o.noColor}}function O(o){let e=[],n=o.version??"0.0.0",t=x(o);e.push(""),e.push(g("ToolNet Memory",n,t)),e.push(" Persistent memory & code intelligence for AI coding agents"),e.push(""),e.push(a("USAGE",t)),e.push(" toolnet-memory <command> [options]"),e.push("");let i=[{key:"core",title:"GET STARTED"},{key:"memory",title:"MEMORY"},{key:"code",title:"CODE"},{key:"system",title:"SYSTEM"}];for(let{key:s,title:d}of i){let c=u.filter(r=>r.category===s&&!r.hidden);if(c.length===0)continue;e.push(a(d,t));let y=Math.max(...c.map(r=>r.name.length));for(let r of c)e.push(l(r.name,r.description,y,t));e.push("")}return e.push(a("MORE",t)),e.push(l("help --all","Show all advanced commands",15,t)),e.push(l("help <command>","Show command details",15,t)),e.push(""),e.join(`
1
+ import{readFileSync as A}from"node:fs";import{dirname as G,resolve as w}from"node:path";import{fileURLToPath as D}from"node:url";var I={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},R={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 o=process.env.TERM_PROGRAM,e=process.env.WT_SESSION,n=process.env.VSCODE_PID,t=process.env.ConEmuPID;return!!(e||n||t||o==="vscode")}return process.env.TERM!=="linux"}var h;function k(){return h||(h=U()?I:R),h}var m={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 T(o){return o.noColor||process.env.NO_COLOR?!1:o.tty??process.stdout.isTTY??!1}function f(o,e,n){return T(n)?`${e}${o}${m.reset}`:o}function N(o,e){return f(o,m.dim,e)}function M(o,e){return f(o,m.bold,e)}function b(o,e){return f(o,m.cyan,e)}function g(o,e,n){let t=k(),i=e?` ${N(`v${e}`,n)}`:"";return`${b(t.phaseDone,n)} ${o}${i}`}function a(o,e){return M(o,e)}function l(o,e,n,t){let i=" ".repeat(Math.max(0,n-o.length));return` ${b(o,t)}${i} ${e}`}var u=[{name:"init",description:"Initialize current project",usage:"toolnet-memory init [path] [--adopt-remote NAME] [--no-remote-identity] [--rebind-git-identity]",category:"core",examples:["toolnet-memory init","toolnet-memory init /path/to/project","toolnet-memory init --adopt-remote my-project"]},{name:"doctor",description:"Check system health",category:"core"},{name:"ask",description:"Ask project memory",usage:"toolnet-memory ask <question>",category:"memory"},{name:"context",description:"Show current project context",category:"memory",aliases:["context:print"]},{name:"work",description:"Show current work state",category:"memory",aliases:["work:status"]},{name:"index",description:"Build code intelligence",category:"code",pipeline:["Scanning files","Parsing code","Type Resolution","Rich Graph","Local Code Search \u2014 SQLite FTS5/BM25","Architecture Intelligence","Graph Analysis","3D Visualization Dataset"]},{name:"semantic",description:"Local code search \u2014 SQLite FTS5/BM25 (legacy command name)",usage:"toolnet-memory semantic <query>",category:"code"},{name:"impact",description:"Analyze change impact",usage:"toolnet-memory impact <file>",category:"code"},{name:"graph",description:"Open code graph UI",category:"code"},{name:"graph:ui",description:"Open code graph UI",category:"code",hidden:!0},{name:"status",description:"Show ToolNet status",category:"system"},{name:"gc",description:"Plan or apply safe retention cleanup",usage:"toolnet-memory gc [--dry-run|--apply] [--remote] [--keep-snapshots N] [--snapshot-days N] [--runtime-days N] [--stale-lock-minutes N] [--project PATH] [--json]",category:"system",examples:["toolnet-memory gc","toolnet-memory gc --remote --dry-run","toolnet-memory gc --apply","toolnet-memory gc --remote --apply --keep-snapshots 10"]},{name:"update",description:"Update ToolNet Memory",category:"system"},{name:"context:print",description:"Print fast project context",category:"context",hidden:!0},{name:"context:sync",description:"Show context hash/size",category:"context"},{name:"context:refresh",description:"Rebuild deep startup brief cache",category:"context"},{name:"brief",description:"Show full project brief",category:"context"},{name:"brief:json",description:"Show brief as JSON",category:"context"},{name:"profile:show",description:"Show .toolnet/profile.md",category:"context"},{name:"profile:sync",description:"Sync profile to agent files",category:"context"},{name:"work:status",description:"Show current work state",category:"work",hidden:!0},{name:"work:json",description:"Show work state as JSON",category:"work"},{name:"work:reconcile",description:"Reconcile work continuity",category:"work"},{name:"handoff:latest",description:"Show latest session handoff",category:"work"},{name:"handoff:refresh",description:"Refresh handoff data",category:"work"},{name:"index:graph",description:"Build graph index only",category:"code"},{name:"incremental",description:"Incremental code indexing",category:"code"},{name:"config",description:"Manage configuration",usage:"toolnet-memory config <get|set|list|open>",category:"system"},{name:"integrate:detect",description:"Detect agent integrations",category:"integration"},{name:"integrate:auto",description:"Auto-enable integrations with safe project scope policy",usage:"toolnet-memory integrate:auto [--all] [--scope global|project|both] [--project <path>] [--json]",category:"integration",examples:["toolnet-memory integrate:auto","toolnet-memory integrate:auto --project /path/to/toolnet-project","toolnet-memory integrate:auto --scope global","toolnet-memory integrate:auto --scope both --project /path/to/project"]},{name:"integrate:agy",description:"Install Agy hooks",category:"integration"},{name:"integrate:codex",description:"Install Codex integration",category:"integration"},{name:"integrate:opencode",description:"Install OpenCode plugin",category:"integration"},{name:"integrate:claude",description:"Install Claude Code integration",category:"integration"},{name:"integrate:kiro",description:"Install Kiro CLI integration",usage:"toolnet-memory integrate:kiro [--status] [--json]",category:"integration"},{name:"integrate:cursor",description:"Install Cursor CLI integration",usage:"toolnet-memory integrate:cursor [--scope global|project|both] [--project <path>] [--status] [--json]",category:"integration",examples:["toolnet-memory integrate:cursor --scope global","toolnet-memory integrate:cursor --scope project --project /path/to/project","toolnet-memory integrate:cursor --scope both --project /path/to/project"]},{name:"integrate:copilot",description:"Install GitHub Copilot CLI integration",usage:"toolnet-memory integrate:copilot [--scope global|project|both] [--project <path>] [--status] [--json]",category:"integration",examples:["toolnet-memory integrate:copilot --scope global","toolnet-memory integrate:copilot --scope project --project /path/to/project","toolnet-memory integrate:copilot --scope both --project /path/to/project"]},{name:"integrate:grok",description:"Install Grok Build integration",usage:"toolnet-memory integrate:grok [--scope global|project|both] [--project <path>] [--status] [--json]",category:"integration",examples:["toolnet-memory integrate:grok --scope global","toolnet-memory integrate:grok --scope project --project /path/to/project","toolnet-memory integrate:grok --scope both --project /path/to/project"]},{name:"integrate:toolnet-cli",description:"Install ToolNet CLI MCP integration",usage:"toolnet-memory integrate:toolnet-cli [--status] [--json] [--force]",category:"integration",examples:["toolnet-memory integrate:toolnet-cli","toolnet-memory integrate:toolnet-cli --status"]},{name:"integrate:kilo",description:"Install Kilo CLI MCP integration",usage:"toolnet-memory integrate:kilo [--status] [--json] [--force]",category:"integration",examples:["toolnet-memory integrate:kilo","toolnet-memory integrate:kilo --status"]},{name:"integrate:all",description:"Auto-enable all detected integrations",usage:"toolnet-memory integrate:all [--json]",category:"integration"},{name:"integrate:status",description:"Show unified Cursor/Copilot/Grok scoped integration status",usage:"toolnet-memory integrate:status [--scope global|project|both] [--project <path>] [--agent cursor|copilot|grok] [--json]",category:"integration",examples:["toolnet-memory integrate:status --scope global","toolnet-memory integrate:status --scope both --project /path/to/project","toolnet-memory integrate:status --scope both --project /path/to/project --agent cursor"]},{name:"session:agy-sync",description:"Sync Agy session",category:"session"},{name:"session:agy-recover",description:"Recover Agy sessions",category:"session"},{name:"session:agy-hook",description:"Agy session hook",category:"session",hidden:!0},{name:"session:codex-sync",description:"Sync Codex session",category:"session"},{name:"session:codex-recover",description:"Recover Codex sessions",category:"session"},{name:"session:codex-notify",description:"Codex notification hook",category:"session",hidden:!0},{name:"session:codex-context",description:"Codex context hook",category:"session",hidden:!0},{name:"session:opencode-sync",description:"Sync OpenCode session",category:"session"},{name:"session:opencode-recover",description:"Recover OpenCode sessions",category:"session"},{name:"session:claude-hook",description:"Claude session hook",category:"session",hidden:!0},{name:"session:kiro-hook",description:"Kiro lifecycle hook",category:"session",hidden:!0},{name:"session:cursor-hook",description:"Cursor lifecycle hook",category:"session",hidden:!0},{name:"session:copilot-hook",description:"Copilot lifecycle hook",category:"session",hidden:!0},{name:"session:grok-hook",description:"Grok lifecycle hook",category:"session",hidden:!0},{name:"memory:review",description:"Review memory entries",category:"session"},{name:"memory:reconcile",description:"Reconcile memory state",category:"session"},{name:"guard:check",description:"Check project rules",category:"guard"},{name:"guard:explain",description:"Show rules and evidence",category:"guard"},{name:"guard:json",description:"Output guard result as JSON",category:"guard",hidden:!0},{name:"project:manual-init",description:"Initialize project manual",category:"project"},{name:"project:manual-show",description:"Show project manual",category:"project"},{name:"project:manual-sync",description:"Sync project manual",category:"project"},{name:"snapshot:list",description:"List snapshots",category:"snapshot"},{name:"snapshot:create",description:"Create snapshot",category:"snapshot"},{name:"snapshot:restore",description:"Restore snapshot",category:"snapshot"},{name:"recover",description:"Recover latest snapshot",category:"snapshot"},{name:"service",description:"Run daemon in foreground",category:"service"},{name:"service:install",description:"Install/start daemon",category:"service"},{name:"service:start",description:"Start daemon",category:"service"},{name:"service:stop",description:"Stop daemon",category:"service"},{name:"service:restart",description:"Restart daemon",category:"service"},{name:"service:status",description:"Show daemon status",category:"service"},{name:"service:remove",description:"Remove daemon",category:"service"},{name:"mcp",description:"Run MCP server",category:"advanced"},{name:"api",description:"Run API server",category:"advanced"},{name:"run",description:"Run ToolNet runtime",category:"advanced",hidden:!0},{name:"production:certify",description:"Verify production runtime",category:"advanced"},{name:"certify:continuity",description:"Certify work continuity",category:"advanced"}];function x(o){return{tty:o.tty,noColor:o.noColor}}function O(o){let e=[],n=o.version??"0.0.0",t=x(o);e.push(""),e.push(g("ToolNet Memory",n,t)),e.push(" Persistent memory & code intelligence for AI coding agents"),e.push(""),e.push(a("USAGE",t)),e.push(" toolnet-memory <command> [options]"),e.push("");let i=[{key:"core",title:"GET STARTED"},{key:"memory",title:"MEMORY"},{key:"code",title:"CODE"},{key:"system",title:"SYSTEM"}];for(let{key:s,title:d}of i){let c=u.filter(r=>r.category===s&&!r.hidden);if(c.length===0)continue;e.push(a(d,t));let y=Math.max(...c.map(r=>r.name.length));for(let r of c)e.push(l(r.name,r.description,y,t));e.push("")}return e.push(a("MORE",t)),e.push(l("help --all","Show all advanced commands",15,t)),e.push(l("help <command>","Show command details",15,t)),e.push(""),e.join(`
2
2
  `)}function j(o){let e=[],n=o.version??"0.0.0",t=x(o);e.push(""),e.push(g("ToolNet Memory",n,t)),e.push(" Persistent memory & code intelligence for AI coding agents"),e.push(""),e.push(a("USAGE",t)),e.push(" toolnet-memory <command> [options]"),e.push("");let i=[{key:"core",title:"PROJECT SETUP"},{key:"memory",title:"MEMORY"},{key:"code",title:"CODE INTELLIGENCE"},{key:"system",title:"SYSTEM"},{key:"context",title:"CONTEXT & MEMORY"},{key:"work",title:"WORK CONTINUITY"},{key:"integration",title:"AGENT INTEGRATIONS"},{key:"session",title:"SESSIONS"},{key:"guard",title:"GUARD"},{key:"project",title:"PROJECT MANUAL"},{key:"snapshot",title:"SNAPSHOTS & RECOVERY"},{key:"service",title:"BACKGROUND SERVICE"},{key:"advanced",title:"DEVELOPER / PRODUCTION"}];for(let{key:s,title:d}of i){let c=u.filter(r=>r.category===s&&!r.hidden);if(c.length===0)continue;e.push(a(d,t));let y=Math.max(...c.map(r=>r.name.length));for(let r of c)e.push(l(r.name,r.description,y,t));e.push("")}return e.join(`
3
- `)}function v(o,e){let n=u.find(s=>s.name===o||s.aliases?.includes(o));if(!n)return null;let t=[],i=x(e);if(t.push(""),t.push(g(n.name,void 0,i)),t.push(""),t.push(n.description),t.push(""),n.usage&&(t.push(a("USAGE",i)),t.push(` ${n.usage}`),t.push("")),n.aliases&&n.aliases.length>0){t.push(a("ALIASES",i));for(let s of n.aliases)t.push(` ${s}`);t.push("")}if(n.pipeline&&n.pipeline.length>0){t.push(a("PIPELINE",i));for(let s of n.pipeline)t.push(` ${s}`);t.push("")}if(n.examples&&n.examples.length>0){t.push(a("EXAMPLES",i));for(let s of n.examples)t.push(` ${s}`);t.push("")}return t.join(`
4
- `)}function S(o){return u.flatMap(t=>[t.name,...t.aliases??[]]).filter(t=>t===o?!1:!!(t.startsWith(o)||o.length>=3&&t.includes(o))).slice(0,3)}function P(){let o=M(D(import.meta.url)),e=[w(o,"../package.json"),w(o,"../../package.json")];for(let n of e)try{let t=JSON.parse(A(n,"utf8"));if(t.version)return t.version}catch{}return process.env.npm_package_version??"unknown"}var p=process.argv.slice(2),C={version:P(),tty:!!process.stdout.isTTY};function E(o){let e=S(o);if(console.error(""),console.error(`\u2715 Unknown command: ${o}`),e.length>0){console.error(""),console.error(" Did you mean:");for(let n of e)console.error(` ${n}`)}console.error(""),console.error(" Run `toolnet-memory help` to see available commands."),console.error("")}if(p[0]==="--unknown")E(p[1]??""),process.exitCode=1;else if(p[0]==="--all")console.log(j(C));else if(p[0]){let o=v(p[0],C);o?console.log(o):(E(p[0]),process.exitCode=1)}else console.log(O(C));
3
+ `)}function S(o,e){let n=u.find(s=>s.name===o||s.aliases?.includes(o));if(!n)return null;let t=[],i=x(e);if(t.push(""),t.push(g(n.name,void 0,i)),t.push(""),t.push(n.description),t.push(""),n.usage&&(t.push(a("USAGE",i)),t.push(` ${n.usage}`),t.push("")),n.aliases&&n.aliases.length>0){t.push(a("ALIASES",i));for(let s of n.aliases)t.push(` ${s}`);t.push("")}if(n.pipeline&&n.pipeline.length>0){t.push(a("PIPELINE",i));for(let s of n.pipeline)t.push(` ${s}`);t.push("")}if(n.examples&&n.examples.length>0){t.push(a("EXAMPLES",i));for(let s of n.examples)t.push(` ${s}`);t.push("")}return t.join(`
4
+ `)}function v(o){return u.flatMap(t=>[t.name,...t.aliases??[]]).filter(t=>t===o?!1:!!(t.startsWith(o)||o.length>=3&&t.includes(o))).slice(0,3)}function L(){let o=G(D(import.meta.url)),e=[w(o,"../package.json"),w(o,"../../package.json")];for(let n of e)try{let t=JSON.parse(A(n,"utf8"));if(t.version)return t.version}catch{}return process.env.npm_package_version??"unknown"}var p=process.argv.slice(2),C={version:L(),tty:!!process.stdout.isTTY};function E(o){let e=v(o);if(console.error(""),console.error(`\u2715 Unknown command: ${o}`),e.length>0){console.error(""),console.error(" Did you mean:");for(let n of e)console.error(` ${n}`)}console.error(""),console.error(" Run `toolnet-memory help` to see available commands."),console.error("")}if(p[0]==="--unknown")E(p[1]??""),process.exitCode=1;else if(p[0]==="--all")console.log(j(C));else if(p[0]){let o=S(p[0],C);o?console.log(o):(E(p[0]),process.exitCode=1)}else console.log(O(C));
package/bundle/impact.js CHANGED
@@ -1,4 +1,4 @@
1
- import"dotenv/config";import{existsSync as ue,readFileSync as fe}from"node:fs";import{homedir as me}from"node:os";import{join as ge}from"node:path";function he(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 ye(){let s=process.env.TOOLNET_GLOBAL_ENV??ge(me(),".config","toolnet-memory",".env");if(!ue(s))return;let e=fe(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]=he(r.slice(n+1)))}}ye();function S(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function b(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function B(){return{memory:{autoCapture:S(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:S(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:S(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:S(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:b(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:b(process.env.MEMORY_RERANK_TOP,10),finalContext:b(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:b(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:S(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:b(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Se}from"node:crypto";import{existsSync as R,mkdirSync as be,readFileSync as xe,renameSync as Ce,writeFileSync as Ee}from"node:fs";import{basename as we,dirname as T,join as x,parse as Y,resolve as y}from"node:path";var J=".toolnet",ve="project.json";function ke(s){return Se("sha256").update(s).digest("hex").slice(0,16)}function M(s){return x(s,J,ve)}function Pe(s){return R(M(s))}function W(s,e){let t=y(s),r=Y(t).root;for(;;){if(Pe(t))return t;if(t===r||e&&t===y(e))break;let n=T(t);if(n===t)break;t=n}return null}function U(s){let e=y(s),t=Y(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>R(x(e,o))))return e;if(e===t)break;let n=T(e);if(n===e)break;e=n}return y(s)}function H(s){let e;try{e=JSON.parse(xe(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:T(T(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 V(s,e){let t=x(s,J);be(t,{recursive:!0});let r=M(s),n=`${r}.tmp-${process.pid}`;Ee(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Ce(n,r)}function G(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 A=class{findExisting(e=process.cwd()){let t=y(e),r=U(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>R(x(r,d))),i=W(t,o?r:void 0);if(!i)return null;let a=H(M(i));return G(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=y(e),r=U(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>R(x(r,p))),i=W(t,o?r:void 0);if(i){let p=M(i),m=H(p);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),V(i,m)),G(m,i)}let a=new Date().toISOString(),d=we(r),l={version:1,id:ke(r),name:d,remote:d,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return V(r,l),G(l,r)}};var Re=[{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"}],Te=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function q(s){return s.normalize("NFKC").trim().toLowerCase()}function Me(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 Ae(s){return/^[a-f0-9]{32}$/iu.test(s)||/^[a-f0-9]{40}$/iu.test(s)||/^[a-f0-9]{64}$/iu.test(s)}function je(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 Ie(s,e){return s.start<e.end&&e.start<s.end}function Z(s){return s.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var j=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=q(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of Re){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=Z(t),n=[];for(let o of r)n.some(i=>Ie(i,o))||n.push(o);return Z(n)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=q(e);return Te.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)||Ae(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||je(e,n.index,n.index+o.length)&&(Me(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:n.index,end:n.index+o.length,confidence:"heuristic"}))}return t}};var C=class{scanner;constructor(e={}){this.scanner=new j(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 Lt=new C;import{homedir as tt}from"node:os";import{join as rt}from"node:path";import{DeleteObjectCommand as Le,GetObjectCommand as Ne,HeadObjectCommand as Oe,ListObjectsV2Command as _e,PutObjectCommand as Fe,S3Client as De}from"@aws-sdk/client-s3";import{getSignedUrl as $e}from"@aws-sdk/s3-request-presigner";var I=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new De({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 Fe({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await $e(this.client,new Ne({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 Oe({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 Le({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new _e({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 Q,mkdir as Ge,readFile as ze,readdir as Ke,rm as Be,stat as X,writeFile as We}from"node:fs/promises";import{dirname as Ue,join as He,relative as ee,resolve as Ve}from"node:path";var E=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ve(this.root,t)}async put(e,t){let r=this.path(e);await Ge(Ue(r),{recursive:!0}),await We(r,t)}async get(e){try{return await ze(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 Q(this.path(e)),!0}catch{return!1}}async delete(e){await Be(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await Q(t)}catch{return r}let n=async i=>{let a=await Ke(i,{withFileTypes:!0});for(let d of a){let l=He(i,d.name);if(d.isDirectory()){await n(l);continue}let p=await X(l);r.push({key:ee(this.root,l),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await X(t);return o.isDirectory()?await n(t):r.push({key:ee(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as Ye,GetObjectCommand as Je,HeadObjectCommand as qe,ListObjectsV2Command as Ze,PutObjectCommand as Qe,S3Client as Xe}from"@aws-sdk/client-s3";import{getSignedUrl as et}from"@aws-sdk/s3-request-presigner";var w=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Xe({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 Qe({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await et(this.client,new Je({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 qe({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 Ye({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new Ze({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 z(s,e){return console.warn(e),new E(s)}function te(s){let e=s.localRoot??rt(tt(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new w({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):z(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(s.provider==="s3"){let t=s.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new w({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):z(e,"[storage] S3 credentials missing. Using local fallback.")}if(s.provider==="huggingface"){let t=s.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new I({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):z(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new E(e)}var v=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")}};function st(s){return new Promise(e=>setTimeout(e,s))}async function re(s,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,n=e.maxDelayMs??2e3,o;for(let i=1;i<=t;i++)try{return await s()}catch(a){if(o=a,i>=t)break;let d=Math.min(n,r*2**(i-1)),l=Math.floor(Math.random()*Math.max(1,d*.2));await st(d+l)}throw o}var nt=new Set(["put","get","getText","delete","list"]);function se(s,e={}){return new Proxy(s,{get(t,r){let n=Reflect.get(t,r,t);return typeof n!="function"?n:nt.has(r)?(...o)=>re(()=>Promise.resolve(n.apply(t,o)),e):n.bind(t)}})}function ne(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 oe(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 L=class{constructor(e,t,r,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=ne(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=oe(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,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))}};var bs=2*1024*1024;var k=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)}};import*as u from"typescript";function ct(s,e){return e.ranges.length===0?!0:typeof s.startLine!="number"||typeof s.endLine!="number"?!1:e.ranges.some(t=>s.startLine<=t.endLine&&s.endLine>=t.startLine)}var N=class{constructor(e){this.graph=e}graph;map(e,t){let r=this.graph.allSymbols(e),n=[];for(let o of t){let i=r.filter(l=>l.filePath===o.filePath),d=i.filter(l=>l.type!=="file").filter(l=>ct(l,o));if(d.length===0){let l=i.find(p=>p.type==="file");l&&n.push({symbol:l,fileStatus:o.status,direct:!0});continue}for(let l of d)n.push({symbol:l,fileStatus:o.status,direct:!0})}return n}mapFile(e,t){return this.map(e,[{filePath:t,status:"modified",ranges:[]}])}};var lt={CALLS:4,CALL_REFERENCE:6,USES_TYPE:4,TESTS:2,ROUTE:4,WRITES:3,IMPORTS:3,INHERITS:5,IMPLEMENTS:5,DEFINES:1};function dt(s){return s>=30?"CRITICAL":s>=16?"HIGH":s>=6?"MEDIUM":"LOW"}function ae(s){let e=s.toLowerCase().replaceAll("\\","/");return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}var O=class{constructor(e){this.graph=e}graph;analyze(e,t,r=4){let n=this.graph.allEdges(e),o=new Map,i=0;for(let p of t){p.fileStatus==="deleted"?i+=8:p.fileStatus==="renamed"?i+=5:i+=2,p.symbol.type==="interface"&&(i+=5),p.symbol.type==="class"&&(i+=3);let m=new Set([p.symbol.id]),F=[{id:p.symbol.id,depth:0}];for(;F.length;){let D=F.shift();if(D.depth>=r)continue;let le=n.filter(g=>g.to===D.id&&["CALLS","CALL_REFERENCE","USES_TYPE","TESTS","ROUTE","WRITES","IMPORTS","INHERITS","IMPLEMENTS","DEFINES"].includes(g.type));for(let g of le){if(m.has(g.from))continue;m.add(g.from);let P=this.graph.getSymbol(g.from);if(!P)continue;let $=D.depth+1,de=`${p.symbol.id}:${P.id}`;o.set(de,{symbol:P,relation:g.type,depth:$,sourceSymbolId:p.symbol.id});let pe=lt[g.type]??1;i+=Math.max(1,pe-($-1)),F.push({id:P.id,depth:$})}}}let a=[...o.values()].sort((p,m)=>p.depth-m.depth),d=[...new Set(a.map(p=>p.symbol.filePath))],l=d.filter(ae);return l.length===0&&l.push(...d.filter(p=>!ae(p)).slice(0,10)),{risk:dt(i),riskScore:i,changedSymbols:t,impacted:a,impactedFiles:d,suggestedTests:l}}};import{execFile as pt}from"node:child_process";import{promisify as ut}from"node:util";var K=ut(pt);function ft(s){let e=[],t=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm;for(let r of s.matchAll(t)){let n=Number(r[1]),o=Number(r[2]??1);e.push({startLine:n,endLine:Math.max(n,n+o-1)})}return e}function mt(s){return s.startsWith("A")?"added":s.startsWith("D")?"deleted":s.startsWith("R")?"renamed":"modified"}async function ce(s){let e="";try{e=(await K("git",["diff","HEAD","--name-status","--no-renames"],{cwd:s,maxBuffer:10485760})).stdout}catch{return[]}let t=[];for(let r of e.split(/\r?\n/).filter(Boolean)){let[n,...o]=r.split(" "),i=o.at(-1);if(!i)continue;let a="";try{a=(await K("git",["diff","HEAD","--unified=0","--",i],{cwd:s,maxBuffer:20971520})).stdout}catch{a=""}t.push({filePath:i,status:mt(n),ranges:ft(a)})}try{let r=await K("git",["ls-files","--others","--exclude-standard"],{cwd:s});for(let n of r.stdout.split(/\r?\n/).filter(Boolean))t.some(o=>o.filePath===n)||t.push({filePath:n,status:"added",ranges:[]})}catch{}return t}var _=class{constructor(e){this.graph=e;this.mapper=new N(e),this.blast=new O(e)}graph;mapper;blast;async analyzeGitDiff(e,t,r={}){let n=await ce(t),o=this.mapper.map(e,n),i=this.blast.analyze(e,o,r.maxDepth??4);return{mode:"git_diff",changes:n,...i}}analyzeFile(e,t,r={}){let n=this.mapper.mapFile(e,t);return{mode:"planned_file",filePath:t,...this.blast.analyze(e,n,r.maxDepth??4)}}};import*as h from"typescript";import{DatabaseSync as jn}from"node:sqlite";import*as f from"typescript";import*as c from"typescript";var Xn=new Set([c.SyntaxKind.EqualsToken,c.SyntaxKind.PlusEqualsToken,c.SyntaxKind.MinusEqualsToken,c.SyntaxKind.AsteriskEqualsToken,c.SyntaxKind.SlashEqualsToken,c.SyntaxKind.PercentEqualsToken,c.SyntaxKind.QuestionQuestionEqualsToken,c.SyntaxKind.AmpersandAmpersandEqualsToken,c.SyntaxKind.BarBarEqualsToken]);async function yt(){let s=B(),e=new A().detect(),t=se(te({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),{attempts:3}),r=new L(t,e.id,e.name,e.remote??e.name),n=await new v(r).load(e.id);if(!n)throw new Error("Code graph missing");let o=new k;o.import(n.symbols,n.edges);let i=new _(o),a=process.argv[2],d=a?i.analyzeFile(e.id,a):await i.analyzeGitDiff(e.id,e.rootPath);console.log({risk:d.risk,riskScore:d.riskScore,changedSymbols:d.changedSymbols.map(l=>({symbol:l.symbol.qualifiedName,file:l.symbol.filePath,type:l.symbol.type})),impactedFiles:d.impactedFiles,suggestedTests:d.suggestedTests,impactedCount:d.impacted.length})}yt().catch(s=>{console.error(s),process.exit(1)});
1
+ import"dotenv/config";import{existsSync as Ee,readFileSync as we}from"node:fs";import{homedir as ve}from"node:os";import{join as Re}from"node:path";function ke(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 Pe(){let n=process.env.TOOLNET_GLOBAL_ENV??Re(ve(),".config","toolnet-memory",".env");if(!Ee(n))return;let e=we(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]=ke(r.slice(s+1)))}}Pe();function C(n,e){return n===void 0?e:["1","true","yes","on"].includes(n.toLowerCase())}function E(n,e){if(!n)return e;let t=Number(n);return Number.isFinite(t)?t:e}function q(){return{memory:{autoCapture:C(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:C(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:C(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:C(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:E(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:E(process.env.MEMORY_RERANK_TOP,10),finalContext:E(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:E(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:C(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:E(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Ne}from"node:crypto";import{existsSync as L,mkdirSync as _e,readFileSync as Oe,renameSync as Fe,writeFileSync as De}from"node:fs";import{basename as $e,dirname as N,join as v,parse as ne,resolve as b}from"node:path";import{createHash as Z}from"node:crypto";import{spawnSync as Ae}from"node:child_process";var w="git-remote-v1",Me=new Set(["github.com","gitlab.com","bitbucket.org"]);function X(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:(Me.has(n)&&(t=t.toLowerCase()),t)}function Te(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=X(t,e.pathname);return o?`${s}/${o}`:null}function Ie(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=X(t,e[2]??"");return r?`${t}/${r}`:null}function J(n){let e=n.trim();return e?e.includes("://")?Te(e):Ie(e):null}function je(n){return Z("sha256").update(`${w}:${n}`).digest("hex")}function ee(n){return Z("sha256").update(`toolnet-project:${w}:${n}`).digest("hex").slice(0,16)}function Le(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function H(n,e){let t=Ae("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function Q(n,e){let t=Le(n);return t?{scheme:w,canonicalRemote:n,fingerprint:je(n),repositoryName:t,source:e}:null}function te(n){let e=H(n,["remote","get-url","origin"]);if(e){let s=J(e);if(s)return Q(s,"origin")}let t=H(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=H(n,["remote","get-url",s]);if(!o)continue;let i=J(o);i&&r.add(i)}return r.size!==1?null:Q([...r][0],"unique-remote")}var se=".toolnet",Ge="project.json";function Ke(n){return Ne("sha256").update(n).digest("hex").slice(0,16)}function x(n){return v(n,se,Ge)}function oe(n){return L(x(n))}function re(n,e){let t=b(n),r=ne(t).root;for(;;){if(oe(t))return t;if(t===r||e&&t===b(e))break;let s=N(t);if(s===t)break;t=s}return null}function W(n){let e=b(n),t=ne(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>L(v(e,o))))return e;if(e===t)break;let s=N(e);if(s===e)break;e=s}return b(n)}function I(n){let e;try{e=JSON.parse(Oe(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:N(N(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 j(n,e){let t=v(n,se);_e(t,{recursive:!0});let r=x(n),s=`${r}.tmp-${process.pid}`;De(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Fe(s,r)}function S(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 U(n){return{version:1,scheme:w,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function ze(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 _=class{adopt(e,t){let r=W(b(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(oe(r)){let a=I(x(r));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return S(a,r)}let s=new Date().toISOString(),o={...t.metadata};t.gitIdentity&&(o.toolnetIdentity=U(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 j(r,i),S(i,r)}recordGitIdentity(e,t,r={}){let s=this.requireExisting(e),o=x(s.rootPath),i=I(o),a=ze(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 c=i.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:U(t)},i.updatedAt=new Date().toISOString(),j(s.rootPath,i)),S(i,s.rootPath)}findExisting(e=process.cwd()){let t=b(e),r=W(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>L(v(r,c))),i=re(t,o?r:void 0);if(!i)return null;let a=I(x(i));return S(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=b(e),r=W(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(g=>L(v(r,g))),i=re(t,o?r:void 0);if(i){let g=x(i),f=I(g);return f.rootPath!==i&&(f.rootPath=i,f.updatedAt=new Date().toISOString(),j(i,f)),S(f,i)}let a=new Date().toISOString(),c=$e(r),l=te(r),p={version:1,id:l?ee(l.canonicalRemote):Ke(r),name:c,remote:l?.repositoryName??c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:l?{toolnetIdentity:U(l)}:void 0};return j(r,p),S(p,r)}};var Be=[{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"}],He=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ie(n){return n.normalize("NFKC").trim().toLowerCase()}function We(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 Ue(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function Ve(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 Ye(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 O=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=ie(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of Be){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=>Ye(i,o))||s.push(o);return ae(s)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ie(e);return He.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)||Ue(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||Ve(e,s.index,s.index+o.length)&&(We(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return t}};var R=class{scanner;constructor(e={}){this.scanner=new O(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 Xt=new R;import{homedir as yt}from"node:os";import{join as St}from"node:path";import{DeleteObjectCommand as qe,GetObjectCommand as Je,HeadObjectCommand as Qe,ListObjectsV2Command as Ze,PutObjectCommand as Xe,S3Client as et}from"@aws-sdk/client-s3";import{getSignedUrl as tt}from"@aws-sdk/s3-request-presigner";var F=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new et({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 Xe({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await tt(this.client,new Je({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 Qe({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 qe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new Ze({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 ce,mkdir as rt,readFile as nt,readdir as st,rm as ot,stat as le,writeFile as it}from"node:fs/promises";import{dirname as at,join as ct,relative as de,resolve as lt}from"node:path";var k=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return lt(this.root,t)}async put(e,t){let r=this.path(e);await rt(at(r),{recursive:!0}),await it(r,t)}async get(e){try{return await nt(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 ce(this.path(e)),!0}catch{return!1}}async delete(e){await ot(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await ce(t)}catch{return r}let s=async i=>{let a=await st(i,{withFileTypes:!0});for(let c of a){let l=ct(i,c.name);if(c.isDirectory()){await s(l);continue}let p=await le(l);r.push({key:de(this.root,l),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await le(t);return o.isDirectory()?await s(t):r.push({key:de(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as dt,GetObjectCommand as pt,HeadObjectCommand as ut,ListObjectsV2Command as mt,PutObjectCommand as ft,S3Client as gt}from"@aws-sdk/client-s3";import{getSignedUrl as ht}from"@aws-sdk/s3-request-presigner";var P=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new gt({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 ft({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await ht(this.client,new pt({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 ut({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 dt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new mt({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}};function V(n,e){return console.warn(e),new k(n)}function pe(n){let e=n.localRoot??St(yt(),".toolnet-memory","storage");if(n.provider==="r2"){let t=n.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new P({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):V(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(n.provider==="s3"){let t=n.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new P({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):V(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?new F({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):V(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new k(e)}var A=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")}};function bt(n){return new Promise(e=>setTimeout(e,n))}async function ue(n,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let i=1;i<=t;i++)try{return await n()}catch(a){if(o=a,i>=t)break;let c=Math.min(s,r*2**(i-1)),l=Math.floor(Math.random()*Math.max(1,c*.2));await bt(c+l)}throw o}var xt=new Set(["put","get","getText","delete","list"]);function me(n,e={}){return new Proxy(n,{get(t,r){let s=Reflect.get(t,r,t);return typeof s!="function"?s:xt.has(r)?(...o)=>ue(()=>Promise.resolve(s.apply(t,o)),e):s.bind(t)}})}function fe(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 ge(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 D=class{constructor(e,t,r,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=fe(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)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ge(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))}};var Hn=2*1024*1024;var M=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)}};import*as u from"typescript";function vt(n,e){return e.ranges.length===0?!0:typeof n.startLine!="number"||typeof n.endLine!="number"?!1:e.ranges.some(t=>n.startLine<=t.endLine&&n.endLine>=t.startLine)}var $=class{constructor(e){this.graph=e}graph;map(e,t){let r=this.graph.allSymbols(e),s=[];for(let o of t){let i=r.filter(l=>l.filePath===o.filePath),c=i.filter(l=>l.type!=="file").filter(l=>vt(l,o));if(c.length===0){let l=i.find(p=>p.type==="file");l&&s.push({symbol:l,fileStatus:o.status,direct:!0});continue}for(let l of c)s.push({symbol:l,fileStatus:o.status,direct:!0})}return s}mapFile(e,t){return this.map(e,[{filePath:t,status:"modified",ranges:[]}])}};var Rt={CALLS:4,CALL_REFERENCE:6,USES_TYPE:4,TESTS:2,ROUTE:4,WRITES:3,IMPORTS:3,INHERITS:5,IMPLEMENTS:5,DEFINES:1};function kt(n){return n>=30?"CRITICAL":n>=16?"HIGH":n>=6?"MEDIUM":"LOW"}function ye(n){let e=n.toLowerCase().replaceAll("\\","/");return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}var G=class{constructor(e){this.graph=e}graph;analyze(e,t,r=4){let s=this.graph.allEdges(e),o=new Map,i=0;for(let p of t){p.fileStatus==="deleted"?i+=8:p.fileStatus==="renamed"?i+=5:i+=2,p.symbol.type==="interface"&&(i+=5),p.symbol.type==="class"&&(i+=3);let g=new Set([p.symbol.id]),f=[{id:p.symbol.id,depth:0}];for(;f.length;){let z=f.shift();if(z.depth>=r)continue;let be=s.filter(h=>h.to===z.id&&["CALLS","CALL_REFERENCE","USES_TYPE","TESTS","ROUTE","WRITES","IMPORTS","INHERITS","IMPLEMENTS","DEFINES"].includes(h.type));for(let h of be){if(g.has(h.from))continue;g.add(h.from);let T=this.graph.getSymbol(h.from);if(!T)continue;let B=z.depth+1,xe=`${p.symbol.id}:${T.id}`;o.set(xe,{symbol:T,relation:h.type,depth:B,sourceSymbolId:p.symbol.id});let Ce=Rt[h.type]??1;i+=Math.max(1,Ce-(B-1)),f.push({id:T.id,depth:B})}}}let a=[...o.values()].sort((p,g)=>p.depth-g.depth),c=[...new Set(a.map(p=>p.symbol.filePath))],l=c.filter(ye);return l.length===0&&l.push(...c.filter(p=>!ye(p)).slice(0,10)),{risk:kt(i),riskScore:i,changedSymbols:t,impacted:a,impactedFiles:c,suggestedTests:l}}};import{execFile as Pt}from"node:child_process";import{promisify as At}from"node:util";var Y=At(Pt);function Mt(n){let e=[],t=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm;for(let r of n.matchAll(t)){let s=Number(r[1]),o=Number(r[2]??1);e.push({startLine:s,endLine:Math.max(s,s+o-1)})}return e}function Tt(n){return n.startsWith("A")?"added":n.startsWith("D")?"deleted":n.startsWith("R")?"renamed":"modified"}async function Se(n){let e="";try{e=(await Y("git",["diff","HEAD","--name-status","--no-renames"],{cwd:n,maxBuffer:10485760})).stdout}catch{return[]}let t=[];for(let r of e.split(/\r?\n/).filter(Boolean)){let[s,...o]=r.split(" "),i=o.at(-1);if(!i)continue;let a="";try{a=(await Y("git",["diff","HEAD","--unified=0","--",i],{cwd:n,maxBuffer:20971520})).stdout}catch{a=""}t.push({filePath:i,status:Tt(s),ranges:Mt(a)})}try{let r=await Y("git",["ls-files","--others","--exclude-standard"],{cwd:n});for(let s of r.stdout.split(/\r?\n/).filter(Boolean))t.some(o=>o.filePath===s)||t.push({filePath:s,status:"added",ranges:[]})}catch{}return t}var K=class{constructor(e){this.graph=e;this.mapper=new $(e),this.blast=new G(e)}graph;mapper;blast;async analyzeGitDiff(e,t,r={}){let s=await Se(t),o=this.mapper.map(e,s),i=this.blast.analyze(e,o,r.maxDepth??4);return{mode:"git_diff",changes:s,...i}}analyzeFile(e,t,r={}){let s=this.mapper.mapFile(e,t);return{mode:"planned_file",filePath:t,...this.blast.analyze(e,s,r.maxDepth??4)}}};import*as y from"typescript";import{DatabaseSync as to}from"node:sqlite";import*as m from"typescript";import*as d from"typescript";var To=new Set([d.SyntaxKind.EqualsToken,d.SyntaxKind.PlusEqualsToken,d.SyntaxKind.MinusEqualsToken,d.SyntaxKind.AsteriskEqualsToken,d.SyntaxKind.SlashEqualsToken,d.SyntaxKind.PercentEqualsToken,d.SyntaxKind.QuestionQuestionEqualsToken,d.SyntaxKind.AmpersandAmpersandEqualsToken,d.SyntaxKind.BarBarEqualsToken]);async function Lt(){let n=q(),e=new _().detect(),t=me(pe({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:3}),r=new D(t,e.id,e.name,e.remote??e.name),s=await new A(r).load(e.id);if(!s)throw new Error("Code graph missing");let o=new M;o.import(s.symbols,s.edges);let i=new K(o),a=process.argv[2],c=a?i.analyzeFile(e.id,a):await i.analyzeGitDiff(e.id,e.rootPath);console.log({risk:c.risk,riskScore:c.riskScore,changedSymbols:c.changedSymbols.map(l=>({symbol:l.symbol.qualifiedName,file:l.symbol.filePath,type:l.symbol.type})),impactedFiles:c.impactedFiles,suggestedTests:c.suggestedTests,impactedCount:c.impacted.length})}Lt().catch(n=>{console.error(n),process.exit(1)});