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{existsSync as je,readFileSync as Ae}from"node:fs";import{homedir as Me}from"node:os";import{join as Re}from"node:path";function Pe(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 Ce(){let r=process.env.TOOLNET_GLOBAL_ENV??Re(Me(),".config","toolnet-memory",".env");if(!je(r))return;let e=Ae(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 i=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=Pe(n.slice(o+1)))}}Ce();function k(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function S(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function q(){return{memory:{autoCapture:k(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:k(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:k(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:k(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:S(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:S(process.env.MEMORY_RERANK_TOP,10),finalContext:S(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:S(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:k(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:S(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Ee}from"node:crypto";import{existsSync as j,mkdirSync as Ie,readFileSync as Te,renameSync as _e,writeFileSync as Oe}from"node:fs";import{basename as Ne,dirname as A,join as b,parse as ne,resolve as h}from"node:path";var oe=".toolnet",$e="project.json";function Ke(r){return Ee("sha256").update(r).digest("hex").slice(0,16)}function M(r){return b(r,oe,$e)}function De(r){return j(M(r))}function X(r,e){let t=h(r),n=ne(t).root;for(;;){if(De(t))return t;if(t===n||e&&t===h(e))break;let o=A(t);if(o===t)break;t=o}return null}function ee(r){let e=h(r),t=ne(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>j(b(e,i))))return e;if(e===t)break;let o=A(e);if(o===e)break;e=o}return h(r)}function te(r){let e;try{e=JSON.parse(Te(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:A(A(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 re(r,e){let t=b(r,oe);Ie(t,{recursive:!0});let n=M(r),o=`${n}.tmp-${process.pid}`;Oe(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),_e(o,n)}function N(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 R=class{findExisting(e=process.cwd()){let t=h(e),n=ee(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>j(b(n,u))),a=X(t,i?n:void 0);if(!a)return null;let c=te(M(a));return N(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=h(e),n=ee(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>j(b(n,m))),a=X(t,i?n:void 0);if(a){let m=M(a),g=te(m);return g.rootPath!==a&&(g.rootPath=a,g.updatedAt=new Date().toISOString(),re(a,g)),N(g,a)}let c=new Date().toISOString(),u=Ne(n),l={version:1,id:Ke(n),name:u,remote:u,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return re(n,l),N(l,n)}};var ze=[{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"}],Le=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function se(r){return r.normalize("NFKC").trim().toLowerCase()}function Ve(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 We(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function Fe(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 Be(r,e){return r.start<e.end&&e.start<r.end}function ie(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var P=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=se(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let i of ze){let a=new RegExp(i.regex.source,i.regex.flags);for(let c of e.matchAll(a))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:i.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:i.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ie(t),o=[];for(let i of n)o.some(a=>Be(a,i))||o.push(i);return ie(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=se(e);return Le.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 i=o[0];this.allowed(i)||We(i)||!/[A-Za-z]/u.test(i)||!/[0-9]/u.test(i)||Fe(e,o.index,o.index+i.length)&&(Ve(i)<3.7||t.push({type:"high_entropy_secret",value:i,start:o.index,end:o.index+i.length,confidence:"heuristic"}))}return t}};var C=class{scanner;constructor(e={}){this.scanner=new P(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),i=new Set;for(let a of o)i.add(a.type),n=n.slice(0,a.start)+`[REDACTED:${a.type}]`+n.slice(a.end);return{text:n,redacted:t.length,secretTypes:[...i].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[n,o]of Object.entries(e)){let i=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(i.includes("password")||i.includes("passwd")||i==="pwd"||i.includes("secret")||i.includes("token")||i.includes("cookie")||i.includes("authorization")||i.includes("apikey")||i.includes("accesskey")||i.includes("privatekey")||i.includes("clientsecret")||i.includes("credential")){t[n]="[REDACTED]";continue}t[n]=this.sanitizeValue(o)}return t}return e}};var Ft=new C;import{homedir as mt}from"node:os";import{join as ft}from"node:path";import{DeleteObjectCommand as Je,GetObjectCommand as He,HeadObjectCommand as Ue,ListObjectsV2Command as Ye,PutObjectCommand as Ge,S3Client as Ze}from"@aws-sdk/client-s3";import{getSignedUrl as Qe}from"@aws-sdk/s3-request-presigner";var E=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ze({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 Ge({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Qe(this.client,new He({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 Ue({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Je({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Ye({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let i of o.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as ae,mkdir as qe,readFile as Xe,readdir as et,rm as tt,stat as ce,writeFile as rt}from"node:fs/promises";import{dirname as nt,join as ot,relative as ue,resolve as st}from"node:path";var w=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return st(this.root,t)}async put(e,t){let n=this.path(e);await qe(nt(n),{recursive:!0}),await rt(n,t)}async get(e){try{return await Xe(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await ae(this.path(e)),!0}catch{return!1}}async delete(e){await tt(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await ae(t)}catch{return n}let o=async a=>{let c=await et(a,{withFileTypes:!0});for(let u of c){let l=ot(a,u.name);if(u.isDirectory()){await o(l);continue}let m=await ce(l);n.push({key:ue(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},i=await ce(t);return i.isDirectory()?await o(t):n.push({key:ue(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),n}};import{DeleteObjectCommand as it,GetObjectCommand as at,HeadObjectCommand as ct,ListObjectsV2Command as ut,PutObjectCommand as dt,S3Client as lt}from"@aws-sdk/client-s3";import{getSignedUrl as pt}from"@aws-sdk/s3-request-presigner";var x=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new lt({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new dt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await pt(this.client,new at({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 ct({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 it({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 i of o.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};function $(r,e){return console.warn(e),new w(r)}function de(r){let e=r.localRoot??ft(mt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new x({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):$(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 x({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):$(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 E({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):$(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new w(e)}function gt(r){return new Promise(e=>setTimeout(e,r))}async function le(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let u=Math.min(o,n*2**(a-1)),l=Math.floor(Math.random()*Math.max(1,u*.2));await gt(u+l)}throw i}var yt=new Set(["put","get","getText","delete","list"]);function pe(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:yt.has(n)?(...i)=>le(()=>Promise.resolve(o.apply(t,i)),e):o.bind(t)}})}function me(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function fe(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var I=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=me(o??n),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),n=t,o=await this.provider.getText(e);if(o){let 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 i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,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=fe(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{join as he}from"node:path";import{mkdirSync as xt}from"node:fs";import{createHash as ht}from"node:crypto";import{dirname as kt}from"node:path";import{mkdirSync as St,readFileSync as En,renameSync as bt,writeFileSync as wt}from"node:fs";function ge(r){return ht("sha256").update(r).digest("hex")}function ye(r,e){St(kt(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;wt(t,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),bt(t,r)}function Se(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 i=Se(o);if(!(!i||n.has(i))&&(n.add(i),t.push(o),t.length>=e))break}return t.reverse()}function vt(r,e=20){let t=new Map;for(let n of r){let o=`${n.kind}|${Se(n.command)}`;t.delete(o),t.set(o,n)}return Array.from(t.values()).slice(-e)}function jt(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 ke(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&&jt(e)?r.title:e.text;return{id:r?.id??ge(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 be(r,e){let t=`projects/${r.id}/work/observations/`,n=await e.list(t),o=[];for(let i of n.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(i.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&o.push(c)}catch{}}return o}async function K(r,e){let n=(await be(r,e)).flatMap(s=>s.observations).sort((s,d)=>{let Z=s.occurredAt.localeCompare(d.occurredAt);if(Z!==0)return Z;let Q=s.sequence-d.sequence;return Q!==0?Q:s.id.localeCompare(d.id)}),o=new Map,i=new Map,a,c,u,l,m,g=[],z=[],L=[],V=[],W=[],T=new Map,F=[],B=[],J=[],H=[],U=[],Y=[];for(let s of n)switch(s.kind){case"request":a=s.text;break;case"activity":c=s.text;break;case"goal":u=s.text;break;case"plan":l=s.text;break;case"phase":o.set(s.key,ke(o.get(s.key),s));break;case"task":i.set(s.key,ke(i.get(s.key),s));break;case"decision":g.push(s.text);break;case"blocker":z.push(s.text);break;case"warning":L.push(s.text);break;case"next_action":V.push(s.text);break;case"file":{W.push(s.text);let d=s.fileAction??"active";T.delete(s.text),T.set(s.text,d),d==="modified"?F.push(s.text):d==="created"?B.push(s.text):d==="deleted"&&J.push(s.text);break}case"command":H.push(s.text);break;case"test":U.push(s.text),s.checkKind&&Y.push({kind:s.checkKind,command:s.text,status:s.checkStatus??"unknown",updatedAt:s.occurredAt,agent:s.agent,nativeSessionId:s.nativeSessionId});break;case"session":m={agent:s.agent,nativeSessionId:s.nativeSessionId,sessionKey:s.sessionKey,updatedAt:s.occurredAt};break}let y=Array.from(o.values()).sort((s,d)=>(s.order??Number.MAX_SAFE_INTEGER)-(d.order??Number.MAX_SAFE_INTEGER)),f=Array.from(i.values()).sort((s,d)=>(s.order??Number.MAX_SAFE_INTEGER)-(d.order??Number.MAX_SAFE_INTEGER)),_=y.find(s=>s.status==="in_progress")??y.find(s=>s.status==="blocked")??y.find(s=>s.status==="pending"),v=f.find(s=>s.status==="in_progress")??f.find(s=>s.status==="blocked")??f.find(s=>s.status==="pending"),xe=p([...V,...v?[v.title]:[],...!v&&_?[_.title]:[],...f.filter(s=>s.status==="pending").slice(0,5).map(s=>s.title)],8),ve=p([...z,...y.filter(s=>s.status==="blocked").map(s=>s.title),...f.filter(s=>s.status==="blocked").map(s=>s.title)],20),O={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:u,plan:l,phases:y,tasks:f,decisions:p(g,20),blockers:ve,warnings:p(L,20),nextActions:xe,filesTouched:p(W,30),activeFiles:Array.from(T.entries()).filter(([,s])=>s!=="deleted").map(([s])=>s).slice(-5),modifiedFiles:p(F,30),createdFiles:p(B,30),deletedFiles:p(J,30),commands:p(H,20),tests:p(U,20),checks:vt(Y,20),currentPhase:_,currentTask:v,progress:{phasesTotal:y.length,phasesCompleted:y.filter(s=>s.status==="completed").length,tasksTotal:f.length,tasksCompleted:f.filter(s=>s.status==="completed").length,blocked:y.filter(s=>s.status==="blocked").length+f.filter(s=>s.status==="blocked").length},lastSession:m,updatedAt:n.length?n[n.length-1].occurredAt:new Date().toISOString()},G=he(r.rootPath,".toolnet","work");return xt(G,{recursive:!0}),ye(he(G,"current.json"),O),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(O,null,2)+`
6
- `,"application/json"),O}async function D(r,e){if((await be(r,e)).length>0)return K(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 At(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Mt(r){let e=q(),t=pe(de({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new I(t,r.id,r.name,r.remote??r.name)}function we(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 Rt(){let[r="help",...e]=process.argv.slice(2),t=new R().detect(At(e,"--project")??process.cwd()),n=Mt(t);if(r==="reconcile"){let o=await K(t,n);we(o);return}if(r==="status"){let o=await D(t,n);if(!o){console.log("No active work state yet.");return}we(o);return}if(r==="json"){let o=await D(t,n);console.log(JSON.stringify(o,null,2));return}console.log(`Work Continuity
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
- `)}Rt().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
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.15",
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",
@@ -112,7 +112,19 @@
112
112
  "release:certify:final": "bash scripts/final-release-certify.sh",
113
113
  "release:verify:static": "node scripts/verify-release-contract.mjs",
114
114
  "security:isolation:test": "vitest run tests/security/security-isolation.test.ts",
115
- "release:verify:v0315": "node scripts/verify-v0315-contract.mjs"
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"
116
128
  },
117
129
  "dependencies": {
118
130
  "@aws-sdk/client-s3": "^3.1102.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "name": "toolnet-memory",
4
- "version": "0.3.15",
4
+ "version": "0.3.16",
5
5
  "releaseSeries": "0.3.x",
6
6
  "runtime": {
7
7
  "node": ">=22",
@@ -119,6 +119,56 @@
119
119
  "projectDataTrusted": false,
120
120
  "clientSideEncryption": false,
121
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
122
172
  }
123
173
  }
124
174
  }