toolnet-memory 0.3.14 → 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.
- package/.env.example +0 -1
- package/.release-target +1 -1
- package/README.md +182 -6
- package/bin/toolnet-memory +5 -0
- package/bundle/agy-hook.js +71 -71
- package/bundle/agy.js +65 -65
- package/bundle/api.js +15 -15
- package/bundle/auto-integrate.js +28 -28
- package/bundle/background-refresh.js +7 -7
- package/bundle/claude-hook.js +51 -50
- package/bundle/codex-context.js +29 -28
- package/bundle/codex.js +77 -77
- package/bundle/context-runtime.js +44 -43
- package/bundle/context.js +15 -15
- package/bundle/continuity-certify.js +13 -13
- package/bundle/copilot-hook.js +88 -86
- package/bundle/copilot.js +4 -4
- package/bundle/cursor-hook.js +88 -86
- package/bundle/cursor.js +4 -4
- package/bundle/doctor.js +4 -4
- package/bundle/full-index.js +21 -21
- package/bundle/gc.js +3 -0
- package/bundle/graph-index.js +4 -4
- package/bundle/graph-ui.js +3 -3
- package/bundle/grok-hook.js +64 -63
- package/bundle/grok.js +5 -5
- package/bundle/handoff-refresh.js +10 -10
- package/bundle/help-cli.js +3 -3
- package/bundle/impact.js +4 -4
- package/bundle/incremental.js +5 -4
- package/bundle/init.js +38 -37
- package/bundle/integration-status.js +4 -4
- package/bundle/kiro-hook.js +93 -92
- package/bundle/learner.js +6 -6
- package/bundle/mcp.js +17 -17
- package/bundle/memory-agent.js +7 -7
- package/bundle/memory-query.js +7 -7
- package/bundle/opencode.js +84 -84
- package/bundle/project-manual.js +7 -7
- package/bundle/recovery-certify.js +15 -15
- package/bundle/runtime.js +13 -12
- package/bundle/semantic.js +5 -5
- package/bundle/snapshot.js +4 -4
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +60 -60
- package/bundle/work-continuity.js +7 -7
- package/package.json +21 -3
- package/release-manifest.json +104 -3
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function
|
|
3
|
-
`,{encoding:"utf8",mode:384}),Re(n,s)}function Z(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var j=class{detect(e=process.cwd()){let t=S(e),s=Oe(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>T(A(s,m))),a=Ee(t,i?s:void 0);if(a){let m=E(a),g=_e(m);return g.rootPath!==a&&(g.rootPath=a,g.updatedAt=new Date().toISOString(),Q(a,g)),Z(g,a)}let c=new Date().toISOString(),d=Pe(s),p={version:1,id:Ie(s),name:d,remote:d,rootPath:s,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return Q(s,p),Z(p,s)}};import{homedir as st}from"node:os";import{join as ot}from"node:path";import{DeleteObjectCommand as Ne,GetObjectCommand as $e,HeadObjectCommand as Ke,ListObjectsV2Command as De,PutObjectCommand as ze,S3Client as Le}from"@aws-sdk/client-s3";import{getSignedUrl as Ve}from"@aws-sdk/s3-request-presigner";var R=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Le({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,s="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ze({Bucket:this.bucket,Key:e,Body:n,ContentType:s}))}async get(e){let t=await Ve(this.client,new $e({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`HF download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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 Ke({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 Ne({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],s;do{let n=await this.client.send(new De({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return t}};import{access as ee,mkdir as We,readFile as Fe,readdir as Be,rm as Je,stat as te,writeFile as Ue}from"node:fs/promises";import{dirname as He,join as Ye,relative as re,resolve as Ge}from"node:path";var v=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ge(this.root,t)}async put(e,t){let s=this.path(e);await We(He(s),{recursive:!0}),await Ue(s,t)}async get(e){try{return await Fe(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 ee(this.path(e)),!0}catch{return!1}}async delete(e){await Je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),s=[];try{await ee(t)}catch{return s}let n=async a=>{let c=await Be(a,{withFileTypes:!0});for(let d of c){let p=Ye(a,d.name);if(d.isDirectory()){await n(p);continue}let m=await te(p);s.push({key:re(this.root,p),size:m.size,updatedAt:m.mtime.toISOString()})}},i=await te(t);return i.isDirectory()?await n(t):s.push({key:re(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),s}};import{DeleteObjectCommand as Qe,GetObjectCommand as Ze,HeadObjectCommand as qe,ListObjectsV2Command as Xe,PutObjectCommand as et,S3Client as tt}from"@aws-sdk/client-s3";import{getSignedUrl as rt}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 tt({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,s="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new et({Bucket:this.bucket,Key:e,Body:n,ContentType:s}))}async get(e){let t=await rt(this.client,new Ze({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`${this.name} download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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=[],s;do{let n=await this.client.send(new Xe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return t}};function O(r,e){return console.warn(e),new v(r)}function se(r){let e=r.localRoot??ot(st(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.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}):O(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new 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}):O(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new R({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):O(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new v(e)}function nt(r){return new Promise(e=>setTimeout(e,r))}async function oe(r,e={}){let t=Math.max(1,e.attempts??3),s=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let d=Math.min(n,s*2**(a-1)),p=Math.floor(Math.random()*Math.max(1,d*.2));await nt(d+p)}throw i}var it=new Set(["put","get","getText","delete","list"]);function ne(r,e={}){return new Proxy(r,{get(t,s){let n=Reflect.get(t,s,t);return typeof n!="function"?n:it.has(s)?(...i)=>oe(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}function ie(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function ae(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(s)return`${s[1]}memory/records/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),s)return`${s[1]}memory/vectors/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),s)return`${s[1]}code/graph/${s[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 M=class{constructor(e,t,s,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=s,this.folder=ie(n??s),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(),s=t,n=await this.provider.getText(e);if(n){let a;try{a=JSON.parse(n)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(s=a.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:s,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
|
|
4
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=
|
|
5
|
-
`,{encoding:"utf8",mode:384}),
|
|
6
|
-
`,"application/json"),
|
|
1
|
+
import{existsSync as Oe,readFileSync as Ne}from"node:fs";import{homedir as Ke}from"node:os";import{join as $e}from"node:path";function De(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Le(){let r=process.env.TOOLNET_GLOBAL_ENV??$e(Ke(),".config","toolnet-memory",".env");if(!Oe(r))return;let e=Ne(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=De(n.slice(o+1)))}}Le();function x(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function w(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function oe(){return{memory:{autoCapture:x(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:x(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:x(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:x(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:w(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:w(process.env.MEMORY_RERANK_TOP,10),finalContext:w(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:w(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:x(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:w(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as He}from"node:crypto";import{existsSync as C,mkdirSync as Je,readFileSync as Ue,renameSync as Ye,writeFileSync as qe}from"node:fs";import{basename as Ze,dirname as E,join as j,parse as pe,resolve as S}from"node:path";import{createHash as ae}from"node:crypto";import{spawnSync as ze}from"node:child_process";var v="git-remote-v1",Ve=new Set(["github.com","gitlab.com","bitbucket.org"]);function ce(r,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(n=>!n||n==="."||n==="..")?null:(Ve.has(r)&&(t=t.toLowerCase()),t)}function Fe(r){let e;try{e=new URL(r)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let n=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!n?`${t}:${e.port}`:t,s=ce(t,e.pathname);return s?`${o}/${s}`:null}function We(r){let e=r.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let n=ce(t,e[2]??"");return n?`${t}/${n}`:null}function se(r){let e=r.trim();return e?e.includes("://")?Fe(e):We(e):null}function Be(r){return ae("sha256").update(`${v}:${r}`).digest("hex")}function de(r){return ae("sha256").update(`toolnet-project:${v}:${r}`).digest("hex").slice(0,16)}function Ge(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function z(r,e){let t=ze("git",["-C",r,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function ie(r,e){let t=Ge(r);return t?{scheme:v,canonicalRemote:r,fingerprint:Be(r),repositoryName:t,source:e}:null}function ue(r){let e=z(r,["remote","get-url","origin"]);if(e){let o=se(e);if(o)return ie(o,"origin")}let t=z(r,["remote"]);if(!t)return null;let n=new Set;for(let o of t.split(/\r?\n/u).map(s=>s.trim()).filter(Boolean)){let s=z(r,["remote","get-url",o]);if(!s)continue;let a=se(s);a&&n.add(a)}return n.size!==1?null:ie([...n][0],"unique-remote")}var me=".toolnet",Qe="project.json";function Xe(r){return He("sha256").update(r).digest("hex").slice(0,16)}function b(r){return j(r,me,Qe)}function fe(r){return C(b(r))}function le(r,e){let t=S(r),n=pe(t).root;for(;;){if(fe(t))return t;if(t===n||e&&t===S(e))break;let o=E(t);if(o===t)break;t=o}return null}function V(r){let e=S(r),t=pe(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>C(j(e,s))))return e;if(e===t)break;let o=E(e);if(o===e)break;e=o}return S(r)}function I(r){let e;try{e=JSON.parse(Ue(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:E(E(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function P(r,e){let t=j(r,me);Je(t,{recursive:!0});let n=b(r),o=`${n}.tmp-${process.pid}`;qe(o,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),Ye(o,n)}function h(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}function F(r){return{version:1,scheme:v,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function et(r){let e=r.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var T=class{adopt(e,t){let n=V(S(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(fe(n)){let c=I(b(n));if(c.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${c.id}`,`requested=${t.id}`].join(" "));return h(c,n)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=F(t.gitIdentity));let a={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:n,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return P(n,a),h(a,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),s=b(o.rootPath),a=I(s),c=et(a);if(c&&c!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${c}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let d=a.metadata?.toolnetIdentity;return d&&typeof d=="object"&&!Array.isArray(d)&&d.fingerprint===t.fingerprint||(a.metadata={...a.metadata,toolnetIdentity:F(t)},a.updatedAt=new Date().toISOString(),P(o.rootPath,a)),h(a,o.rootPath)}findExisting(e=process.cwd()){let t=S(e),n=V(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>C(j(n,d))),a=le(t,s?n:void 0);if(!a)return null;let c=I(b(a));return h(c,a)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=S(e),n=V(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(k=>C(j(n,k))),a=le(t,s?n:void 0);if(a){let k=b(a),g=I(k);return g.rootPath!==a&&(g.rootPath=a,g.updatedAt=new Date().toISOString(),P(a,g)),h(g,a)}let c=new Date().toISOString(),d=Ze(n),u=ue(n),f={version:1,id:u?de(u.canonicalRemote):Xe(n),name:d,remote:u?.repositoryName??d,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0,metadata:u?{toolnetIdentity:F(u)}:void 0};return P(n,f),h(f,n)}};var tt=[{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"}],rt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ge(r){return r.normalize("NFKC").trim().toLowerCase()}function nt(r){if(r.length===0)return 0;let e=new Map;for(let n of r)e.set(n,(e.get(n)??0)+1);let t=0;for(let n of e.values()){let o=n/r.length;t-=o*Math.log2(o)}return t}function ot(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function st(r,e,t){let n=r.slice(Math.max(0,e-48),e),o=r.slice(t,Math.min(r.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${o}`)}function it(r,e){return r.start<e.end&&e.start<r.end}function ye(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var _=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=ge(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of tt){let a=new RegExp(s.regex.source,s.regex.flags);for(let c of e.matchAll(a))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:s.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ye(t),o=[];for(let s of n)o.some(a=>it(a,s))||o.push(s);return ye(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ge(e);return rt.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(n)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||ot(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||st(e,o.index,o.index+s.length)&&(nt(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var O=class{scanner;constructor(e={}){this.scanner=new _(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let n=e,o=[...t].sort((a,c)=>c.start-a.start),s=new Set;for(let a of o)s.add(a.type),n=n.slice(0,a.start)+`[REDACTED:${a.type}]`+n.slice(a.end);return{text:n,redacted:t.length,secretTypes:[...s].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[n,o]of Object.entries(e)){let s=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){t[n]="[REDACTED]";continue}t[n]=this.sanitizeValue(o)}return t}return e}};var dr=new O;import{homedir as Pt}from"node:os";import{join as Ct}from"node:path";import{DeleteObjectCommand as at,GetObjectCommand as ct,HeadObjectCommand as dt,ListObjectsV2Command as ut,PutObjectCommand as lt,S3Client as pt}from"@aws-sdk/client-s3";import{getSignedUrl as mt}from"@aws-sdk/s3-request-presigner";var N=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new pt({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new lt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await mt(this.client,new ct({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new dt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new at({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new ut({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as he,mkdir as ft,readFile as gt,readdir as yt,rm as ht,stat as Se,writeFile as St}from"node:fs/promises";import{dirname as kt,join as bt,relative as ke,resolve as xt}from"node:path";var A=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return xt(this.root,t)}async put(e,t){let n=this.path(e);await ft(kt(n),{recursive:!0}),await St(n,t)}async get(e){try{return await gt(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await he(this.path(e)),!0}catch{return!1}}async delete(e){await ht(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await he(t)}catch{return n}let o=async a=>{let c=await yt(a,{withFileTypes:!0});for(let d of c){let u=bt(a,d.name);if(d.isDirectory()){await o(u);continue}let f=await Se(u);n.push({key:ke(this.root,u),size:f.size,updatedAt:f.mtime.toISOString()})}},s=await Se(t);return s.isDirectory()?await o(t):n.push({key:ke(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as wt,GetObjectCommand as vt,HeadObjectCommand as jt,ListObjectsV2Command as At,PutObjectCommand as Mt,S3Client as Rt}from"@aws-sdk/client-s3";import{getSignedUrl as It}from"@aws-sdk/s3-request-presigner";var M=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Rt({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Mt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await It(this.client,new vt({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new jt({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 wt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new At({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};function W(r,e){return console.warn(e),new A(r)}function be(r){let e=r.localRoot??Ct(Pt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new M({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new M({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new N({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new A(e)}function Et(r){return new Promise(e=>setTimeout(e,r))}async function xe(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(s=c,a>=t)break;let d=Math.min(o,n*2**(a-1)),u=Math.floor(Math.random()*Math.max(1,d*.2));await Et(d+u)}throw s}var Tt=new Set(["put","get","getText","delete","list"]);function we(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:Tt.has(n)?(...s)=>xe(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function ve(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function je(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var K=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=ve(o??n),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),n=t,o=await this.provider.getText(e);if(o){let a;try{a=JSON.parse(o)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(n=a.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=je(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{join as Re}from"node:path";import{mkdirSync as Dt}from"node:fs";import{createHash as _t}from"node:crypto";import{dirname as Ot}from"node:path";import{mkdirSync as Nt,readFileSync as eo,renameSync as Kt,writeFileSync as $t}from"node:fs";function Ae(r){return _t("sha256").update(r).digest("hex")}function Me(r,e){Nt(Ot(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;$t(t,JSON.stringify(e,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),Kt(t,r)}function Pe(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function p(r,e=20){let t=[],n=new Set;for(let o of r.slice().reverse()){let s=Pe(o);if(!(!s||n.has(s))&&(n.add(s),t.push(o),t.length>=e))break}return t.reverse()}function Lt(r,e=20){let t=new Map;for(let n of r){let o=`${n.kind}|${Pe(n.command)}`;t.delete(o),t.set(o,n)}return Array.from(t.values()).slice(-e)}function zt(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function Ie(r,e){let t=e.status??r?.status??"pending",n=t;r&&(r.status==="completed"&&t!=="completed"?n="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(n=r.status));let o=r&&zt(e)?r.title:e.text;return{id:r?.id??Ae(e.key).slice(0,24),title:o,status:n,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function Ce(r,e){let t=`projects/${r.id}/work/observations/`,n=await e.list(t),o=[];for(let s of n.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(s.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&o.push(c)}catch{}}return o}async function B(r,e){let n=(await Ce(r,e)).flatMap(i=>i.observations).sort((i,l)=>{let re=i.occurredAt.localeCompare(l.occurredAt);if(re!==0)return re;let ne=i.sequence-l.sequence;return ne!==0?ne:i.id.localeCompare(l.id)}),o=new Map,s=new Map,a,c,d,u,f,k=[],g=[],H=[],J=[],U=[],$=new Map,Y=[],q=[],Z=[],Q=[],X=[],ee=[];for(let i of n)switch(i.kind){case"request":a=i.text;break;case"activity":c=i.text;break;case"goal":d=i.text;break;case"plan":u=i.text;break;case"phase":o.set(i.key,Ie(o.get(i.key),i));break;case"task":s.set(i.key,Ie(s.get(i.key),i));break;case"decision":k.push(i.text);break;case"blocker":g.push(i.text);break;case"warning":H.push(i.text);break;case"next_action":J.push(i.text);break;case"file":{U.push(i.text);let l=i.fileAction??"active";$.delete(i.text),$.set(i.text,l),l==="modified"?Y.push(i.text):l==="created"?q.push(i.text):l==="deleted"&&Z.push(i.text);break}case"command":Q.push(i.text);break;case"test":X.push(i.text),i.checkKind&&ee.push({kind:i.checkKind,command:i.text,status:i.checkStatus??"unknown",updatedAt:i.occurredAt,agent:i.agent,nativeSessionId:i.nativeSessionId});break;case"session":f={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let y=Array.from(o.values()).sort((i,l)=>(i.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),m=Array.from(s.values()).sort((i,l)=>(i.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),D=y.find(i=>i.status==="in_progress")??y.find(i=>i.status==="blocked")??y.find(i=>i.status==="pending"),R=m.find(i=>i.status==="in_progress")??m.find(i=>i.status==="blocked")??m.find(i=>i.status==="pending"),Te=p([...J,...R?[R.title]:[],...!R&&D?[D.title]:[],...m.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),_e=p([...g,...y.filter(i=>i.status==="blocked").map(i=>i.title),...m.filter(i=>i.status==="blocked").map(i=>i.title)],20),L={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:d,plan:u,phases:y,tasks:m,decisions:p(k,20),blockers:_e,warnings:p(H,20),nextActions:Te,filesTouched:p(U,30),activeFiles:Array.from($.entries()).filter(([,i])=>i!=="deleted").map(([i])=>i).slice(-5),modifiedFiles:p(Y,30),createdFiles:p(q,30),deletedFiles:p(Z,30),commands:p(Q,20),tests:p(X,20),checks:Lt(ee,20),currentPhase:D,currentTask:R,progress:{phasesTotal:y.length,phasesCompleted:y.filter(i=>i.status==="completed").length,tasksTotal:m.length,tasksCompleted:m.filter(i=>i.status==="completed").length,blocked:y.filter(i=>i.status==="blocked").length+m.filter(i=>i.status==="blocked").length},lastSession:f,updatedAt:n.length?n[n.length-1].occurredAt:new Date().toISOString()},te=Re(r.rootPath,".toolnet","work");return Dt(te,{recursive:!0}),Me(Re(te,"current.json"),L),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(L,null,2)+`
|
|
6
|
+
`,"application/json"),L}async function G(r,e){if((await Ce(r,e)).length>0)return B(r,e);let n=await e.getText(`projects/${r.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function Vt(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Ft(r){let e=oe(),t=we(be({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new K(t,r.id,r.name,r.remote??r.name)}function Ee(r){console.log(),console.log(`Project: ${r.projectName}`),r.goal&&console.log(`Goal: ${r.goal}`),r.currentPhase&&console.log(`Current phase: ${r.currentPhase.title} [${r.currentPhase.status}]`),r.currentTask&&console.log(`Current task: ${r.currentTask.title} [${r.currentTask.status}]`),console.log(`Phases: ${r.progress.phasesCompleted}/${r.progress.phasesTotal}`),console.log(`Tasks: ${r.progress.tasksCompleted}/${r.progress.tasksTotal}`),r.nextActions.length&&(console.log(),console.log("Next actions:"),r.nextActions.forEach((e,t)=>console.log(`${t+1}. ${e}`))),r.blockers.length&&(console.log(),console.log("Blockers:"),r.blockers.forEach(e=>console.log(`- ${e}`))),r.lastSession&&(console.log(),console.log(`Last session: ${r.lastSession.agent} / ${r.lastSession.nativeSessionId}`))}async function Wt(){let[r="help",...e]=process.argv.slice(2),t=new T().detect(Vt(e,"--project")??process.cwd()),n=Ft(t);if(r==="reconcile"){let o=await B(t,n);Ee(o);return}if(r==="status"){let o=await G(t,n);if(!o){console.log("No active work state yet.");return}Ee(o);return}if(r==="json"){let o=await G(t,n);console.log(JSON.stringify(o,null,2));return}console.log(`Work Continuity
|
|
7
7
|
|
|
8
8
|
Commands:
|
|
9
9
|
status [--project PATH]
|
|
10
10
|
json [--project PATH]
|
|
11
11
|
reconcile [--project PATH]
|
|
12
|
-
`)}
|
|
12
|
+
`)}Wt().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolnet-memory",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"description": "Persistent project memory, work continuity, and code intelligence for AI coding agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,6 +54,10 @@
|
|
|
54
54
|
"snapshot:test": "tsx src/snapshot/test-snapshot.ts",
|
|
55
55
|
"code:semantic:test": "tsx src/code-intelligence/test-semantic.ts",
|
|
56
56
|
"doctor": "tsx src/production/doctor.ts",
|
|
57
|
+
"gc": "tsx src/retention/cli.ts",
|
|
58
|
+
"benchmark:large-repo": "tsx src/code-intelligence/benchmark/large-repo-benchmark.ts",
|
|
59
|
+
"code:large-repo-hardening:test": "vitest run tests/code-intelligence/large-repo-hardening.test.ts",
|
|
60
|
+
"code:correctness:test": "vitest run tests/code-intelligence/code-intelligence-correctness.test.ts",
|
|
57
61
|
"cli": "./bin/toolnet-memory",
|
|
58
62
|
"prod:check": "npm run build && npm test && npm run doctor",
|
|
59
63
|
"project:migrate": "tsx src/storage/project/migrate.ts",
|
|
@@ -94,7 +98,7 @@
|
|
|
94
98
|
"session:new-agents:test": "vitest run tests/session/new-agent-event-mappers.test.ts tests/session/new-agent-hook-installers.test.ts tests/session/new-agent-runtime.test.ts",
|
|
95
99
|
"session:new-agents-continuity:test": "vitest run tests/session/new-agent-continuity.test.ts tests/session/new-agent-continuity-installers.test.ts",
|
|
96
100
|
"session:new-agents-integration:test": "vitest run tests/session/new-agent-integrations.test.ts tests/production/new-agent-auto-integrate.test.ts tests/production/new-agent-production-wiring.test.ts",
|
|
97
|
-
"session:integration-scope:test": "vitest run tests/session/integration-scope.test.ts tests/session/hook-event-dedupe.test.ts",
|
|
101
|
+
"session:integration-scope:test": "vitest run tests/session/integration-scope.test.ts tests/session/hook-event-dedupe.test.ts tests/session/hook-event-dedupe-project.test.ts",
|
|
98
102
|
"session:cursor-dual-scope:test": "vitest run tests/session/cursor-dual-scope.test.ts tests/session/cursor-dual-scope-wiring.test.ts",
|
|
99
103
|
"session:copilot-dual-scope:test": "vitest run tests/session/copilot-dual-scope.test.ts tests/session/copilot-dual-scope-wiring.test.ts",
|
|
100
104
|
"session:grok-dual-scope:test": "vitest run tests/session/grok-dual-scope.test.ts tests/session/grok-dual-scope-wiring.test.ts",
|
|
@@ -106,7 +110,21 @@
|
|
|
106
110
|
"production:phase07-final:test": "vitest run tests/production/final-phase07-release.test.ts",
|
|
107
111
|
"release:certify:10": "vitest run tests/integration/cross-agent-continuity.test.ts tests/production/ten-agent-release-contract.test.ts",
|
|
108
112
|
"release:certify:final": "bash scripts/final-release-certify.sh",
|
|
109
|
-
"release:verify:static": "node scripts/verify-release-contract.mjs"
|
|
113
|
+
"release:verify:static": "node scripts/verify-release-contract.mjs",
|
|
114
|
+
"security:isolation:test": "vitest run tests/security/security-isolation.test.ts",
|
|
115
|
+
"release:verify:v0315": "node scripts/verify-v0315-contract.mjs",
|
|
116
|
+
"project:cross-machine:test": "vitest run tests/core/project-cross-machine-identity.test.ts tests/core/project-identity.test.ts",
|
|
117
|
+
"repository:truth:cleanup": "node scripts/repository-truth-cleanup.mjs",
|
|
118
|
+
"repository:truth:audit": "node scripts/repository-truth-audit.mjs",
|
|
119
|
+
"repository:truth:test": "vitest run tests/repository-truth/repository-truth.test.ts",
|
|
120
|
+
"code:search:naming:audit": "node scripts/code-search-naming-audit.mjs",
|
|
121
|
+
"code:search:naming:test": "vitest run tests/code-intelligence/code-search-naming.test.ts",
|
|
122
|
+
"docs:truth:audit": "node scripts/documentation-truth-audit.mjs",
|
|
123
|
+
"docs:truth:test": "vitest run tests/documentation/documentation-truth.test.ts",
|
|
124
|
+
"memory:conflict-v2:audit": "node scripts/conflict-v2-audit.mjs",
|
|
125
|
+
"memory:conflict-v2:test": "vitest run tests/memory/conflict-v2.test.ts",
|
|
126
|
+
"release:verify:v0316": "node scripts/verify-v0316-contract.mjs",
|
|
127
|
+
"project:identity:audit": "node scripts/project-identity-audit.mjs"
|
|
110
128
|
},
|
|
111
129
|
"dependencies": {
|
|
112
130
|
"@aws-sdk/client-s3": "^3.1102.0",
|
package/release-manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"name": "toolnet-memory",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.16",
|
|
5
5
|
"releaseSeries": "0.3.x",
|
|
6
6
|
"runtime": {
|
|
7
7
|
"node": ">=22",
|
|
@@ -67,7 +67,108 @@
|
|
|
67
67
|
"nativeCliE2ERequired": false,
|
|
68
68
|
"nativeCliE2EReason": "Native host binaries are optional and may be unavailable on the certification host.",
|
|
69
69
|
"fullRepositoryCertificationRequired": true,
|
|
70
|
-
"npmPublishAutomatic":
|
|
71
|
-
"gitTagAutomatic": false
|
|
70
|
+
"npmPublishAutomatic": true,
|
|
71
|
+
"gitTagAutomatic": false,
|
|
72
|
+
"npmPublishTrigger": "git-tag-workflow-trusted-publishing"
|
|
73
|
+
},
|
|
74
|
+
"hardening": {
|
|
75
|
+
"retention": {
|
|
76
|
+
"safeGc": true,
|
|
77
|
+
"defaultDryRun": true,
|
|
78
|
+
"realDeleteRequiresApply": true,
|
|
79
|
+
"protectSemanticMemory": true,
|
|
80
|
+
"protectWorkCurrent": true,
|
|
81
|
+
"protectSharedJournal": true,
|
|
82
|
+
"protectRemoteOperations": true,
|
|
83
|
+
"unflushedWalDeletion": false
|
|
84
|
+
},
|
|
85
|
+
"dedupe": {
|
|
86
|
+
"projectScoped": true,
|
|
87
|
+
"crossProcess": true,
|
|
88
|
+
"crossContainerSharedVolume": true,
|
|
89
|
+
"usesPidIdentity": false,
|
|
90
|
+
"atomicExclusiveClaim": true,
|
|
91
|
+
"ownershipToken": true,
|
|
92
|
+
"ttlRecovery": true,
|
|
93
|
+
"remoteDistributedLock": false
|
|
94
|
+
},
|
|
95
|
+
"largeRepository": {
|
|
96
|
+
"benchmarkProfiles": ["10k", "50k", "100k"],
|
|
97
|
+
"maxCodeFileBytes": 2097152,
|
|
98
|
+
"symlinkTraversal": false,
|
|
99
|
+
"boundedParseConcurrency": true,
|
|
100
|
+
"boundedHashConcurrency": true,
|
|
101
|
+
"cancellationBoundary": true,
|
|
102
|
+
"renameDetection": "unique-hash-1to1"
|
|
103
|
+
},
|
|
104
|
+
"codeIntelligence": {
|
|
105
|
+
"parserEngine": "typescript-compiler-api",
|
|
106
|
+
"treeSitterRuntime": false,
|
|
107
|
+
"supportedExtensions": [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts", ".mjs", ".cjs"],
|
|
108
|
+
"tsconfigPaths": true,
|
|
109
|
+
"baseUrlResolution": true,
|
|
110
|
+
"projectReferences": true,
|
|
111
|
+
"workspacePackages": true,
|
|
112
|
+
"graphRepair": true,
|
|
113
|
+
"danglingEdgeProtection": true
|
|
114
|
+
},
|
|
115
|
+
"security": {
|
|
116
|
+
"secretScannerVersion": 2,
|
|
117
|
+
"durableSanitization": true,
|
|
118
|
+
"projectIsolation": true,
|
|
119
|
+
"projectDataTrusted": false,
|
|
120
|
+
"clientSideEncryption": false,
|
|
121
|
+
"requiresEncryptionKey": false
|
|
122
|
+
},
|
|
123
|
+
"projectIdentity": {
|
|
124
|
+
"crossMachine": true,
|
|
125
|
+
"existingManifestCanonical": true,
|
|
126
|
+
"normalizedGitRemote": true,
|
|
127
|
+
"sshHttpsEquivalent": true,
|
|
128
|
+
"remoteIdentityRegistry": true,
|
|
129
|
+
"legacyExplicitAdoption": true,
|
|
130
|
+
"silentUnverifiedAdoption": false,
|
|
131
|
+
"pathHashPrimaryForGit": false,
|
|
132
|
+
"credentialLeakIntoFingerprint": false
|
|
133
|
+
},
|
|
134
|
+
"repositoryTruth": {
|
|
135
|
+
"deadScaffoldsRemoved": true,
|
|
136
|
+
"unsupportedCapabilitiesExplicit": true,
|
|
137
|
+
"legacySyncScaffoldRemoved": true,
|
|
138
|
+
"multiHostReplacement": "src/multi-host",
|
|
139
|
+
"unclassifiedZeroByteSourceFiles": 0,
|
|
140
|
+
"storagePlaceholdersFrozen": true
|
|
141
|
+
},
|
|
142
|
+
"codeSearch": {
|
|
143
|
+
"displayName": "Local Code Search — SQLite FTS5/BM25",
|
|
144
|
+
"engine": "sqlite-fts5-bm25",
|
|
145
|
+
"mode": "lexical",
|
|
146
|
+
"embeddings": false,
|
|
147
|
+
"vectorDatabase": false,
|
|
148
|
+
"networkRequired": false,
|
|
149
|
+
"legacySemanticAliasesPreserved": true
|
|
150
|
+
},
|
|
151
|
+
"documentationTruth": {
|
|
152
|
+
"runtimeCapabilityMatrix": true,
|
|
153
|
+
"unsupportedLanguagesExplicit": true,
|
|
154
|
+
"unsupportedStorageExplicit": true,
|
|
155
|
+
"crossMachineIdentityDocumented": true,
|
|
156
|
+
"multiHostArchitectureDocumented": true,
|
|
157
|
+
"clientEncryptionClaimed": false
|
|
158
|
+
},
|
|
159
|
+
"conflictEngineV2": {
|
|
160
|
+
"deterministic": true,
|
|
161
|
+
"llmMerge": false,
|
|
162
|
+
"embeddingMatching": false,
|
|
163
|
+
"kinds": ["rule", "decision", "todo", "next_action", "fix", "context", "architecture"],
|
|
164
|
+
"topicMatching": true,
|
|
165
|
+
"entityMatching": true,
|
|
166
|
+
"lexicalSubjectMatching": true,
|
|
167
|
+
"verifiedFixCompletesTask": true,
|
|
168
|
+
"verifiedFixResolvesContext": true,
|
|
169
|
+
"conflictingMemoryActive": false,
|
|
170
|
+
"completedMemoryActive": false,
|
|
171
|
+
"resolvedMemoryActive": false
|
|
172
|
+
}
|
|
72
173
|
}
|
|
73
174
|
}
|