toolnet-memory 0.3.3 → 0.3.4

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,52 +1,26 @@
1
- import{existsSync as Ar,readFileSync as Er}from"node:fs";import{homedir as Pr}from"node:os";import{join as Mr}from"node:path";function Tr(t){let e=t.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 Or(){let t=process.env.TOOLNET_GLOBAL_ENV??Mr(Pr(),".config","toolnet-memory",".env");if(!Ar(t))return;let e=Er(t,"utf8");for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Tr(r.slice(s+1)))}}Or();function X(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function Q(t,e){if(!t)return e;let n=Number(t);return Number.isFinite(n)?n:e}function pe(){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:Q(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:Q(process.env.MEMORY_RERANK_TOP,10),finalContext:Q(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:Q(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:Q(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Rr}from"node:crypto";import{existsSync as Ye,mkdirSync as Nr,readFileSync as _r,renameSync as $r,writeFileSync as Kr}from"node:fs";import{basename as Lr,dirname as me,join as ge,parse as Ct,resolve as Z}from"node:path";var It=".toolnet",Dr="project.json";function Wr(t){return Rr("sha256").update(t).digest("hex").slice(0,16)}function Xe(t){return ge(t,It,Dr)}function Fr(t){return Ye(Xe(t))}function zr(t,e){let n=Z(t),r=Ct(n).root;for(;;){if(Fr(n))return n;if(n===r||e&&n===Z(e))break;let s=me(n);if(s===n)break;n=s}return null}function Br(t){let e=Z(t),n=Ct(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>Ye(ge(e,o))))return e;if(e===n)break;let s=me(e);if(s===e)break;e=s}return Z(t)}function Vr(t){let e;try{e=JSON.parse(_r(t,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${t}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${t}`);let n=e;if(typeof n.id!="string"||!n.id.trim())throw new Error(`ToolNet project manifest is missing id: ${t}`);if(typeof n.name!="string"||!n.name.trim())throw new Error(`ToolNet project manifest is missing name: ${t}`);let r=new Date().toISOString();return{version:1,id:n.id,name:n.name,remote:typeof n.remote=="string"&&n.remote.trim()?n.remote:n.name,rootPath:typeof n.rootPath=="string"?n.rootPath:me(me(t)),createdAt:typeof n.createdAt=="string"?n.createdAt:r,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:r,graphVersion:typeof n.graphVersion=="number"?n.graphVersion:0,memoryVersion:typeof n.memoryVersion=="number"?n.memoryVersion:0,metadata:n.metadata&&typeof n.metadata=="object"?n.metadata:void 0}}function xt(t,e){let n=ge(t,It);Nr(n,{recursive:!0});let r=Xe(t),s=`${r}.tmp-${process.pid}`;Kr(s,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),$r(s,r)}function jt(t,e){return{id:t.id,name:t.name,remote:t.remote,rootPath:e,createdAt:t.createdAt,updatedAt:t.updatedAt,graphVersion:t.graphVersion,memoryVersion:t.memoryVersion,metadata:t.metadata}}var fe=class{detect(e=process.cwd()){let n=Z(e),r=Br(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>Ye(ge(r,p))),i=zr(n,o?r:void 0);if(i){let p=Xe(i),l=Vr(p);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),xt(i,l)),jt(l,i)}let a=new Date().toISOString(),c=Lr(r),u={version:1,id:Wr(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return xt(r,u),jt(u,r)}};var qr=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],ye=class{scan(e){let n=[];for(let r of qr){let s=new RegExp(r.regex.source,r.regex.flags);for(let o of e.matchAll(s))n.push({type:r.type,value:o[0]})}return n}hasSecrets(e){return this.scan(e).length>0}};var ee=class{scanner=new ye;sanitize(e){let n=e,r=this.scanner.scan(e),s=new Set;for(let o of r)s.add(o.type),n=n.split(o.value).join(`[REDACTED:${o.type}]`);return{text:n,redacted:r.length,secretTypes:[...s]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(n=>this.sanitizeValue(n));if(e&&typeof e=="object"){let n={};for(let[r,s]of Object.entries(e)){let o=r.toLowerCase();o.includes("password")||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")?n[r]="[REDACTED]":n[r]=this.sanitizeValue(s)}return n}return e}};import{homedir as fs}from"node:os";import{join as gs}from"node:path";import{DeleteObjectCommand as Jr,GetObjectCommand as Hr,HeadObjectCommand as Gr,ListObjectsV2Command as Ur,PutObjectCommand as Yr,S3Client as Xr}from"@aws-sdk/client-s3";import{getSignedUrl as Qr}from"@aws-sdk/s3-request-presigner";var he=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Xr({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,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new Yr({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await Qr(this.client,new Hr({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new Gr({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new Jr({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new Ur({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};import{access as At,mkdir as Zr,readFile as es,readdir as ts,rm as ns,stat as Et,writeFile as rs}from"node:fs/promises";import{dirname as ss,join as os,relative as Pt,resolve as is}from"node:path";var te=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return is(this.root,n)}async put(e,n){let r=this.path(e);await Zr(ss(r),{recursive:!0}),await rs(r,n)}async get(e){try{return await es(this.path(e))}catch(n){if(typeof n=="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return null;throw n}}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await At(this.path(e)),!0}catch{return!1}}async delete(e){await ns(this.path(e),{force:!0})}async list(e=""){let n=this.path(e),r=[];try{await At(n)}catch{return r}let s=async i=>{let a=await ts(i,{withFileTypes:!0});for(let c of a){let u=os(i,c.name);if(c.isDirectory()){await s(u);continue}let p=await Et(u);r.push({key:Pt(this.root,u),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await Et(n);return o.isDirectory()?await s(n):r.push({key:Pt(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as as,GetObjectCommand as cs,HeadObjectCommand as us,ListObjectsV2Command as ls,PutObjectCommand as ds,S3Client as ps}from"@aws-sdk/client-s3";import{getSignedUrl as ms}from"@aws-sdk/s3-request-presigner";var ne=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ps({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,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new ds({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await ms(this.client,new cs({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new us({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new as({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new ls({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};function Qe(t,e){return console.warn(e),new te(t)}function Mt(t){let e=t.localRoot??gs(fs(),".toolnet-memory","storage");if(t.provider==="r2"){let n=t.r2;return n?.accountId&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new ne({name:"r2",endpoint:`https://${n.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:n.bucket,forcePathStyle:!0,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Qe(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(t.provider==="s3"){let n=t.s3;return n?.bucket&&n.accessKeyId&&n.secretAccessKey?new ne({name:"s3",endpoint:n.endpoint,region:n.region??"us-east-1",bucket:n.bucket,forcePathStyle:n.forcePathStyle??!1,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Qe(e,"[storage] S3 credentials missing. Using local fallback.")}if(t.provider==="huggingface"){let n=t.huggingface;return n?.namespace&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new he({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Qe(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new te(e)}function ys(t){return new Promise(e=>setTimeout(e,t))}async function Tt(t,e={}){let n=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let i=1;i<=n;i++)try{return await t()}catch(a){if(o=a,i>=n)break;let c=Math.min(s,r*2**(i-1)),u=Math.floor(Math.random()*Math.max(1,c*.2));await ys(c+u)}throw o}var hs=new Set(["put","get","getText","delete","list"]);function Ot(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:hs.has(r)?(...o)=>Tt(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Rt(t){let e=t.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 Nt(t){let e=t.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 n=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var Se=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=Rt(s??r),this.sourcePrefix=`projects/${n}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,n=new Date().toISOString(),r=n,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:n};await this.provider.put(e,JSON.stringify(o,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Nt(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,n,r){return await this.ensureRegistered(),this.provider.put(this.key(e),n,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{existsSync as ka}from"node:fs";import{execFileSync as ba}from"node:child_process";import{homedir as xa}from"node:os";import{isAbsolute as ja,join as ar,relative as Ca,resolve as cr}from"node:path";import{DatabaseSync as Ia}from"node:sqlite";import{join as js}from"node:path";import{createHash as Ss}from"node:crypto";import{dirname as ws}from"node:path";import{mkdirSync as vs,readFileSync as ks,renameSync as bs,writeFileSync as xs}from"node:fs";function w(t){return Ss("sha256").update(t).digest("hex")}function Ze(t){if(Array.isArray(t))return t.map(Ze);if(t&&typeof t=="object"){let e=t,n={};for(let r of Object.keys(e).sort())n[r]=Ze(e[r]);return n}return t}function _t(t){return JSON.stringify(Ze(t))}function $t(t){try{return JSON.parse(ks(t,"utf8"))}catch{return null}}function E(t,e){vs(ws(t),{recursive:!0});let n=`${t}.${process.pid}.tmp`;xs(n,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),bs(n,t)}function Kt(t,e){let n=t.trim(),r=n.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=w(n).slice(0,12);if(!r||r==="."||r==="..")return`${e}--${s}`;let o=r.slice(0,100);return o===n&&n.length<=100?o:`${o.slice(0,85)}--${s}`}function Lt(t,e,n){let r=e.trim(),s=n.trim();if(!r)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let o=Kt(r.toLowerCase(),"agent"),i=Kt(s,"session");return{projectId:t.id,projectName:t.name,projectRoot:t.rootPath,agent:r,nativeSessionId:s,sessionKey:`${r}:${s}`,remotePrefix:["projects",t.id,"sessions",o,i].join("/"),localDirectory:js(t.rootPath,".toolnet","sessions",o,i)}}function Dt(t){return String(t).padStart(12,"0")}var we=class{constructor(e,n=100,r=512*1024){this.storage=e;this.maxEventsPerChunk=n;this.maxChunkBytes=r;if(n<1)throw new Error("maxEventsPerChunk must be positive");if(r<1024)throw new Error("maxChunkBytes is too small")}storage;maxEventsPerChunk;maxChunkBytes;async getJson(e){let n=await this.storage.getText(e);return n?JSON.parse(n):null}async putJson(e,n){await this.storage.put(e,JSON.stringify(n,null,2)+`
6
- `,"application/json")}async scan(e){let n=`${e.remotePrefix}/events/`,r=await this.storage.list(n),s=[],o=0;for(let i of r){let a=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!a)continue;let c=Number(a[1]),u=Number(a[2]);!Number.isFinite(c)||!Number.isFinite(u)||(s.push({key:i.key,start:c,end:u}),o=Math.max(o,u))}return s.sort((i,a)=>i.start-a.start),{chunks:s,maxSequence:o}}split(e){let n=[],r=[],s=0;for(let o of e){let i=Buffer.byteLength(JSON.stringify(o)+`
7
- `,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),a=n.filter(y=>y.sequence>i.maxSequence),c=0;for(let y of this.split(a)){let g=y[0],v=y[y.length-1],A=y.map(_=>JSON.stringify(_)).join(`
1
+ import{existsSync as Qt,readFileSync as Xt}from"node:fs";import{homedir as Zt}from"node:os";import{join as en}from"node:path";function tn(t){let e=t.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 nn(){let t=process.env.TOOLNET_GLOBAL_ENV??en(Zt(),".config","toolnet-memory",".env");if(!Qt(t))return;let e=Xt(t,"utf8");for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=tn(r.slice(s+1)))}}nn();function B(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function z(t,e){if(!t)return e;let n=Number(t);return Number.isFinite(n)?n:e}function H(){return{memory:{autoCapture:B(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:B(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:B(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:B(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:z(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:z(process.env.MEMORY_RERANK_TOP,10),finalContext:z(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:z(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:B(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:z(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as rn}from"node:crypto";import{existsSync as we,mkdirSync as sn,readFileSync as on,renameSync as an,writeFileSync as cn}from"node:fs";import{basename as un,dirname as Y,join as Q,parse as ze,resolve as q}from"node:path";var qe=".toolnet",dn="project.json";function ln(t){return rn("sha256").update(t).digest("hex").slice(0,16)}function je(t){return Q(t,qe,dn)}function pn(t){return we(je(t))}function fn(t,e){let n=q(t),r=ze(n).root;for(;;){if(pn(n))return n;if(n===r||e&&n===q(e))break;let s=Y(n);if(s===n)break;n=s}return null}function mn(t){let e=q(t),n=ze(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>we(Q(e,o))))return e;if(e===n)break;let s=Y(e);if(s===e)break;e=s}return q(t)}function gn(t){let e;try{e=JSON.parse(on(t,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${t}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${t}`);let n=e;if(typeof n.id!="string"||!n.id.trim())throw new Error(`ToolNet project manifest is missing id: ${t}`);if(typeof n.name!="string"||!n.name.trim())throw new Error(`ToolNet project manifest is missing name: ${t}`);let r=new Date().toISOString();return{version:1,id:n.id,name:n.name,remote:typeof n.remote=="string"&&n.remote.trim()?n.remote:n.name,rootPath:typeof n.rootPath=="string"?n.rootPath:Y(Y(t)),createdAt:typeof n.createdAt=="string"?n.createdAt:r,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:r,graphVersion:typeof n.graphVersion=="number"?n.graphVersion:0,memoryVersion:typeof n.memoryVersion=="number"?n.memoryVersion:0,metadata:n.metadata&&typeof n.metadata=="object"?n.metadata:void 0}}function We(t,e){let n=Q(t,qe);sn(n,{recursive:!0});let r=je(t),s=`${r}.tmp-${process.pid}`;cn(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),an(s,r)}function Be(t,e){return{id:t.id,name:t.name,remote:t.remote,rootPath:e,createdAt:t.createdAt,updatedAt:t.updatedAt,graphVersion:t.graphVersion,memoryVersion:t.memoryVersion,metadata:t.metadata}}var G=class{detect(e=process.cwd()){let n=q(e),r=mn(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>we(Q(r,p))),i=fn(n,o?r:void 0);if(i){let p=je(i),u=gn(p);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),We(i,u)),Be(u,i)}let d=new Date().toISOString(),c=un(r),a={version:1,id:ln(r),name:c,remote:c,rootPath:r,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return We(r,a),Be(a,r)}};var hn=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],X=class{scan(e){let n=[];for(let r of hn){let s=new RegExp(r.regex.source,r.regex.flags);for(let o of e.matchAll(s))n.push({type:r.type,value:o[0]})}return n}hasSecrets(e){return this.scan(e).length>0}};var J=class{scanner=new X;sanitize(e){let n=e,r=this.scanner.scan(e),s=new Set;for(let o of r)s.add(o.type),n=n.split(o.value).join(`[REDACTED:${o.type}]`);return{text:n,redacted:r.length,secretTypes:[...s]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(n=>this.sanitizeValue(n));if(e&&typeof e=="object"){let n={};for(let[r,s]of Object.entries(e)){let o=r.toLowerCase();o.includes("password")||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")?n[r]="[REDACTED]":n[r]=this.sanitizeValue(s)}return n}return e}};import{homedir as Fn}from"node:os";import{join as Kn}from"node:path";import{DeleteObjectCommand as yn,GetObjectCommand as Sn,HeadObjectCommand as vn,ListObjectsV2Command as bn,PutObjectCommand as kn,S3Client as wn}from"@aws-sdk/client-s3";import{getSignedUrl as jn}from"@aws-sdk/s3-request-presigner";var Z=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new wn({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,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new kn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await jn(this.client,new Sn({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new vn({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new yn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new bn({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};import{access as Je,mkdir as xn,readFile as In,readdir as En,rm as On,stat as Ve,writeFile as Pn}from"node:fs/promises";import{dirname as Cn,join as Tn,relative as Ue,resolve as Rn}from"node:path";var V=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return Rn(this.root,n)}async put(e,n){let r=this.path(e);await xn(Cn(r),{recursive:!0}),await Pn(r,n)}async get(e){try{return await In(this.path(e))}catch(n){if(typeof n=="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return null;throw n}}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await Je(this.path(e)),!0}catch{return!1}}async delete(e){await On(this.path(e),{force:!0})}async list(e=""){let n=this.path(e),r=[];try{await Je(n)}catch{return r}let s=async i=>{let d=await En(i,{withFileTypes:!0});for(let c of d){let a=Tn(i,c.name);if(c.isDirectory()){await s(a);continue}let p=await Ve(a);r.push({key:Ue(this.root,a),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await Ve(n);return o.isDirectory()?await s(n):r.push({key:Ue(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as Mn,GetObjectCommand as An,HeadObjectCommand as Nn,ListObjectsV2Command as _n,PutObjectCommand as $n,S3Client as Ln}from"@aws-sdk/client-s3";import{getSignedUrl as Dn}from"@aws-sdk/s3-request-presigner";var U=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Ln({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,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new $n({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await Dn(this.client,new An({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new Nn({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new Mn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new _n({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};function xe(t,e){return console.warn(e),new V(t)}function He(t){let e=t.localRoot??Kn(Fn(),".toolnet-memory","storage");if(t.provider==="r2"){let n=t.r2;return n?.accountId&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new U({name:"r2",endpoint:`https://${n.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:n.bucket,forcePathStyle:!0,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):xe(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(t.provider==="s3"){let n=t.s3;return n?.bucket&&n.accessKeyId&&n.secretAccessKey?new U({name:"s3",endpoint:n.endpoint,region:n.region??"us-east-1",bucket:n.bucket,forcePathStyle:n.forcePathStyle??!1,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):xe(e,"[storage] S3 credentials missing. Using local fallback.")}if(t.provider==="huggingface"){let n=t.huggingface;return n?.namespace&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new Z({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):xe(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new V(e)}function Wn(t){return new Promise(e=>setTimeout(e,t))}async function Ye(t,e={}){let n=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let i=1;i<=n;i++)try{return await t()}catch(d){if(o=d,i>=n)break;let c=Math.min(s,r*2**(i-1)),a=Math.floor(Math.random()*Math.max(1,c*.2));await Wn(c+a)}throw o}var Bn=new Set(["put","get","getText","delete","list"]);function Ge(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:Bn.has(r)?(...o)=>Ye(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Qe(t){let e=t.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 Xe(t){let e=t.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 n=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var ee=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=Qe(s??r),this.sourcePrefix=`projects/${n}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,n=new Date().toISOString(),r=n,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${d instanceof Error?d.message:String(d)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:n};await this.provider.put(e,JSON.stringify(o,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Xe(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,n,r){return await this.ensureRegistered(),this.provider.put(this.key(e),n,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{existsSync as bs}from"node:fs";import{homedir as ks}from"node:os";import{isAbsolute as ws,join as js,relative as xs,resolve as _t}from"node:path";import{DatabaseSync as Is}from"node:sqlite";import{join as Yn}from"node:path";import{createHash as zn}from"node:crypto";import{dirname as qn}from"node:path";import{mkdirSync as Jn,readFileSync as Vn,renameSync as Un,writeFileSync as Hn}from"node:fs";function v(t){return zn("sha256").update(t).digest("hex")}function Ie(t){if(Array.isArray(t))return t.map(Ie);if(t&&typeof t=="object"){let e=t,n={};for(let r of Object.keys(e).sort())n[r]=Ie(e[r]);return n}return t}function Ze(t){return JSON.stringify(Ie(t))}function et(t){try{return JSON.parse(Vn(t,"utf8"))}catch{return null}}function I(t,e){Jn(qn(t),{recursive:!0});let n=`${t}.${process.pid}.tmp`;Hn(n,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),Un(n,t)}function tt(t,e){let n=t.trim(),r=n.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=v(n).slice(0,12);if(!r||r==="."||r==="..")return`${e}--${s}`;let o=r.slice(0,100);return o===n&&n.length<=100?o:`${o.slice(0,85)}--${s}`}function nt(t,e,n){let r=e.trim(),s=n.trim();if(!r)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let o=tt(r.toLowerCase(),"agent"),i=tt(s,"session");return{projectId:t.id,projectName:t.name,projectRoot:t.rootPath,agent:r,nativeSessionId:s,sessionKey:`${r}:${s}`,remotePrefix:["projects",t.id,"sessions",o,i].join("/"),localDirectory:Yn(t.rootPath,".toolnet","sessions",o,i)}}function rt(t){return String(t).padStart(12,"0")}var te=class{constructor(e,n=100,r=512*1024){this.storage=e;this.maxEventsPerChunk=n;this.maxChunkBytes=r;if(n<1)throw new Error("maxEventsPerChunk must be positive");if(r<1024)throw new Error("maxChunkBytes is too small")}storage;maxEventsPerChunk;maxChunkBytes;async getJson(e){let n=await this.storage.getText(e);return n?JSON.parse(n):null}async putJson(e,n){await this.storage.put(e,JSON.stringify(n,null,2)+`
6
+ `,"application/json")}async scan(e){let n=`${e.remotePrefix}/events/`,r=await this.storage.list(n),s=[],o=0;for(let i of r){let d=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!d)continue;let c=Number(d[1]),a=Number(d[2]);!Number.isFinite(c)||!Number.isFinite(a)||(s.push({key:i.key,start:c,end:a}),o=Math.max(o,a))}return s.sort((i,d)=>i.start-d.start),{chunks:s,maxSequence:o}}split(e){let n=[],r=[],s=0;for(let o of e){let i=Buffer.byteLength(JSON.stringify(o)+`
7
+ `,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),d=n.filter(g=>g.sequence>i.maxSequence),c=0;for(let g of this.split(d)){let h=g[0],w=g[g.length-1],C=g.map(A=>JSON.stringify(A)).join(`
8
8
  `)+`
9
- `,O=w(A).slice(0,16),C=[e.remotePrefix,"events",`${Dt(g.sequence)}-${Dt(v.sequence)}-${O}.jsonl`].join("/");await this.storage.exists(C)||await this.storage.put(C,A,"application/x-ndjson"),c+=y.length}let u=await this.scan(e),p=n[n.length-1],l=o?.status??"active";p?.type==="session_end"||p?.type==="session_idle"?l="idle":p?.type==="error"?l="error":n.length>0&&(l="active");let m=new Date().toISOString(),d=n[0],f={version:1,projectId:e.projectId,projectName:e.projectName,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,status:l,createdAt:o?.createdAt??d?.timestamp??m,updatedAt:p?.timestamp??m,firstEventAt:o?.firstEventAt??d?.timestamp,lastEventAt:p?.timestamp??o?.lastEventAt,eventCount:u.maxSequence,chunkCount:u.chunks.length,metadata:{...o?.metadata,...s.metadata}};(s.title??o?.title)&&(f.title=s.title??o?.title);let h={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,lastLocalSequence:n.length>0?n[n.length-1].sequence:u.maxSequence,lastRemoteSequence:u.maxSequence,sourceCursors:r,updatedAt:m};return await this.putJson(`${e.remotePrefix}/cursor.json`,h),await this.putJson(`${e.remotePrefix}/session.json`,f),{uploadedEvents:c,lastRemoteSequence:u.maxSequence,eventCount:f.eventCount,chunkCount:f.chunkCount,status:l}}};import{closeSync as et,existsSync as Cs,fsyncSync as Is,mkdirSync as As,openSync as tt,readSync as Es,rmSync as Wt,statSync as Ft,writeSync as Ps}from"node:fs";import{join as nt}from"node:path";var Ms=12e4,Ts=80,Os=2e3;function Rs(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}var ve=class{constructor(e){this.identity=e;As(e.localDirectory,{recursive:!0}),this.eventsFile=nt(e.localDirectory,"events.jsonl"),this.stateFile=nt(e.localDirectory,"state.json"),this.lockFile=nt(e.localDirectory,"journal.lock")}identity;eventsFile;stateFile;lockFile;initialState(){let e=new Date().toISOString();return{version:1,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,status:"idle",createdAt:e,updatedAt:e,lastSequence:0,lastRemoteSequence:0,remoteByteOffset:0,sourceCursors:{},recentEventIds:[]}}loadStateUnsafe(){return $t(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(e){E(this.stateFile,e)}acquireLock(){for(let e=0;e<Ts;e+=1)try{return tt(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-Ft(this.lockFile).mtimeMs>Ms){Wt(this.lockFile,{force:!0});continue}}catch{}Rs(25)}throw new Error(`Session journal is locked: ${this.lockFile}`)}withLock(e){let n=this.acquireLock();try{return e()}finally{et(n),Wt(this.lockFile,{force:!0})}}append(e){return e.length===0?[]:this.withLock(()=>{let n=this.loadStateUnsafe(),r=new Set(n.recentEventIds),s=n.lastSequence,o=[];for(let l of e){let m=l.timestamp??new Date().toISOString(),d=l.data??{},f=l.provenance?.rawDigest??w(_t(d)),h=l.sourceEventId?[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,l.sourceEventId].join("|"):[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,s+1,l.type,m,f].join("|"),y=w(h).slice(0,32);if(r.has(y))continue;s+=1;let g={version:1,id:y,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,type:l.type,timestamp:m,data:d,provenance:{...l.provenance,rawDigest:f}};l.role!==void 0&&(g.role=l.role),l.sourceEventId!==void 0&&(g.sourceEventId=l.sourceEventId),l.sourceSequence!==void 0&&(g.sourceSequence=l.sourceSequence),o.push(g),r.add(y)}if(o.length===0)return[];let i=o.map(l=>JSON.stringify(l)).join(`
9
+ `,$=v(C).slice(0,16),T=[e.remotePrefix,"events",`${rt(h.sequence)}-${rt(w.sequence)}-${$}.jsonl`].join("/");await this.storage.exists(T)||await this.storage.put(T,C,"application/x-ndjson"),c+=g.length}let a=await this.scan(e),p=n[n.length-1],u=o?.status??"active";p?.type==="session_end"||p?.type==="session_idle"?u="idle":p?.type==="error"?u="error":n.length>0&&(u="active");let m=new Date().toISOString(),l=n[0],S={version:1,projectId:e.projectId,projectName:e.projectName,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,status:u,createdAt:o?.createdAt??l?.timestamp??m,updatedAt:p?.timestamp??m,firstEventAt:o?.firstEventAt??l?.timestamp,lastEventAt:p?.timestamp??o?.lastEventAt,eventCount:a.maxSequence,chunkCount:a.chunks.length,metadata:{...o?.metadata,...s.metadata}};(s.title??o?.title)&&(S.title=s.title??o?.title);let y={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,lastLocalSequence:n.length>0?n[n.length-1].sequence:a.maxSequence,lastRemoteSequence:a.maxSequence,sourceCursors:r,updatedAt:m};return await this.putJson(`${e.remotePrefix}/cursor.json`,y),await this.putJson(`${e.remotePrefix}/session.json`,S),{uploadedEvents:c,lastRemoteSequence:a.maxSequence,eventCount:S.eventCount,chunkCount:S.chunkCount,status:u}}};import{closeSync as Ee,existsSync as Gn,fsyncSync as Qn,mkdirSync as Xn,openSync as Oe,readSync as Zn,rmSync as st,statSync as ot,writeSync as er}from"node:fs";import{join as Pe}from"node:path";var tr=12e4,nr=80,rr=2e3;function sr(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}var ne=class{constructor(e){this.identity=e;Xn(e.localDirectory,{recursive:!0}),this.eventsFile=Pe(e.localDirectory,"events.jsonl"),this.stateFile=Pe(e.localDirectory,"state.json"),this.lockFile=Pe(e.localDirectory,"journal.lock")}identity;eventsFile;stateFile;lockFile;initialState(){let e=new Date().toISOString();return{version:1,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,status:"idle",createdAt:e,updatedAt:e,lastSequence:0,lastRemoteSequence:0,remoteByteOffset:0,sourceCursors:{},recentEventIds:[]}}loadStateUnsafe(){return et(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(e){I(this.stateFile,e)}acquireLock(){for(let e=0;e<nr;e+=1)try{return Oe(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-ot(this.lockFile).mtimeMs>tr){st(this.lockFile,{force:!0});continue}}catch{}sr(25)}throw new Error(`Session journal is locked: ${this.lockFile}`)}withLock(e){let n=this.acquireLock();try{return e()}finally{Ee(n),st(this.lockFile,{force:!0})}}append(e){return e.length===0?[]:this.withLock(()=>{let n=this.loadStateUnsafe(),r=new Set(n.recentEventIds),s=n.lastSequence,o=[];for(let u of e){let m=u.timestamp??new Date().toISOString(),l=u.data??{},S=u.provenance?.rawDigest??v(Ze(l)),y=u.sourceEventId?[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,u.sourceEventId].join("|"):[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,s+1,u.type,m,S].join("|"),g=v(y).slice(0,32);if(r.has(g))continue;s+=1;let h={version:1,id:g,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,type:u.type,timestamp:m,data:l,provenance:{...u.provenance,rawDigest:S}};u.role!==void 0&&(h.role=u.role),u.sourceEventId!==void 0&&(h.sourceEventId=u.sourceEventId),u.sourceSequence!==void 0&&(h.sourceSequence=u.sourceSequence),o.push(h),r.add(g)}if(o.length===0)return[];let i=o.map(u=>JSON.stringify(u)).join(`
10
10
  `)+`
11
- `,a=tt(this.eventsFile,"a",384);try{Ps(a,i,null,"utf8"),Is(a)}finally{et(a)}let c=o[o.length-1],u="active";c.type==="session_end"||c.type==="session_idle"?u="idle":c.type==="error"&&(u="error");let p=Array.from(r).slice(-Os);return this.saveStateUnsafe({...n,status:u,updatedAt:c.timestamp,lastSequence:c.sequence,recentEventIds:p}),o})}readPending(){return this.withLock(()=>{let e=this.loadStateUnsafe();if(!Cs(this.eventsFile))return{events:[],startOffset:e.remoteByteOffset,endOffset:e.remoteByteOffset};let n=Ft(this.eventsFile).size,r=Math.min(e.remoteByteOffset,n);if(n<=r)return{events:[],startOffset:r,endOffset:n};let s=n-r,o=Buffer.alloc(s),i=tt(this.eventsFile,"r");try{Es(i,o,0,s,r)}finally{et(i)}return{events:o.toString("utf8").split(`
12
- `).filter(Boolean).map(u=>JSON.parse(u)),startOffset:r,endOffset:n}})}markRemote(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,lastRemoteSequence:Math.max(r.lastRemoteSequence,e),remoteByteOffset:Math.max(r.remoteByteOffset,n),updatedAt:new Date().toISOString()})})}setSourceCursor(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,sourceCursors:{...r.sourceCursors,[e]:String(n)},updatedAt:new Date().toISOString()})})}};import{closeSync as ji,existsSync as Ci,openSync as Ii,readSync as Ai,statSync as Ei}from"node:fs";function zt(t,e){let n=e.toLowerCase();return n.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||n.includes("tuy\u1EC7t \u0111\u1ED1i")||n.includes("must not")||n.includes("never ")?"critical":t==="rule"||t==="decision"?"high":t==="todo"||n.includes("error")||n.includes("failed")||n.includes("exception")?"normal":"temporary"}var Jt=[/không được/iu,/tuyệt đối/iu,/bắt buộc/iu,/đừng\s+/iu,/must not/iu,/do not/iu,/don't/iu,/\bnever\b/iu],Ns=[/từ giờ/iu,/về sau/iu,/mỗi lần/iu,/luôn luôn/iu,/\bluôn\b/iu,/quy tắc/iu,/workflow/iu,/\balways\b/iu,/\brequired\b/iu,/\bmust\b/iu,/from now on/iu],_s=[/\bchốt\b/iu,/quyết định/iu,/sẽ dùng/iu,/chọn .+ thay/iu,/đổi sang/iu,/chuyển sang/iu,/\bdecided\b/iu,/\bchosen\b/iu,/we will use/iu,/use .+ instead/iu,/switch(?:ed)? to/iu],$s=[/\btodo\b/iu,/cần làm/iu,/cần thêm/iu,/cần sửa/iu,/cần kiểm tra/iu,/tiếp theo/iu,/bước tiếp theo/iu,/còn phải/iu,/còn cần/iu,/next step/iu,/\bneed to\b/iu,/\bremaining\b/iu,/follow[- ]?up/iu],Ks=[/đã sửa/iu,/đã fix/iu,/đã khắc phục/iu,/đã xử lý/iu,/hoàn tất/iu,/hoàn thành/iu,/\bfixed\b/iu,/\bresolved\b/iu,/\bimplemented\b/iu,/\bcompleted\b/iu,/\bpasses?\b/iu],Bt=[/kiến trúc/iu,/pipeline/iu,/adapter/iu,/schema/iu,/runtime/iu,/namespace/iu,/storage/iu,/lưu trữ/iu,/workflow/iu,/session core/iu,/memory engine/iu,/retrieval/iu],Ls=[/\bdùng\b/iu,/\btách\b/iu,/\bthay\b/iu,/\bchuyển\b/iu,/\blưu\b/iu,/\bmap\b/iu,/\buse\b/iu,/\bsplit\b/iu,/\bstore\b/iu,/\breplace\b/iu,/\bmove\b/iu],Ds=[/đường dẫn/iu,/\bpath\b/iu,/\bport\b/iu,/\bendpoint\b/iu,/\bdomain\b/iu,/\bbucket\b/iu,/\brepository\b/iu,/\brepo\b/iu,/\bbranch\b/iu,/\/[A-Za-z0-9._/-]{4,}/u],Ws=[/\blà\b/iu,/\bở\b/iu,/\bdùng\b/iu,/\bnằm\b/iu,/\bis\b/iu,/\buse\b/iu,/located/iu,/runs on/iu],Vt=new Set(["content","text","message","prompt","summary","description","reason","title","last_assistant_message","lastAssistantMessage","input_messages","inputMessages"]),Fs=new Set(["payload","data","content","message","messages","parts","summary"]);function P(t,e){return e.some(n=>n.test(t))}function Ht(t){return t.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function zs(t){return Ht(t).toLowerCase().replace(/[^\p{L}\p{N}:/._-]+/gu," ").replace(/\s+/g," ").trim()}function Bs(t){return!(t.length<12||t.length>1e3||(t.match(new RegExp("\\p{L}","gu"))??[]).length<6||/^(?:https?:\/\/\S+|[A-Za-z0-9+/=]{80,})$/u.test(t))}function rt(t,e,n,r=0){if(!(r>6)){if(typeof t=="string"){(!e||Vt.has(e))&&n.push(t);return}if(Array.isArray(t)){for(let s of t.slice(0,50))rt(s,e,n,r+1);return}if(!(!t||typeof t!="object"))for(let[s,o]of Object.entries(t))(Vt.has(s)||Fs.has(s))&&rt(o,s,n,r+1)}}function Vs(t){let e=[];rt(t.data,void 0,e);let n=[],r=new Set;for(let s of e)for(let o of s.split(/\n+|(?<=[.!?])\s+/u)){let i=Ht(o);if(Bs(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function qt(t){return(t.role??(typeof t.data.role=="string"?t.data.role:"")).toLowerCase()}function qs(t,e,n){if(n.type==="decision")return{kind:"decision",confidence:1};if(n.type==="todo")return{kind:"todo",confidence:1};let r=e==="user"||n.type==="user_prompt",s=e==="assistant"||n.type==="assistant_message";return r&&P(t,Jt)?{kind:"rule",confidence:.98}:r&&P(t,Ns)?{kind:"rule",confidence:.92}:P(t,_s)?{kind:P(t,Bt)?"architecture":"decision",confidence:r?.93:.86}:r&&P(t,$s)?{kind:"todo",confidence:.87}:P(t,Bt)&&P(t,Ls)?{kind:"architecture",confidence:r?.88:.82}:s&&P(t,Ks)?{kind:"fix",confidence:.8}:r&&P(t,Ds)&&P(t,Ws)?{kind:"context",confidence:.79}:null}function Js(t){switch(t){case"rule":return"rule";case"decision":case"architecture":return"decision";case"todo":return"todo";case"fix":case"context":return"code"}}function Hs(t,e,n){return t==="rule"&&P(n,Jt)?"critical":t==="architecture"||t==="decision"||t==="rule"?"high":t==="fix"||t==="context"?"normal":zt(e,n)}function Gt(t,e){let n=[],r=new Set,s=new Map;for(let o of e){let i=typeof o.data.messageId=="string"?o.data.messageId:void 0,a=qt(o);i&&a&&s.set(i,a)}for(let o of e){let i=qt(o),a=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&a&&(i=s.get(a)??"");for(let c of Vs(o)){let u=qs(c,i,o);if(!u||u.confidence<.75)continue;let p=Js(u.kind),l=zs(c),m=w([t.projectId,u.kind,l].join("|"));if(r.has(m))continue;r.add(m);let d=o.provenance.sourcePath?[o.provenance.sourcePath]:[],f=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:m,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,kind:u.kind,type:p,content:c,confidence:u.confidence,importance:Hs(u.kind,p,c),tags:[p],provenance:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventIds:[o.id],sourceEventIds:f,sourcePaths:d,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}import{createHash as Gs}from"node:crypto";var Us=["project-knowledge","implementation","continuation","session-context"],Ys={"project-knowledge":"Project knowledge",implementation:"Implementation state",continuation:"Work continuation","session-context":"Session context"};function st(t){return Gs("sha256").update(t).digest("hex")}function ke(t,e){return`${t}:${st(e).slice(0,24)}`}function Xs(t){try{return st(JSON.stringify(t))}catch{return st(String(t))}}function W(t){let e=new Set,n=[];for(let r of t){let s=r?.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function Yt(t,e=420){let n=t.replace(/\s+/gu," ").trim();return n.length<=e?n:`${n.slice(0,Math.max(0,e-1)).trimEnd()}\u2026`}function Qs(t){return t==="rule"||t==="architecture"?"project-knowledge":t==="decision"||t==="fix"?"implementation":t==="todo"?"continuation":"session-context"}function Ut(t){return t.length===0?0:t.reduce((e,n)=>e+n,0)/t.length}function Zs(t){return t.slice().sort((e,n)=>n.importanceScore-e.importanceScore||n.confidence-e.confidence||e.id.localeCompare(n.id)).slice(0,5).map(e=>Yt(e.content)).join(" | ")}function eo(t){return t.slice().sort((e,n)=>n.importanceScore-e.importanceScore||n.confidence-e.confidence||e.id.localeCompare(n.id)).slice(0,6).map(e=>Yt(e.content)).join(`
13
- `)}function Xt(t,e){let n=t.slice().sort((m,d)=>m.sequence-d.sequence||m.timestamp.localeCompare(d.timestamp)||m.id.localeCompare(d.id)),r=n.map(m=>({id:ke("raw",[m.projectId,m.agent,m.nativeSessionId,m.id,String(m.sequence)].join("|")),level:"raw",eventId:m.id,sourceEventId:m.sourceEventId,sequence:m.sequence,type:m.type,role:m.role,timestamp:m.timestamp,sourcePath:m.provenance.sourcePath,payloadDigest:Xs(m.data)})),s=new Map,o=new Map;n.forEach((m,d)=>{let f=r[d];f&&(s.set(m.id,f.id),m.sourceEventId&&o.set(m.sourceEventId,f.id))});let i=e.map(m=>{let d=W([...m.provenance.eventIds.map(f=>s.get(f)),...m.provenance.sourceEventIds.map(f=>o.get(f))]);return{id:ke("fact",m.fingerprint),level:"fact",fingerprint:m.fingerprint,kind:m.kind,type:m.type,content:m.content,knowledgeClass:m.knowledgeClass,importanceScore:m.importanceScore,confidence:m.confidence,tags:W([...m.tags,"level:fact",`class:${m.knowledgeClass}`,`kind:${m.kind}`]),rawIds:d,sourcePaths:W(m.provenance.sourcePaths)}}),a=new Map;for(let m of i){let d=Qs(m.kind),f=a.get(d)??[];f.push(m),a.set(d,f)}let c=[];for(let m of Us){let d=a.get(m);if(!d?.length)continue;let f=d.slice().sort((y,g)=>g.importanceScore-y.importanceScore||g.confidence-y.confidence||y.id.localeCompare(g.id)),h=f.map(y=>y.id);c.push({id:ke("scene",`${m}|${h.join("|")}`),level:"scene",kind:m,title:Ys[m],summary:Zs(f),factIds:h,importanceScore:Math.max(...f.map(y=>y.importanceScore)),confidence:Ut(f.map(y=>y.confidence)),tags:W(["level:scene",`scene:${m}`,...f.flatMap(y=>y.tags)]),sourcePaths:W(f.flatMap(y=>y.sourcePaths))})}let u=new Map(i.map(m=>[m.id,m])),p=[];for(let m of c){let f=m.factIds.map(g=>u.get(g)).filter(g=>!!g).filter(g=>(g.knowledgeClass==="permanent"||g.knowledgeClass==="task")&&g.importanceScore>=.55);if(f.length===0)continue;let h=f.some(g=>g.knowledgeClass==="permanent")?"permanent":"task",y=eo(f);p.push({id:ke("knowledge",`${m.id}|${h}|${f.map(g=>g.id).join("|")}`),level:"knowledge",knowledgeClass:h,title:m.title,content:y,sceneIds:[m.id],factIds:f.map(g=>g.id),importanceScore:Math.max(...f.map(g=>g.importanceScore)),confidence:Ut(f.map(g=>g.confidence)),tags:W(["level:knowledge",`class:${h}`,`scene:${m.kind}`,...f.flatMap(g=>g.tags)]),sourcePaths:W(f.flatMap(g=>g.sourcePaths))})}let l=[];for(let m of i)for(let d of m.rawIds)l.push({from:d,to:m.id,type:"supports"});for(let m of c)for(let d of m.factIds)l.push({from:d,to:m.id,type:"belongs_to"});for(let m of p)for(let d of m.sceneIds)l.push({from:d,to:m.id,type:"promotes_to"});return{schema:"toolnet.memory-hierarchy.v1",version:1,raw:r,facts:i,scenes:c,knowledge:p,links:l,stats:{raw:r.length,facts:i.length,scenes:c.length,knowledge:p.length,links:l.length}}}function be(t){return t?Math.ceil(t.length/3.5):0}function xe(t,e){if(!t)return"";if(be(t)<=e)return t;let r=Math.floor(e*3.5),s=t.slice(0,r),o=s.lastIndexOf("."),i=s.lastIndexOf(`
14
- `),a=Math.max(o,i);return a>r*.7?s.slice(0,a+1):s}function F(){let t=pe(),e=process.env.TOOLNET_SESSION_SAVE||"summary",n=process.env.TOOLNET_RAW_TRANSCRIPT==="on"||e==="archive"||e==="full",r=process.env.TOOLNET_MEMORY_PROMOTION||"conservative",s=parseFloat(process.env.TOOLNET_PROMOTE_MIN_SCORE||"0.65"),o=parseInt(process.env.TOOLNET_SESSION_SUMMARY_MAX_TOKENS||"700",10),i=parseInt(process.env.TOOLNET_DURABLE_MEMORY_MAX_ITEMS_PER_SESSION||"10",10),a=n,c=process.env.TOOLNET_RAW_TRANSCRIPT_REMOTE==="on"||e==="full";return{sessionSave:e,rawTranscript:n,memoryPromotion:r,promoteMinScore:s,sessionSummaryMaxTokens:o,durableMemoryMaxItemsPerSession:i,archiveLocal:a,archiveRemote:c}}function Qt(t){return(t||F()).rawTranscript}function Zt(t){return(t||F()).durableMemoryMaxItemsPerSession}function en(t){return(t||F()).sessionSummaryMaxTokens}function tn(t){return(t||F()).archiveRemote}function to(t){return t.replace(/\b[A-Za-z0-9_-]{20,}\b/g,"[REDACTED]").replace(/api[_-]?key[:\s=]+[^\s]+/gi,"api_key=[REDACTED]").replace(/token[:\s=]+[^\s]+/gi,"token=[REDACTED]").replace(/secret[:\s=]+[^\s]+/gi,"secret=[REDACTED]").replace(/password[:\s=]+[^\s]+/gi,"password=[REDACTED]")}function no(t,e){let n=t.toLowerCase(),r=.5,s=["nh\u1EDB","remember","quy t\u1EAFc","rule","t\u1EEB gi\u1EDD","from now","kh\xF4ng \u0111\u01B0\u1EE3c","must not","lu\xF4n lu\xF4n","always","never","critical","important","blocker","deploy","production","architecture"];for(let i of s)n.includes(i)&&(r+=.15);e==="rule"||e==="architecture"||e==="blocker"?r+=.2:e==="decision"||e==="deploy"?r+=.15:(e==="fix"||e==="next_action")&&(r+=.1),t.length<20?r-=.3:t.length>500&&(r-=.1);let o=[/npm (notice|warn|ERR)/i,/\d+ packages? in \d+/i,/found \d+ vulnerabilities/i,/up to date/i,/added \d+ packages/i,/^(ok|done|success|error|warning)$/i];for(let i of o)i.test(t)&&(r-=.4);return Math.max(0,Math.min(1,r))}function ro(t,e){let n=[],r=new Set;for(let i of t){let a=i.split(`
15
- `).filter(c=>c.trim());for(let c of a){let u=c.trim();if(u.length<15)continue;let p=u.toLowerCase().replace(/\s+/g," ");if(r.has(p))continue;r.add(p);let l="decision";/\b(rule|quy tắc|policy|standard|convention)\b/i.test(u)||/\b(always|never|must|should|từ giờ|không được)\b/i.test(u)?l="rule":/\b(fix|fixed|bug|issue|error|lỗi)\b/i.test(u)?l="fix":/\b(blocker|blocked|stuck|cannot|không thể)\b/i.test(u)?l="blocker":/\b(next|todo|action|task|cần làm)\b/i.test(u)?l="next_action":/\b(deploy|release|publish|ship)\b/i.test(u)?l="deploy":/\b(architecture|design|structure|pattern)\b/i.test(u)?l="architecture":/\.(ts|js|py|go|rs|java|cpp|c|h)\b/i.test(u)&&(l="file");let m=no(u,l);if(m<.3)continue;let d=to(u);n.push({category:l,text:d,importance:m,sourceSessionId:e})}}let s=F(),o=Zt(s);return n.sort((i,a)=>a.importance-i.importance).slice(0,o)}function so(t){let e=F(),n=en(e),o=t.join(`
16
-
17
- `).split(`
18
- `).filter(i=>{let a=i.trim();return a.length>20&&!a.startsWith("npm")&&!a.startsWith("\u2713")&&!a.startsWith("Error:")}).slice(0,20).join(`
19
- `);return xe(o,n)}function je(t,e){let r=(Array.isArray(t)?t:t.split(`
20
-
21
- `).filter(d=>d.trim())).map(d=>typeof d=="string"?d:JSON.stringify(d)).filter(d=>d.trim()),s=ro(r,e),o=s.filter(d=>d.category==="decision").map(d=>d.text),i=s.filter(d=>d.category==="rule").map(d=>d.text),a=s.filter(d=>d.category==="file").map(d=>d.text),c=s.filter(d=>d.category==="fix").map(d=>d.text),u=s.filter(d=>d.category==="blocker").map(d=>d.text),p=s.filter(d=>d.category==="next_action").map(d=>d.text),l=s.filter(d=>d.category==="deploy").map(d=>d.text);return{summary:so(r),decisions:o,projectRules:i,filesChanged:a,bugsFixed:c,commands:l,blockers:u,nextActions:p,durableFacts:s}}function K(t){let e=new Set,n=[];for(let r of t){let s=r?.replace(/\s+/g," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function oo(t){let e=new Map;for(let n of t){if(!n||!n.id||!Number.isFinite(n.sequence))continue;let r=n.sourceEventId?`${n.agent}:${n.sourceEventId}`:n.id,s=e.get(r);(!s||n.sequence>s.sequence)&&e.set(r,n)}return[...e.values()].sort((n,r)=>n.sequence-r.sequence||n.timestamp.localeCompare(r.timestamp))}function io(t){switch(t){case"critical":return 1;case"high":return .85;case"normal":return .6;case"temporary":return .25}}function ao(t){let e=io(t.importance);return Math.max(0,Math.min(1,e*.75+t.confidence*.25))}function co(t){return t.importance==="temporary"||t.confidence<.78?"transient":t.kind==="rule"||t.kind==="architecture"?"permanent":t.kind==="decision"||t.kind==="todo"||t.kind==="fix"?"task":"session"}function uo(t){let e=t.normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}_./:-]+/gu)??[],n=new Set;for(let r of e)if(!(r.length<2||/^\d+$/u.test(r))&&(n.add(r),n.size>=40))break;return[...n]}function lo(t){let e=co(t),n=ao(t),r=uo(t.content);return{...t,knowledgeClass:e,importanceScore:n,retrievalTerms:r,tags:K([...t.tags,"level:fact",`class:${e}`,`kind:${t.kind}`])}}function po(t){return t.map(e=>{try{return JSON.stringify({type:e.type,role:e.role,data:e.data,provenance:{sourcePath:e.provenance.sourcePath,files:e.provenance.files}})}catch{return""}}).filter(Boolean)}function mo(t,e,n){let r=je(po(e),t.nativeSessionId),s=n.filter(u=>u.kind==="todo").map(u=>u.content),o=n.flatMap(u=>u.provenance.sourcePaths),i=n.filter(u=>u.kind==="architecture").map(u=>u.content),a=K([...s,...r.nextActions]),c=K([...r.nextActions,...s]);return{summary:r.summary,state:{task:c[0]??a[0],decisions:K(r.decisions),files:K([...r.filesChanged,...o]),todos:a,completed:K(r.bugsFixed),blockers:K(r.blockers),nextActions:c,architecture:K(i)}}}function nn(t,e){let n=oo(e),r=Gt(t,n).map(lo),s=r.filter(p=>p.knowledgeClass!=="transient").sort((p,l)=>l.importanceScore-p.importanceScore),{summary:o,state:i}=mo(t,n,s),a=s.map(p=>({fingerprint:p.fingerprint,kind:p.kind,knowledgeClass:p.knowledgeClass,importanceScore:p.importanceScore,content:p.content,terms:p.retrievalTerms})),c=Xt(n,s),u=p=>r.filter(l=>l.knowledgeClass===p).length;return{version:2,normalizedEvents:n,summary:o,state:i,candidates:s,retrievalIndex:a,hierarchy:c,stats:{inputEvents:e.length,normalizedEvents:n.length,extractedCandidates:r.length,persistedCandidates:s.length,permanent:u("permanent"),task:u("task"),session:u("session"),transient:u("transient")}}}import{createHash as fo}from"node:crypto";import{chmodSync as rn,existsSync as go,mkdirSync as yo,readFileSync as ho,renameSync as So,writeFileSync as sn}from"node:fs";import{dirname as on,join as Ce}from"node:path";var at="toolnet.context-offload.v1",wo="toolnet.context-offload-asset.v1",vo=256,ko=new Set(["tool_call","tool_result","file_read","file_write","file_edit","command","test","artifact"]);function an(t){return Ce(t,".toolnet","offload")}function bo(t){return Ce(an(t),"assets")}function cn(t){return Ce(an(t),"graph.json")}function un(t){yo(t,{recursive:!0,mode:448});try{rn(t,448)}catch{}}function xo(t,e){un(on(t));let n=`${t}.${process.pid}.${Date.now()}.tmp`;sn(n,e,{encoding:"utf8",mode:384}),So(n,t);try{rn(t,384)}catch{}}function it(t){return Array.isArray(t)?t.map(it):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).sort(([e],[n])=>e.localeCompare(n)).map(([e,n])=>[e,it(n)])):t}function jo(t){return fo("sha256").update(JSON.stringify(it(t)),"utf8").digest("hex")}function ot(){return{schema:at,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function Co(t){let e=cn(t);if(!go(e))return ot();try{let n=JSON.parse(ho(e,"utf8"));return n.schema!==at||n.version!==1||!Array.isArray(n.nodes)?ot():n}catch{return ot()}}function Io(t,e){xo(cn(t),JSON.stringify(e,null,2)+`
22
- `)}function Ao(t,e=260){if(typeof t!="string")return null;let n=t.replace(/\s+/gu," ").trim();return n?n.slice(0,e):null}function Eo(t){let e=[...t.provenance.files??[],t.provenance.sourcePath],n=[];for(let r of e){let s=Ao(r);if(!(!s||n.includes(s))&&(n.push(s),n.length===3))break}return n}function Po(t){return`${t.agent}:${t.sourceEventId??t.id}`.replace(/\s+/gu," ").trim().slice(0,120)}function Mo(t,e){un(on(t));try{return sn(t,e,{encoding:"utf8",flag:"wx",mode:384}),!0}catch(n){if(n.code==="EEXIST")return!1;throw n}}function To(t,e){let n=t.nodes.find(s=>s.id===e.id),r=n?{...n,kind:e.kind,bytes:e.bytes,sourceRefs:Array.from(new Set([...n.sourceRefs,...e.sourceRefs])).slice(-8),files:Array.from(new Set([...n.files,...e.files])).slice(0,6)}:e;return{schema:at,version:1,updatedAt:new Date().toISOString(),nodes:[...t.nodes.filter(s=>s.id!==e.id),r].slice(-vo)}}function ln(t,e){let n=Co(t),r=0,s=0,o=0,i=[];for(let a of e){if(!ko.has(a.type))continue;r+=1;let c=jo({type:a.type,data:a.data}),u={schema:wo,version:1,assetId:c,event:{type:a.type,agent:a.agent,nativeSessionId:a.nativeSessionId,timestamp:a.timestamp,sourceEventId:a.sourceEventId,provenance:a.provenance,data:a.data}},p=JSON.stringify(u,null,2)+`
23
- `;Mo(Ce(bo(t),`${c}.json`),p)?s+=1:o+=1,i.push(c),n=To(n,{id:c,kind:a.type,bytes:Buffer.byteLength(p,"utf8"),createdAt:a.timestamp,sourceRefs:[Po(a)],files:Eo(a)})}return r>0&&Io(t,n),{eligible:r,written:s,deduped:o,graphNodes:n.nodes.length,assetIds:i}}import{createHash as Do}from"node:crypto";import{existsSync as Wo,readdirSync as Fo,readFileSync as zo}from"node:fs";import{basename as Bo,join as An}from"node:path";import{randomUUID as mn}from"node:crypto";var x=class extends Error{constructor(n,r){super(n);this.statusCode=r}statusCode};function re(t){let e=new Set,n=[];for(let r of t){let s=r.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function B(t){let e=t.normalize("NFKD").replace(/[\u0300-\u036f]/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,120);if(!e)throw new x("Invalid Wiki slug",400);return e}function dn(t){let e=[];for(let n of t.matchAll(/\[\[([^\[\]]+)\]\]/gu)){let r=n[1]?.trim();r&&e.push(B(r))}return re(e)}function Oo(t){return t.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_-]+/u).map(e=>e.trim()).filter(e=>e.length>=2)}function pn(t){return{id:`revision-${mn()}`,pageId:t.id,slug:t.slug,revision:t.revision,title:t.title,...t.summary?{summary:t.summary}:{},content:t.content,tags:[...t.tags],links:[...t.links],createdAt:t.updatedAt}}function z(t){return structuredClone(t)}var Ie=class{constructor(e){this.store=e}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}async mutate(e){let n,r=this.queue.then(async()=>{let s=await this.ensureState();n=e(s),s.updatedAt=new Date().toISOString(),await this.store.save(s)});return this.queue=r.then(()=>{},()=>{}),await r,n}async summary(){let e=await this.ensureState(),n=new Set(e.pages.flatMap(r=>r.links));return{schema:"toolnet.wiki-summary.v1",projectId:e.projectId,pages:e.pages.length,revisions:e.revisions.length,tags:re(e.pages.flatMap(r=>r.tags)).sort((r,s)=>r.localeCompare(s)),links:e.pages.reduce((r,s)=>r+s.links.length,0),orphanPages:e.pages.filter(r=>r.links.length===0&&!n.has(r.slug)).length,automatedPages:e.pages.filter(r=>r.tags.some(s=>s.startsWith("toolnet-auto-"))).length,updatedAt:e.updatedAt}}async listPages(){let e=await this.ensureState();return z([...e.pages].sort((n,r)=>n.title.localeCompare(r.title)))}async getPage(e){let n=await this.ensureState(),r=B(e),s=n.pages.find(o=>o.slug===r||o.id===e);if(!s)throw new x(`Wiki page not found: ${e}`,404);return z(s)}async createPage(e){return this.mutate(n=>{let r=e.title.trim(),s=e.content.trim();if(!r)throw new x("Wiki title is required",400);let o=B(e.slug??r);if(n.pages.some(c=>c.slug===o))throw new x(`Wiki page already exists: ${o}`,409);let i=new Date().toISOString(),a={id:`wiki-${mn()}`,slug:o,title:r,...e.summary?.trim()?{summary:e.summary.trim()}:{},content:s,tags:re(e.tags??[]),links:dn(s),revision:1,createdAt:i,updatedAt:i};return n.pages.push(a),n.revisions.push(pn(a)),z(a)})}async updatePage(e,n){return this.mutate(r=>{let s=B(e),o=r.pages.find(i=>i.slug===s||i.id===e);if(!o)throw new x(`Wiki page not found: ${e}`,404);if(n.title!==void 0){let i=n.title.trim();if(!i)throw new x("Wiki title is required",400);o.title=i}if(n.summary!==void 0){let i=n.summary.trim();i?o.summary=i:delete o.summary}return n.content!==void 0&&(o.content=n.content.trim(),o.links=dn(o.content)),n.tags!==void 0&&(o.tags=re(n.tags)),o.revision+=1,o.updatedAt=new Date().toISOString(),r.revisions.push(pn(o)),z(o)})}async history(e){let n=await this.getPage(e),r=await this.ensureState();return z(r.revisions.filter(s=>s.pageId===n.id).sort((s,o)=>o.revision-s.revision))}async backlinks(e){let n=await this.getPage(e),r=await this.ensureState();return z(r.pages.filter(s=>s.links.includes(n.slug)).sort((s,o)=>s.title.localeCompare(o.title)))}async search(e,n=10){let r=await this.ensureState(),s=re(Oo(e));if(s.length===0)return[];let o=Math.max(1,Math.min(20,Math.floor(n))),i=[];for(let a of r.pages){let c=a.title.toLowerCase(),u=a.slug.toLowerCase(),p=a.summary?.toLowerCase()??"",l=a.content.toLowerCase(),m=a.tags.map(f=>f.toLowerCase()),d=0;for(let f of s)u===f&&(d+=12),c===f&&(d+=10),c.includes(f)&&(d+=6),u.includes(f)&&(d+=5),m.some(h=>h===f)?d+=5:m.some(h=>h.includes(f))&&(d+=3),p.includes(f)&&(d+=2),l.includes(f)&&(d+=1);d>0&&i.push({page:z(a),score:d})}return i.sort((a,c)=>c.score-a.score||c.page.updatedAt.localeCompare(a.page.updatedAt)).slice(0,o)}};var fn="wiki/state.v1.json";function Ro(t){let e=new Date().toISOString();return{schema:"toolnet.wiki.v1",version:1,projectId:t.id,pages:[],revisions:[],createdAt:e,updatedAt:e}}function No(t,e){let n=JSON.parse(t);if(n.schema!=="toolnet.wiki.v1"||n.version!==1||n.projectId!==e.id||!Array.isArray(n.pages)||!Array.isArray(n.revisions))throw new Error("Invalid ToolNet Wiki state");return n}var Ae=class{constructor(e,n){this.storage=e;this.project=n}storage;project;async load(){let e=await this.storage.getText(fn);if(!e){let n=Ro(this.project);return await this.save(n),n}return No(e,this.project)}async save(e){await this.storage.put(fn,JSON.stringify(e,null,2),"application/json")}};import{createHash as _o,randomUUID as gn}from"node:crypto";var yn="wiki/governance.v1.json",vn="toolnet.knowledge-governance.v1",hn=500,se={autoApproveThreshold:.86,criticalApproveThreshold:.94,staleAfterDays:90};function $o(t,e=0,n=1){return Math.max(e,Math.min(n,t))}function ct(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/gu," ").trim()}function Sn(t){return _o("sha256").update(t.normalize("NFKC").replace(/\s+/gu," ").trim()).digest("hex")}function Ko(t){let e=[t.title,t.summary??"",t.content.slice(0,2e3),...t.tags].join(" ").toLowerCase();return/\b(?:architecture|security|authentication|authorization|auth|database|production|deploy|deployment|payment|billing|permission|permissions|acl|credential|secret|migration)\b/u.test(e)}function Lo(t){let e=t.sourceType==="skill"?.96:t.sourceType==="memory"?.94:.88,n=t.tags.map(r=>r.toLowerCase());return(n.includes("permanent")||n.includes("task"))&&(e+=.03),t.content.length>=200&&(e+=.02),t.content.length<80&&(e-=.05),t.title.length<4&&(e-=.05),$o(e)}function wn(t){let e=new Date().toISOString();return{schema:vn,version:1,projectId:t,policy:{...se},reviews:[],audit:[],createdAt:e,updatedAt:e}}function kn(t){let e=t.autoApproveThreshold??se.autoApproveThreshold,n=t.criticalApproveThreshold??se.criticalApproveThreshold,r=t.staleAfterDays??se.staleAfterDays;if(!Number.isFinite(e)||e<.5||e>1)throw new x("Invalid autoApproveThreshold",400);if(!Number.isFinite(n)||n<.5||n>1)throw new x("Invalid criticalApproveThreshold",400);if(!Number.isInteger(r)||r<1||r>3650)throw new x("Invalid staleAfterDays",400);return{autoApproveThreshold:e,criticalApproveThreshold:n,staleAfterDays:r}}var Ee=class{constructor(e,n){this.storage=e;this.project=n}storage;project;async load(){let e=await this.storage.getText(yn);if(!e){let n=wn(this.project.id);return await this.save(n),n}try{let n=JSON.parse(e);if(n.schema!==vn||n.version!==1||n.projectId!==this.project.id||!Array.isArray(n.reviews)||!Array.isArray(n.audit))throw new Error("invalid");return{...n,policy:kn(n.policy??se)}}catch{let n=wn(this.project.id);return await this.save(n),n}}async save(e){await this.storage.put(yn,JSON.stringify(e,null,2),"application/json")}},Pe=class{constructor(e){this.store=e}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}audit(e,n,r,s={}){e.audit.push({id:gn(),action:n,principal:r,...s.reviewId?{reviewId:s.reviewId}:{},...s.sourceKey?{sourceKey:s.sourceKey}:{},timestamp:new Date().toISOString(),...s.metadata?{metadata:s.metadata}:{}}),e.audit.length>hn&&(e.audit=e.audit.slice(-hn))}async mutate(e){let n,r=this.queue.then(async()=>{let s=await this.ensureState();n=await e(s),s.updatedAt=new Date().toISOString(),await this.store.save(s)});return this.queue=r.then(()=>{},()=>{}),await r,n}async policy(){return{...(await this.ensureState()).policy}}async setPolicy(e,n){return this.mutate(r=>(r.policy=kn({...r.policy,...e}),this.audit(r,"policy:update",n,{metadata:{...r.policy}}),{...r.policy}))}async summary(){let e=await this.ensureState(),n=r=>e.reviews.filter(s=>s.status===r).length;return{schema:"toolnet.knowledge-governance-summary.v1",projectId:e.projectId,pending:n("pending"),approved:n("approved"),rejected:n("rejected"),superseded:n("superseded"),criticalPending:e.reviews.filter(r=>r.status==="pending"&&r.risk==="critical").length,conflictPending:e.reviews.filter(r=>r.status==="pending"&&r.risk==="conflict").length,auditEvents:e.audit.length,policy:{...e.policy},updatedAt:e.updatedAt}}async listReviews(e){let n=await this.ensureState();return structuredClone(n.reviews.filter(r=>!e||r.status===e).sort((r,s)=>s.updatedAt.localeCompare(r.updatedAt)))}async auditLog(e=100){let n=await this.ensureState(),r=Math.max(1,Math.min(500,Math.floor(e)));return structuredClone(n.audit.slice(-r).reverse())}async assess(e,n){let r=await this.ensureState(),s=Lo(e),o=ct(e.title),i=n.filter(p=>p.slug!==e.slug&&ct(p.title)===o&&Sn(p.content)!==Sn(e.content)).map(p=>p.slug),a=Ko(e),c=[];s<r.policy.autoApproveThreshold&&c.push(`confidence:${s.toFixed(2)}`),a&&s<r.policy.criticalApproveThreshold&&c.push("critical-knowledge"),i.length>0&&c.push("conflicting-knowledge");let u=i.length>0?"conflict":a?"critical":"normal";return{confidence:s,risk:u,requiresReview:i.length>0||s<r.policy.autoApproveThreshold||a&&s<r.policy.criticalApproveThreshold,reasons:c,conflicts:i}}async gate(e,n){let r=await this.assess(e,n);return this.mutate(s=>{let o=s.reviews.find(c=>c.sourceKey===e.sourceKey&&c.digest===e.digest);if(o?.status==="approved")return{allowed:!0,mode:"review-approved",assessment:r,review:structuredClone(o)};if(o?.status==="rejected")return{allowed:!1,mode:"rejected",assessment:r,review:structuredClone(o)};if(!r.requiresReview)return this.audit(s,"knowledge:auto-approved","system",{sourceKey:e.sourceKey,metadata:{confidence:r.confidence,risk:r.risk}}),{allowed:!0,mode:"auto-approved",assessment:r};if(o?.status==="pending")return{allowed:!1,mode:"pending-review",assessment:r,review:structuredClone(o)};let i=new Date().toISOString(),a={id:gn(),sourceKey:e.sourceKey,sourceType:e.sourceType,slug:e.slug,marker:e.marker,digest:e.digest,title:e.title,...e.summary?{summary:e.summary}:{},content:e.content,tags:[...new Set([...e.tags,e.marker])],confidence:r.confidence,risk:r.risk,reasons:[...r.reasons],conflicts:[...r.conflicts],status:"pending",createdAt:i,updatedAt:i};return s.reviews.push(a),this.audit(s,"knowledge:review-requested","system",{reviewId:a.id,sourceKey:a.sourceKey,metadata:{confidence:a.confidence,risk:a.risk}}),{allowed:!1,mode:"pending-review",assessment:r,review:structuredClone(a)}})}async markApplied(e,n){await this.mutate(r=>{let s=r.reviews.find(o=>o.sourceKey===e&&o.digest===n&&o.status==="approved");s&&(s.appliedAt=new Date().toISOString(),s.updatedAt=s.appliedAt,this.audit(r,"knowledge:applied",s.reviewedBy??"system",{reviewId:s.id,sourceKey:e}))})}async decide(e,n,r){return this.mutate(async s=>{let o=s.reviews.find(u=>u.id===e);if(!o)throw new x(`Governance review not found: ${e}`,404);if(o.status!=="pending")throw new x("Governance review is already resolved",409);let i=new Date().toISOString();if(o.reviewedAt=i,o.reviewedBy=n.principal,o.updatedAt=i,n.note?.trim()&&(o.reviewNote=n.note.trim()),n.action==="reject")return o.status="rejected",this.audit(s,"knowledge:rejected",n.principal,{reviewId:e,sourceKey:o.sourceKey}),structuredClone(o);if(n.action==="supersede")return o.status="superseded",n.targetReviewId&&(o.supersededBy=n.targetReviewId),this.audit(s,"knowledge:superseded",n.principal,{reviewId:e,sourceKey:o.sourceKey,metadata:{targetReviewId:n.targetReviewId}}),structuredClone(o);if(n.action==="merge"){if(!n.targetReviewId)throw new x("targetReviewId is required for merge",400);let u=s.reviews.find(p=>p.id===n.targetReviewId);if(!u)throw new x("Merge target review not found",404);return o.status="superseded",o.mergedInto=u.id,this.audit(s,"knowledge:merged",n.principal,{reviewId:e,sourceKey:o.sourceKey,metadata:{targetReviewId:u.id}}),structuredClone(o)}o.status="approved";let c=(await r.listPages()).find(u=>u.slug===o.slug);if(c&&!c.tags.includes(o.marker))throw new x(`Wiki page '${o.slug}' is manually managed`,409);return c?await r.updatePage(o.slug,{title:o.title,summary:o.summary??"",content:o.content,tags:o.tags}):await r.createPage({slug:o.slug,title:o.title,...o.summary?{summary:o.summary}:{},content:o.content,tags:o.tags}),o.appliedAt=i,this.audit(s,"knowledge:approved",n.principal,{reviewId:e,sourceKey:o.sourceKey}),structuredClone(o)})}async quality(e){let n=await this.ensureState(),r=await e.listPages(),s=Date.now(),o=n.policy.staleAfterDays*864e5,i=r.map(p=>{let l=s-Date.parse(p.updatedAt);return{slug:p.slug,title:p.title,updatedAt:p.updatedAt,ageDays:Math.max(0,Math.floor(l/864e5)),stale:Number.isFinite(l)&&l>o}}).filter(p=>p.stale).map(({stale:p,...l})=>l),a=new Map;for(let p of r){let l=ct(p.title),m=a.get(l)??[];m.push(p),a.set(l,m)}let c=[...a.entries()].filter(([,p])=>p.length>1).map(([p,l])=>({title:p,pages:l.map(m=>m.slug)})),u=n.reviews.filter(p=>p.status==="pending");return{schema:"toolnet.knowledge-quality.v1",totalPages:r.length,automatedPages:r.filter(p=>p.tags.some(l=>l.startsWith("toolnet-auto-"))).length,manualPages:r.filter(p=>!p.tags.some(l=>l.startsWith("toolnet-auto-"))).length,stalePages:i,duplicateTitles:c,pendingReviews:u.length,lowConfidenceReviews:u.filter(p=>p.confidence<n.policy.autoApproveThreshold).length,conflicts:u.filter(p=>p.risk==="conflict").length,generatedAt:new Date().toISOString()}}};var En="wiki/automation.v1.json",Pn="toolnet.wiki-automation.v1",dt=8e3,bn=new Set(["raw","rawtext","raw_text","rawtranscript","raw_transcript","transcript","messages","message","payload","prompt","response","assistantmessage","assistant_message","userprompt","user_prompt"]);function ie(t){return Do("sha256").update(JSON.stringify(t)).digest("hex")}function oe(t){if(!(!t||typeof t!="object"||Array.isArray(t)))return t}function xn(t){return Array.isArray(t)?t:[]}function Mn(t){return typeof t!="string"?void 0:t.replace(/\s+/gu," ").trim()||void 0}function ut(t){return Array.isArray(t)?t.map(Mn).filter(e=>!!e):[]}function R(t,e){for(let n of e){let r=Mn(t[n]);if(r)return r}}function ae(t){let e=new Set,n=[];for(let r of t){let s=r.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function Me(t,e=0,n=""){if(e>3)return[];let r=n.replace(/[^a-z0-9]/giu,"").toLowerCase();if(bn.has(r))return[];if(typeof t=="string"){let i=t.replace(/\s+/gu," ").trim();return i.length<8?[]:[i]}if(Array.isArray(t))return t.flatMap(i=>Me(i,e+1,n));let s=oe(t);if(!s)return[];let o=[];for(let[i,a]of Object.entries(s)){let c=i.replace(/[^a-z0-9]/giu,"").toLowerCase();bn.has(c)||o.push(...Me(a,e+1,i))}return o}function jn(t){let n=ae(["content","summary","text","value","statement","description","decision","task","knowledge","context","outcome","reason","rationale"].flatMap(s=>Me(t[s],0,s)));return(n.length>0?n:ae(Me(t))).join(`
24
-
25
- `).slice(0,dt)}function Cn(t,e){return R(t,["id","key","fingerprint","knowledgeId","sceneId"])??e}function In(t,e){return R(t,["title","name","topic","label","task","kind","type"])??e}function Vo(t){return(R(t,["knowledgeClass","class","classification","scope"])??"").toLowerCase()}function qo(t){return(R(t,["kind","sceneKind","type"])??"").toLowerCase()}function Jo(t){let e=oe(t);if(!e)return[];let n=[],r=xn(e.knowledge);for(let[o,i]of r.entries()){let a=oe(i);if(!a)continue;let c=Vo(a);if(c==="session"||c==="transient")continue;let u=jn(a);if(u.length<20)continue;let p=Cn(a,ie(a).slice(0,16)),l=In(a,`Durable Memory ${o+1}`);n.push({sourceKey:`memory:${p}`,sourceType:"memory",title:l,summary:R(a,["summary","description"]),content:u,tags:ae(["toolnet","auto","memory",...c?[c]:[]])})}let s=xn(e.scenes);for(let[o,i]of s.entries()){let a=oe(i);if(!a)continue;let c=qo(a);if(c==="session-context")continue;let u=jn(a);if(u.length<20)continue;let p=Cn(a,ie(a).slice(0,16)),l=In(a,`Knowledge Scene ${o+1}`);n.push({sourceKey:`scene:${p}`,sourceType:"scene",title:l,summary:R(a,["summary","description"]),content:u,tags:ae(["toolnet","auto","scene",...c?[c]:[]])})}return n}function Ho(t){return An(t,".toolnet","memory","skills")}function Go(t){let e=Ho(t);if(!Wo(e))return{candidates:[],failed:0};let n=[],r=0,s=Fo(e).filter(o=>o.endsWith(".json")).sort();for(let o of s)try{let i=JSON.parse(zo(An(e,o),"utf8")),a=oe(i);if(!a||a.schema!=="toolnet.skill-memory.v1")continue;let c=R(a,["id","fingerprint"])??Bo(o,".json"),u=R(a,["task"])??"",p=R(a,["title"])||u||`Reusable Skill ${c.slice(0,8)}`,l=R(a,["summary"])??void 0,m=ut(a.steps),d=ut(a.verification),f=ut(a.files),h=[];u&&h.push(`## Task
26
- ${u}`),l&&h.push(`## Summary
27
- ${l}`),m.length>0&&h.push(`## Procedure
28
- ${m.map((g,v)=>`${v+1}. ${g}`).join(`
29
- `)}`),d.length>0&&h.push(`## Verification
30
- ${d.map(g=>`- ${g}`).join(`
31
- `)}`),f.length>0&&h.push(`## Relevant Files
32
- ${f.map(g=>`- \`${g}\``).join(`
33
- `)}`);let y=h.join(`
34
-
35
- `).slice(0,dt);if(y.length<20)continue;n.push({sourceKey:`skill:${c}`,sourceType:"skill",title:p,summary:l,content:y,tags:["toolnet","auto","skill","sop"]})}catch{r+=1}return{candidates:n,failed:r}}function lt(t){let e=new Date().toISOString();return{schema:Pn,version:1,projectId:t,entries:[],createdAt:e,updatedAt:e}}async function Uo(t,e){let n=await t.getText(En);if(!n)return lt(e);try{let r=JSON.parse(n);return r.schema!==Pn||r.version!==1||r.projectId!==e||!Array.isArray(r.entries)?lt(e):r}catch{return lt(e)}}async function Yo(t,e){await t.put(En,JSON.stringify(e,null,2),"application/json")}function Xo(t){return`toolnet-auto-${ie(t).slice(0,12)}`}function Qo(t){let e=B(t.title).slice(0,72),n=ie(t.sourceKey).slice(0,10);return B(`auto-${t.sourceType}-${e}-${n}`)}function Zo(t){return[`> Auto-generated by ToolNet Knowledge Automation from ${t.sourceType==="skill"?"reusable Skill Memory":t.sourceType==="scene"?"semantic memory scene":"durable memory"}.`,"",t.content].join(`
36
- `).slice(0,dt)}function ei(t){return ie({sourceType:t.sourceType,title:t.title,summary:t.summary,content:t.content,tags:t.tags})}function ti(t,e){return t.tags.includes(e)}async function Tn(t){let e=Jo(t.hierarchy),n=Go(t.project.rootPath),r=new Map;for(let d of[...e,...n.candidates])r.set(d.sourceKey,d);let s=[...r.values()].sort((d,f)=>d.sourceKey.localeCompare(f.sourceKey)),o={schema:"toolnet.wiki-automation-result.v1",scanned:e.length+n.candidates.length,eligible:s.length,created:0,updated:0,unchanged:0,skipped:0,failed:n.failed,reviewPending:0,autoApproved:0,reviewApproved:0,pages:[]},i=new Ie(new Ae(t.storage,t.project));await i.initialize();let a=new Pe(new Ee(t.storage,t.project));await a.initialize();let c=await Uo(t.storage,t.project.id),u=await i.listPages(),p=new Map(u.map(d=>[d.slug,d])),l=new Map(c.entries.map(d=>[d.sourceKey,d]));for(let d of s)try{let f=Xo(d.sourceKey),h=ei(d),y=l.get(d.sourceKey),g=y?.slug??Qo(d),v=p.get(g);if(v&&!ti(v,f)){o.skipped+=1;continue}let A=ae([...d.tags,f]),O=Zo(d),C=await a.gate({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:g,marker:f,digest:h,title:d.title,...d.summary?{summary:d.summary}:{},content:O,tags:A},[...p.values()]);if(!C.allowed){C.mode==="pending-review"?o.reviewPending+=1:o.skipped+=1;continue}C.mode==="auto-approved"?o.autoApproved+=1:C.mode==="review-approved"&&(o.reviewApproved+=1),v?y?.digest!==h?(v=await i.updatePage(g,{title:d.title,summary:d.summary??"",content:O,tags:A}),p.set(v.slug,v),o.updated+=1,o.pages.push({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:v.slug,action:"updated"})):(o.unchanged+=1,o.pages.push({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:g,action:"unchanged"})):(v=await i.createPage({slug:g,title:d.title,summary:d.summary,content:O,tags:A}),p.set(v.slug,v),o.created+=1,o.pages.push({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:v.slug,action:"created"}));let _=new Date().toISOString(),S={sourceKey:d.sourceKey,sourceType:d.sourceType,slug:g,digest:h,marker:f,updatedAt:_},j=c.entries.findIndex(de=>de.sourceKey===d.sourceKey);j>=0?c.entries[j]=S:c.entries.push(S),l.set(d.sourceKey,S),await a.markApplied(d.sourceKey,h)}catch(f){if(f instanceof x&&f.statusCode===409){o.skipped+=1;continue}o.failed+=1}let m=new Date().toISOString();return c.updatedAt=m,c.lastRunAt=m,c.entries.sort((d,f)=>d.sourceKey.localeCompare(f.sourceKey)),await Yo(t.storage,c),o}import{createHash as ni}from"node:crypto";import{chmodSync as Rn,existsSync as ri,mkdirSync as si,readFileSync as Dl,readdirSync as Wl,renameSync as oi,statSync as Fl,writeFileSync as ii}from"node:fs";import{join as Nn}from"node:path";var ai="toolnet.skill-memory.v1",On=5,ci=16,ui=24,li=32;function di(t){return ni("sha256").update(t).digest("hex")}function ue(t,e=Number.MAX_SAFE_INTEGER){let n=new Set,r=[];for(let s of t){let o=s.replace(/\s+/gu," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();if(!n.has(i)&&(n.add(i),r.push(o),r.length>=e))break}return r}function pt(t,e=360){let n=t.replace(/\s+/gu," ").trim();return n.length<=e?n:n.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function pi(t){return t.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/giu,"Bearer [REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{8,}\b/gu,"[REDACTED]").replace(/\b(api[_-]?key|token|password|passwd|secret)\b(\s*[:=]\s*)(["']?)[^\s"'`]+/giu,"$1$2[REDACTED]")}function $(t,e=360){return t&&pt(pi(t),e)||void 0}function le(t,e){for(let n of e){let r=t[n];if(typeof r=="string"&&r.trim())return r}}function _n(t,e){for(let n of e){let r=t[n];if(typeof r=="number"&&Number.isFinite(r))return r;if(typeof r=="string"&&r.trim()&&Number.isFinite(Number(r)))return Number(r)}}function $n(t,e){for(let n of e){let r=t[n];if(typeof r=="boolean")return r;if(typeof r=="string"){let s=r.trim().toLowerCase();if(["true","yes","pass","passed","success","succeeded","ok"].includes(s))return!0;if(["false","no","fail","failed","error"].includes(s))return!1}}}function Kn(t){let e=t.data??{};if($n(e,["passed","pass","success","succeeded","ok"])===!1)return!0;let r=_n(e,["exitCode","exit_code","code","statusCode"]);if(r!==void 0&&r!==0)return!0;let s=le(e,["status","result","outcome"]);return!!(s&&/\b(fail(?:ed)?|error|broken|cancelled)\b/iu.test(s))}function ce(t){let e=t.data??{};if(Kn(t))return!1;if($n(e,["passed","pass","success","succeeded","ok"])===!0||_n(e,["exitCode","exit_code","code","statusCode"])===0)return!0;let s=le(e,["status","result","outcome"]);return s&&/\b(pass(?:ed)?|success(?:ful)?|succeeded|ok|green|complete(?:d)?)\b/iu.test(s)?!0:t.type==="commit"||t.type==="deploy"}function Ln(t){let e=t.data??{},n=le(e,["path","file","filePath","filename","target"]);if(n)return $(n,260);let r=t.provenance?.files;return $(r?.[0],260)}function mt(t){return $(le(t.data??{},["command","cmd","script"]),420)}function q(t){return $(le(t.data??{},["name","test","suite","title","message","text","result","status"]),300)}function mi(t){let e=[];for(let n of[...t].sort((r,s)=>r.sequence-s.sequence))if(ce(n)){if(n.type==="test"){let r=q(n)??mt(n)??"Tests passed";e.push(`Test passed: ${r}`);continue}if(n.type==="commit"){let r=q(n);e.push(r?`Commit: ${r}`:"Commit completed");continue}if(n.type==="deploy"){let r=q(n);e.push(r?`Deploy: ${r}`:"Deployment completed")}}return ue(e,10)}function fi(t,e){let n=[];for(let r of[...t].sort((s,o)=>s.sequence-o.sequence))switch(r.type){case"file_write":case"file_edit":{let s=Ln(r);s&&n.push(`Update ${s}`);break}case"command":{if(Kn(r))break;let s=mt(r);s&&n.push(`Run: ${s}`);break}case"test":{if(!ce(r))break;let s=q(r)??mt(r)??"project tests";n.push(`Verify: ${s}`);break}case"commit":{if(!ce(r))break;let s=q(r);n.push(s?`Commit: ${s}`:"Commit verified changes");break}case"deploy":{if(!ce(r))break;let s=q(r);n.push(s?`Deploy: ${s}`:"Deploy verified build");break}default:break}if(n.length===0)for(let r of e.files.slice(0,8)){let s=$(r,260);s&&n.push(`Update ${s}`)}return ue(n,ci)}function gi(t,e){let n=[...e.files];for(let r of t){let s=Ln(r);s&&n.push(s);for(let o of r.provenance?.files??[]){let i=$(o,260);i&&n.push(i)}}return ue(n,ui)}function yi(t){return ue(t.filter(e=>["file_write","file_edit","command","test","commit","deploy"].includes(e.type)).map(e=>e.id),li)}function hi(t){return t.map(n=>n.timestamp).filter(Boolean).sort().at(-1)??new Date(0).toISOString()}function Dn(t,e,n){if(e.length===0)return[];let r=mi(e),s=ue(n.completed.map(f=>$(f,280)??""),On);if(!(s.length>0||e.some(f=>["test","commit","deploy"].includes(f.type)&&ce(f))))return[];let i=$(n.task,280)??$(n.nextActions[0],280),a=s.length>0?s:i?[i]:[];if(a.length===0)return[];let c=fi(e,n);if(c.length===0)return[];let u=gi(e,n),p=yi(e),l=Math.min(...e.map(f=>f.sequence)),m=Math.max(...e.map(f=>f.sequence)),d=hi(e);return a.slice(0,On).map(f=>{let h=[`Reusable procedure learned from successful task: ${f}.`,u.length>0?`Files: ${u.slice(0,6).join(", ")}.`:"",r.length>0?`Verification: ${r.slice(0,4).join("; ")}.`:""].filter(Boolean),y=JSON.stringify({projectId:t.projectId,task:f,steps:c,verification:r,files:u}),g=di(y);return{schema:ai,version:1,id:`skill-${g.slice(0,24)}`,fingerprint:g,projectId:t.projectId,title:pt(`SOP: ${f}`,180),task:f,summary:pt(h.join(" "),900),steps:c,verification:r,files:u,source:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,firstSequence:l,lastSequence:m,eventIds:p},createdAt:d}})}function Si(t){return Nn(t.rootPath,".toolnet","memory","skills")}function wi(t){let e=Si(t);return si(e,{recursive:!0,mode:448}),Rn(e,448),e}function Wn(t,e){if(e.length===0)return{written:0,deduped:0,files:[]};let n=wi(t),r=0,s=0,o=[];for(let i of e){if(i.projectId!==t.id)throw new Error(`Skill project mismatch: ${i.projectId} != ${t.id}`);let a=Nn(n,`${i.id}.json`);if(o.push(a),ri(a)){s+=1;continue}let c=`${a}.${process.pid}.${Date.now()}.tmp`;ii(c,JSON.stringify(i,null,2)+`
37
- `,{encoding:"utf8",mode:384}),oi(c,a),Rn(a,384),r+=1}return{written:r,deduped:s,files:o}}function Fn(t){return String(t).padStart(12,"0")}function vi(t){return t.remotePrefix.replace("/sessions/","/memory/learned/")}var Te=class{constructor(e){this.storage=e}storage;async write(e,n,r){if(r.length===0||n.length===0)return null;let s=Math.min(...n.map(p=>p.sequence)),o=Math.max(...n.map(p=>p.sequence)),i={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,candidateCount:r.length,candidates:r},a=JSON.stringify(i,null,2)+`
38
- `,c=w(r.map(p=>p.fingerprint).sort().join("|")).slice(0,16),u=[vi(e),"batches",`${Fn(s)}-${Fn(o)}-${c}.json`].join("/");return await this.storage.exists(u)||await this.storage.put(u,a,"application/json"),u}};import{createHash as ki}from"node:crypto";function zn(t){return String(t).padStart(12,"0")}function bi(t){return ki("sha256").update(t).digest("hex")}function xi(t){return t.remotePrefix.replace("/sessions/","/memory/hierarchy/")}var Oe=class{constructor(e){this.storage=e}storage;async write(e,n,r){if(n.length===0||r.facts.length===0)return null;let s=Math.min(...n.map(u=>u.sequence)),o=Math.max(...n.map(u=>u.sequence)),i={schema:"toolnet.memory-hierarchy-batch.v1",version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,hierarchy:r},a=bi([...r.facts.map(u=>u.id),...r.knowledge.map(u=>u.id)].sort().join("|")).slice(0,16),c=[xi(e),"batches",`${zn(s)}-${zn(o)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,`${JSON.stringify(i,null,2)}
39
- `,"application/json"),c}};function Pi(t,e){if(!Ci(t))return{events:[],nextOffset:e};let n=Ei(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=Ii(t,"r");try{Ai(i,o,0,s,r)}finally{ji(i)}let a=o.toString("utf8"),c=a.lastIndexOf(`
40
- `);if(c<0)return{events:[],nextOffset:r};let u=a.slice(0,c+1);return{events:u.split(`
41
- `).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(u,"utf8")}}var Re=class{constructor(e){this.options=e;this.journal=new Te(e.storage),this.hierarchyJournal=new Oe(e.storage)}options;journal;hierarchyJournal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["memory.learner.offset"]??0),r=Number.isFinite(n)?n:0,s=Pi(this.options.wal.eventsFile,r);if(s.events.length===0)return{scannedEvents:0,candidates:0,journalWritten:!1,nextOffset:s.nextOffset};let o=nn(this.options.identity,s.events),i=o.candidates,a=!1;i.length>0&&(a=!!await this.journal.write(this.options.identity,s.events,i));let c=!1;o.hierarchy.facts.length>0&&(c=!!await this.hierarchyJournal.write(this.options.identity,s.events,o.hierarchy));let u=Dn(this.options.identity,s.events,o.state),p=Wn(this.options.project,u);this.options.wal.setSourceCursor("memory.pipeline.version",2),this.options.wal.setSourceCursor("memory.pipeline.normalized_events",o.stats.normalizedEvents),this.options.wal.setSourceCursor("memory.pipeline.persisted",o.stats.persistedCandidates),this.options.wal.setSourceCursor("memory.pipeline.permanent",o.stats.permanent),this.options.wal.setSourceCursor("memory.pipeline.task",o.stats.task),this.options.wal.setSourceCursor("memory.pipeline.session",o.stats.session),this.options.wal.setSourceCursor("memory.pipeline.transient",o.stats.transient),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.version",o.hierarchy.version),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.raw",o.hierarchy.stats.raw),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.facts",o.hierarchy.stats.facts),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.scenes",o.hierarchy.stats.scenes),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.knowledge",o.hierarchy.stats.knowledge),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.journal_written",c?1:0),this.options.wal.setSourceCursor("memory.skill.assets",u.length),this.options.wal.setSourceCursor("memory.skill.written",p.written),this.options.wal.setSourceCursor("memory.skill.deduped",p.deduped);try{let l=ln(this.options.project.rootPath,s.events);this.options.wal.setSourceCursor("memory.context_offload.eligible",l.eligible),this.options.wal.setSourceCursor("memory.context_offload.written",l.written),this.options.wal.setSourceCursor("memory.context_offload.deduped",l.deduped),this.options.wal.setSourceCursor("memory.context_offload.graph_nodes",l.graphNodes),this.options.wal.setSourceCursor("memory.context_offload.failed",0)}catch{this.options.wal.setSourceCursor("memory.context_offload.failed",1)}try{let l=await Tn({project:this.options.project,storage:this.options.storage,hierarchy:o.hierarchy});this.options.wal.setSourceCursor("memory.wiki_automation.scanned",l.scanned),this.options.wal.setSourceCursor("memory.wiki_automation.eligible",l.eligible),this.options.wal.setSourceCursor("memory.wiki_automation.created",l.created),this.options.wal.setSourceCursor("memory.wiki_automation.updated",l.updated),this.options.wal.setSourceCursor("memory.wiki_automation.unchanged",l.unchanged),this.options.wal.setSourceCursor("memory.wiki_automation.skipped",l.skipped),this.options.wal.setSourceCursor("memory.wiki_automation.failed",l.failed),this.options.wal.setSourceCursor("memory.wiki_automation.review_pending",l.reviewPending),this.options.wal.setSourceCursor("memory.wiki_automation.auto_approved",l.autoApproved),this.options.wal.setSourceCursor("memory.wiki_automation.review_approved",l.reviewApproved)}catch{this.options.wal.setSourceCursor("memory.wiki_automation.failed",1)}return this.options.wal.setSourceCursor("memory.learner.offset",s.nextOffset),{scannedEvents:s.events.length,candidates:i.length,journalWritten:a,nextOffset:s.nextOffset}}};import{closeSync as $i,existsSync as Ki,openSync as Li,readSync as Di,statSync as Wi}from"node:fs";var Mi=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function H(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function Vn(t){return H(t).toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function J(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))J(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Mi.has(r)||["data","payload","parts","messages"].includes(r))&&J(s,e,n+1)}}function Ne(t){return/\b(cancelled|canceled)\b|đã hủy|bỏ qua/iu.test(t)?"cancelled":/\b(blocked|blocker)\b|đang vướng|bị vướng|đang kẹt|chưa thể/iu.test(t)?"blocked":/\b(completed|complete|done|finished|passed)\b|hoàn thành|hoàn tất|đã xong|đã làm xong|\bxong\b/iu.test(t)?"completed":/\bin[\s_-]*progress\b|working on|đang làm|đang thực hiện|đang xử lý|đang triển khai/iu.test(t)?"in_progress":"pending"}function Bn(t){let e=H(t);return/^(?:đang\s+làm|đang\s+thực\s+hiện|đang\s+xử\s+lý|đang\s+triển\s+khai|hoàn\s+thành|hoàn\s+tất|đã\s+xong|đã\s+làm\s+xong|xong|pending|in[\s_-]*progress|completed|complete|done|finished|blocked|cancelled|canceled)[.!]*$/iu.test(e)}function I(t,e,n,r,s={}){let o=H(r),i=s.key??Vn(o);return{version:1,id:w([t.projectId,n,i,e.id,o,s.status??"",s.order??""].join("|")).slice(0,32),projectId:t.projectId,kind:n,key:i,text:o,status:s.status,order:s.order,confidence:s.confidence??.85,occurredAt:e.timestamp,sequence:e.sequence,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId}}function Ti(t,e,n){let r=H(n);if(r.length<5||r.length>1200)return[];let s=[],o=/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r),i=r.match(/^(?:mục tiêu|goal|objective)\s*(?::|-)\s*(.+)$/iu);i?.[1]&&s.push(I(t,e,"goal",i[1],{confidence:.97}));let a=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);a?.[1]&&s.push(I(t,e,"plan",a[1],{confidence:.95}));let c=/\b(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?([^.;\n]{0,220})/giu,u;for(;!o&&(u=c.exec(r));){let m=Number(u[1]),d=H(u[2]??""),f=d&&!Bn(d)?`Phase ${m} - ${d}`:`Phase ${m}`;s.push(I(t,e,"phase",f,{key:`phase:${m}`,order:m,status:Ne(r),confidence:.93}))}let p=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);p?.[2]&&s.push(I(t,e,"task",p[2],{status:p[1].trim()?"completed":Ne(p[2]),confidence:.96}));let l=r.match(/^(?:todo|task|việc)\s*(\d+)?(?:\s*[:.\-–—]\s*|\s+)(.+)$/iu);if(l?.[2]){let m=l[1]?Number(l[1]):void 0,d=H(l[2]),f=Bn(d);s.push(I(t,e,"task",f&&m!==void 0?`TODO ${m}`:d,{key:m!==void 0?`task:${m}`:Vn(d),order:m,status:Ne(r),confidence:.93}))}if(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r)){let m=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");m&&s.push(I(t,e,"next_action",m,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(I(t,e,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(I(t,e,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(I(t,e,"decision",r,{confidence:.9})),s}function qn(t,e){if(e.length===0)return[];let n=[],r=new Set;function s(i){r.has(i.id)||(r.add(i.id),n.push(i))}for(let i of e){if(i.type==="decision"){let c=[];J(i.data,c);for(let u of c)s(I(t,i,"decision",u,{confidence:1}))}if(i.type==="todo"){let c=[];J(i.data,c);for(let u of c)s(I(t,i,"task",u,{status:Ne(u),confidence:1}))}if(["file_write","file_edit"].includes(i.type))for(let c of["filePath","path","file"]){let u=i.data[c];typeof u=="string"&&u&&s(I(t,i,"file",u,{confidence:1}))}if(i.type==="test"){let c=[];J(i.data,c);for(let u of c)s(I(t,i,"test",u,{confidence:1}))}let a=[];J(i.data,a);for(let c of a)for(let u of c.split(/\n+/u))for(let p of Ti(t,i,u))s(p)}let o=e[e.length-1];return s(I(t,o,"session",`${t.agent}:${t.nativeSessionId}`,{key:t.sessionKey,confidence:1})),n}function Jn(t){return String(t).padStart(12,"0")}var _e=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(u=>u.sequence)),s=Math.max(...n.map(u=>u.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:r,lastSequence:s,observations:n},i=JSON.stringify(o,null,2)+`
42
- `,a=w(n.map(u=>u.id).sort().join("|")).slice(0,16),c=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${Jn(r)}-${Jn(s)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,i,"application/json"),c}};import{join as Hn}from"node:path";import{mkdirSync as Oi}from"node:fs";function Ri(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function G(t,e=20){let n=[],r=new Set;for(let s of t.slice().reverse()){let o=Ri(s);if(!(!o||r.has(o))&&(r.add(o),n.push(s),n.length>=e))break}return n.reverse()}function Ni(t){return t.kind==="phase"?/^Phase\s+\d+$/iu.test(t.text):t.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(t.text):!1}function Gn(t,e){let n=e.status??t?.status??"pending",r=n;t&&(t.status==="completed"&&n!=="completed"?r="completed":n==="pending"&&(t.status==="in_progress"||t.status==="blocked")&&(r=t.status));let s=t&&Ni(e)?t.title:e.text;return{id:t?.id??w(e.key).slice(0,24),title:s,status:r,order:e.order??t?.order,confidence:Math.max(e.confidence,t?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function _i(t,e){let n=`projects/${t.id}/work/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await e.getText(o.key);if(i)try{let a=JSON.parse(i);a.version===1&&Array.isArray(a.observations)&&s.push(a)}catch{}}return s}async function $e(t,e){let r=(await _i(t,e)).flatMap(S=>S.observations).sort((S,j)=>{let de=S.occurredAt.localeCompare(j.occurredAt);if(de!==0)return de;let bt=S.sequence-j.sequence;return bt!==0?bt:S.id.localeCompare(j.id)}),s=new Map,o=new Map,i,a,c,u=[],p=[],l=[],m=[],d=[],f=[];for(let S of r)switch(S.kind){case"goal":i=S.text;break;case"plan":a=S.text;break;case"phase":s.set(S.key,Gn(s.get(S.key),S));break;case"task":o.set(S.key,Gn(o.get(S.key),S));break;case"decision":u.push(S.text);break;case"blocker":p.push(S.text);break;case"warning":l.push(S.text);break;case"next_action":m.push(S.text);break;case"file":d.push(S.text);break;case"test":f.push(S.text);break;case"session":c={agent:S.agent,nativeSessionId:S.nativeSessionId,sessionKey:S.sessionKey,updatedAt:S.occurredAt};break}let h=Array.from(s.values()).sort((S,j)=>(S.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),y=Array.from(o.values()).sort((S,j)=>(S.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),g=h.find(S=>S.status==="in_progress")??h.find(S=>S.status==="blocked")??h.find(S=>S.status==="pending"),v=y.find(S=>S.status==="in_progress")??y.find(S=>S.status==="blocked")??y.find(S=>S.status==="pending"),A=G([...m,...v?[v.title]:[],...!v&&g?[g.title]:[],...y.filter(S=>S.status==="pending").slice(0,5).map(S=>S.title)],8),O=G([...p,...h.filter(S=>S.status==="blocked").map(S=>S.title),...y.filter(S=>S.status==="blocked").map(S=>S.title)],20),C={version:1,projectId:t.id,projectName:t.name,goal:i,plan:a,phases:h,tasks:y,decisions:G(u,20),blockers:O,warnings:G(l,20),nextActions:A,filesTouched:G(d,30),tests:G(f,20),currentPhase:g,currentTask:v,progress:{phasesTotal:h.length,phasesCompleted:h.filter(S=>S.status==="completed").length,tasksTotal:y.length,tasksCompleted:y.filter(S=>S.status==="completed").length,blocked:h.filter(S=>S.status==="blocked").length+y.filter(S=>S.status==="blocked").length},lastSession:c,updatedAt:r.length?r[r.length-1].occurredAt:new Date().toISOString()},_=Hn(t.rootPath,".toolnet","work");return Oi(_,{recursive:!0}),E(Hn(_,"current.json"),C),await e.put(`projects/${t.id}/work/current.json`,JSON.stringify(C,null,2)+`
43
- `,"application/json"),C}async function Ke(t,e){let n=await e.getText(`projects/${t.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function Fi(t,e){if(!Ki(t))return{events:[],nextOffset:e};let n=Wi(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=Li(t,"r");try{Di(i,o,0,s,r)}finally{$i(i)}let a=o.toString("utf8"),c=a.lastIndexOf(`
44
- `);if(c<0)return{events:[],nextOffset:r};let u=a.slice(0,c+1);return{events:u.split(`
45
- `).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(u,"utf8")}}var Le=class{constructor(e){this.options=e;this.journal=new _e(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.continuity.offset"]??0),r=Fi(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=qn(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await $e(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.continuity.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{closeSync as Yi,existsSync as Xi,openSync as Qi,readSync as Zi,statSync as ea}from"node:fs";var zi=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function U(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function ft(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))ft(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(zi.has(r)||["data","payload","parts","messages"].includes(r))&&ft(s,e,n+1)}}function M(t,e,n,r,s,o=.95){let i=U(r);return{version:1,id:w([t.projectId,n,s.type,s.key??"",i.toLowerCase(),e.id].join("|")).slice(0,32),projectId:t.projectId,kind:n,value:i,scope:s.type,scopeKey:s.key,scopeOrder:s.order,confidence:o,evidence:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId,sequence:e.sequence,occurredAt:e.timestamp}}}function N(t,e){let n=t.toLowerCase();for(let r of e){let s=r.toLowerCase();if(n.startsWith(`${s}:`)||n.startsWith(`${s} -`)||n.startsWith(`${s} \u2014`))return U(t.slice(r.length+1))}return null}function Bi(t){let e=t.trimStart();return e.startsWith("- ")||e.startsWith("* ")||/^\d+[.)]\s+/u.test(e)}function Vi(t){return U(t.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function Un(t,e){let n=[],r=new Set;function s(o){!o.value||o.value.length<3||r.has(o.id)||(r.add(o.id),n.push(o))}for(let o of e){let i=[];ft(o.data,i);for(let a of i){let c={type:"project"},u=null;for(let p of a.split(/\r?\n/u)){let l=U(p);if(!l){u=null;continue}let m=l.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(m){let j=Number(m[1]);c={type:"phase",key:`phase:${j}`,order:j,title:U(m[2]??"")},u=null;continue}let d=l.match(/^(?:todo|task|việc)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(d){let j=Number(d[1]);c={type:"task",key:`task:${j}`,order:j,title:U(d[2]??"")},u=null;continue}let f=N(l,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(f){s(M(t,o,"mission",f,{type:"project"},.99)),u=null;continue}let h=N(l,["current objective","active objective","m\u1EE5c ti\xEAu hi\u1EC7n t\u1EA1i","objective","m\u1EE5c ti\xEAu","m\u1EE5c \u0111\xEDch"]);if(h){s(M(t,o,c.type==="phase"?"phase_objective":"objective",h,c,.98)),u=null;continue}let y=N(l,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(y){s(M(t,o,c.type==="phase"?"phase_why":"why",y,c,.98)),u=null;continue}let g=N(l,["desired outcome","final outcome","k\u1EBFt qu\u1EA3 cu\u1ED1i","k\u1EBFt qu\u1EA3 mong mu\u1ED1n","m\u1EE5c ti\xEAu cu\u1ED1i"]);if(g){s(M(t,o,"desired_outcome",g,{type:"project"},.98)),u=null;continue}let v=N(l,["plan rationale","approach rationale","why this approach","t\u1EA1i sao ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn ki\u1EBFn tr\xFAc"]);if(v){s(M(t,o,"plan_rationale",v,{type:"project"},.98)),u=null;continue}let A=N(l,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(A){s(M(t,o,"phase_deliverable",A,c,.97)),u=null;continue}let O=N(l,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if(O){s(M(t,o,"acceptance_criterion",O,c,.98)),u="acceptance_criterion";continue}let C=N(l,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(C){s(M(t,o,"dependency",C,c,.97)),u="dependency";continue}let _=N(l,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(_){s(M(t,o,"open_question",_,c,.95)),u="open_question";continue}let S=N(l,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(S){s(M(t,o,"constraint",S,c,.97)),u="constraint";continue}if(/^(?:acceptance criteria|definition of done|done khi|tiêu chí hoàn thành)\s*:?\s*$/iu.test(l)){u="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(l)){u="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(l)){u="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(l)){u="constraint";continue}if(u&&Bi(p)){s(M(t,o,u,Vi(p),c,.96));continue}u=null}}}return n}function Yn(t){return String(t).padStart(12,"0")}var De=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(c=>c.evidence.sequence)),s=Math.max(...n.map(c=>c.evidence.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,firstSequence:r,lastSequence:s,createdAt:new Date().toISOString(),observations:n},i=w(n.map(c=>c.id).sort().join("|")).slice(0,16),a=[`projects/${e.projectId}`,"work","semantic","observations",e.agent,e.nativeSessionId,`${Yn(r)}-${Yn(s)}-${i}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,JSON.stringify(o,null,2)+`
46
- `,"application/json"),a}};import{mkdirSync as qi}from"node:fs";import{join as Xn}from"node:path";function Ji(t){return{value:t.value,confidence:t.confidence,evidence:t.evidence}}function Hi(t,e){if(!e)return!0;let n=t.evidence.occurredAt.localeCompare(e.evidence.occurredAt);return n!==0?n>0:t.evidence.sessionKey===e.evidence.sessionKey?t.evidence.sequence>=e.evidence.sequence:t.confidence>=e.confidence}function L(t,e){return Hi(e,t)?e:t}function D(t,e=30){let n=new Set,r=[];for(let s of t){let o=s.value.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim();!o||n.has(o)||(n.add(o),r.push(s))}return r.slice(-e)}async function Gi(t,e){let n=`projects/${t.id}/work/semantic/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await e.getText(o.key);if(i)try{let a=JSON.parse(i);a.version===1&&Array.isArray(a.observations)&&s.push(a)}catch{}}return s}function Ui(t){return{key:t.scopeKey??`phase:${t.scopeOrder??0}`,order:t.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function Qn(t,e){let r=(await Gi(t,e)).flatMap(h=>h.observations).sort((h,y)=>{let g=h.evidence.occurredAt.localeCompare(y.evidence.occurredAt);return g!==0?g:h.evidence.sessionKey===y.evidence.sessionKey?h.evidence.sequence-y.evidence.sequence:h.id.localeCompare(y.id)}),s,o,i,a,c,u=new Map,p=[],l=[],m=[];for(let h of r){let y=Ji(h);if(h.scope==="phase"&&h.scopeKey){let g=u.get(h.scopeKey)??Ui(h);switch(h.kind){case"phase_objective":g.objective=L(g.objective,y);break;case"phase_why":g.why=L(g.why,y);break;case"phase_deliverable":g.deliverable=L(g.deliverable,y);break;case"acceptance_criterion":g.acceptanceCriteria.push(y);break;case"dependency":g.dependencies.push(y);break;case"open_question":g.openQuestions.push(y);break;case"constraint":g.constraints.push(y);break;case"note":g.notes.push(y);break}u.set(g.key,g);continue}switch(h.kind){case"mission":s=L(s,y);break;case"objective":o=L(o,y);break;case"why":i=L(i,y);break;case"desired_outcome":a=L(a,y);break;case"plan_rationale":c=L(c,y);break;case"open_question":p.push(y);break;case"constraint":l.push(y);break;case"note":m.push(y);break}}for(let h of u.values())h.acceptanceCriteria=D(h.acceptanceCriteria,20),h.dependencies=D(h.dependencies,15),h.openQuestions=D(h.openQuestions,15),h.constraints=D(h.constraints,15),h.notes=D(h.notes,20);let d={version:1,projectId:t.id,projectName:t.name,mission:s,activeObjective:o,why:i,desiredOutcome:a,planRationale:c,phases:Array.from(u.values()).sort((h,y)=>h.order-y.order),openQuestions:D(p,20),constraints:D(l,20),notes:D(m,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},f=Xn(t.rootPath,".toolnet","work");return qi(f,{recursive:!0}),E(Xn(f,"semantic-current.json"),d),await e.put(`projects/${t.id}/work/semantic/current.json`,JSON.stringify(d,null,2)+`
47
- `,"application/json"),d}async function Zn(t,e){let n=await e.getText(`projects/${t.id}/work/semantic/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function ta(t,e){if(!Xi(t))return{events:[],nextOffset:e};let n=ea(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=Buffer.alloc(n-r),o=Qi(t,"r");try{Zi(o,s,0,s.length,r)}finally{Yi(o)}let i=s.toString("utf8"),a=i.lastIndexOf(`
48
- `);if(a<0)return{events:[],nextOffset:r};let c=i.slice(0,a+1);return{events:c.split(`
49
- `).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var We=class{constructor(e){this.options=e;this.journal=new De(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.semantic.offset"]??0),r=ta(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=Un(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await Qn(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.semantic.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{mkdirSync as ma}from"node:fs";import{join as gt}from"node:path";import{existsSync as nr,mkdirSync as na,readFileSync as ra,statSync as er,writeFileSync as sa}from"node:fs";import{dirname as oa,join as ia}from"node:path";var tr=64*1024,aa=`# ToolNet Project Operating Manual
11
+ `,d=Oe(this.eventsFile,"a",384);try{er(d,i,null,"utf8"),Qn(d)}finally{Ee(d)}let c=o[o.length-1],a="active";c.type==="session_end"||c.type==="session_idle"?a="idle":c.type==="error"&&(a="error");let p=Array.from(r).slice(-rr);return this.saveStateUnsafe({...n,status:a,updatedAt:c.timestamp,lastSequence:c.sequence,recentEventIds:p}),o})}readPending(){return this.withLock(()=>{let e=this.loadStateUnsafe();if(!Gn(this.eventsFile))return{events:[],startOffset:e.remoteByteOffset,endOffset:e.remoteByteOffset};let n=ot(this.eventsFile).size,r=Math.min(e.remoteByteOffset,n);if(n<=r)return{events:[],startOffset:r,endOffset:n};let s=n-r,o=Buffer.alloc(s),i=Oe(this.eventsFile,"r");try{Zn(i,o,0,s,r)}finally{Ee(i)}return{events:o.toString("utf8").split(`
12
+ `).filter(Boolean).map(a=>JSON.parse(a)),startOffset:r,endOffset:n}})}markRemote(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,lastRemoteSequence:Math.max(r.lastRemoteSequence,e),remoteByteOffset:Math.max(r.remoteByteOffset,n),updatedAt:new Date().toISOString()})})}setSourceCursor(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,sourceCursors:{...r.sourceCursors,[e]:String(n)},updatedAt:new Date().toISOString()})})}};import{closeSync as br,existsSync as kr,openSync as wr,readSync as jr,statSync as xr}from"node:fs";function it(t,e){let n=e.toLowerCase();return n.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||n.includes("tuy\u1EC7t \u0111\u1ED1i")||n.includes("must not")||n.includes("never ")?"critical":t==="rule"||t==="decision"?"high":t==="todo"||n.includes("error")||n.includes("failed")||n.includes("exception")?"normal":"temporary"}var dt=[/không được/iu,/tuyệt đối/iu,/bắt buộc/iu,/đừng\s+/iu,/must not/iu,/do not/iu,/don't/iu,/\bnever\b/iu],or=[/từ giờ/iu,/về sau/iu,/mỗi lần/iu,/luôn luôn/iu,/\bluôn\b/iu,/quy tắc/iu,/workflow/iu,/\balways\b/iu,/\brequired\b/iu,/\bmust\b/iu,/from now on/iu],ir=[/\bchốt\b/iu,/quyết định/iu,/sẽ dùng/iu,/chọn .+ thay/iu,/đổi sang/iu,/chuyển sang/iu,/\bdecided\b/iu,/\bchosen\b/iu,/we will use/iu,/use .+ instead/iu,/switch(?:ed)? to/iu],ar=[/\btodo\b/iu,/cần làm/iu,/cần thêm/iu,/cần sửa/iu,/cần kiểm tra/iu,/tiếp theo/iu,/bước tiếp theo/iu,/còn phải/iu,/còn cần/iu,/next step/iu,/\bneed to\b/iu,/\bremaining\b/iu,/follow[- ]?up/iu],cr=[/đã sửa/iu,/đã fix/iu,/đã khắc phục/iu,/đã xử lý/iu,/hoàn tất/iu,/hoàn thành/iu,/\bfixed\b/iu,/\bresolved\b/iu,/\bimplemented\b/iu,/\bcompleted\b/iu,/\bpasses?\b/iu],at=[/kiến trúc/iu,/pipeline/iu,/adapter/iu,/schema/iu,/runtime/iu,/namespace/iu,/storage/iu,/lưu trữ/iu,/workflow/iu,/session core/iu,/memory engine/iu,/retrieval/iu],ur=[/\bdùng\b/iu,/\btách\b/iu,/\bthay\b/iu,/\bchuyển\b/iu,/\blưu\b/iu,/\bmap\b/iu,/\buse\b/iu,/\bsplit\b/iu,/\bstore\b/iu,/\breplace\b/iu,/\bmove\b/iu],dr=[/đường dẫn/iu,/\bpath\b/iu,/\bport\b/iu,/\bendpoint\b/iu,/\bdomain\b/iu,/\bbucket\b/iu,/\brepository\b/iu,/\brepo\b/iu,/\bbranch\b/iu,/\/[A-Za-z0-9._/-]{4,}/u],lr=[/\blà\b/iu,/\bở\b/iu,/\bdùng\b/iu,/\bnằm\b/iu,/\bis\b/iu,/\buse\b/iu,/located/iu,/runs on/iu],ct=new Set(["content","text","message","prompt","summary","description","reason","title","last_assistant_message","lastAssistantMessage","input_messages","inputMessages"]),pr=new Set(["payload","data","content","message","messages","parts","summary"]);function E(t,e){return e.some(n=>n.test(t))}function lt(t){return t.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function fr(t){return lt(t).toLowerCase().replace(/[^\p{L}\p{N}:/._-]+/gu," ").replace(/\s+/g," ").trim()}function mr(t){return!(t.length<12||t.length>1e3||(t.match(new RegExp("\\p{L}","gu"))??[]).length<6||/^(?:https?:\/\/\S+|[A-Za-z0-9+/=]{80,})$/u.test(t))}function Ce(t,e,n,r=0){if(!(r>6)){if(typeof t=="string"){(!e||ct.has(e))&&n.push(t);return}if(Array.isArray(t)){for(let s of t.slice(0,50))Ce(s,e,n,r+1);return}if(!(!t||typeof t!="object"))for(let[s,o]of Object.entries(t))(ct.has(s)||pr.has(s))&&Ce(o,s,n,r+1)}}function gr(t){let e=[];Ce(t.data,void 0,e);let n=[],r=new Set;for(let s of e)for(let o of s.split(/\n+|(?<=[.!?])\s+/u)){let i=lt(o);if(mr(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function ut(t){return(t.role??(typeof t.data.role=="string"?t.data.role:"")).toLowerCase()}function hr(t,e,n){if(n.type==="decision")return{kind:"decision",confidence:1};if(n.type==="todo")return{kind:"todo",confidence:1};let r=e==="user"||n.type==="user_prompt",s=e==="assistant"||n.type==="assistant_message";return r&&E(t,dt)?{kind:"rule",confidence:.98}:r&&E(t,or)?{kind:"rule",confidence:.92}:E(t,ir)?{kind:E(t,at)?"architecture":"decision",confidence:r?.93:.86}:r&&E(t,ar)?{kind:"todo",confidence:.87}:E(t,at)&&E(t,ur)?{kind:"architecture",confidence:r?.88:.82}:s&&E(t,cr)?{kind:"fix",confidence:.8}:r&&E(t,dr)&&E(t,lr)?{kind:"context",confidence:.79}:null}function yr(t){switch(t){case"rule":return"rule";case"decision":case"architecture":return"decision";case"todo":return"todo";case"fix":case"context":return"code"}}function Sr(t,e,n){return t==="rule"&&E(n,dt)?"critical":t==="architecture"||t==="decision"||t==="rule"?"high":t==="fix"||t==="context"?"normal":it(e,n)}function pt(t,e){let n=[],r=new Set,s=new Map;for(let o of e){let i=typeof o.data.messageId=="string"?o.data.messageId:void 0,d=ut(o);i&&d&&s.set(i,d)}for(let o of e){let i=ut(o),d=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&d&&(i=s.get(d)??"");for(let c of gr(o)){let a=hr(c,i,o);if(!a||a.confidence<.75)continue;let p=yr(a.kind),u=fr(c),m=v([t.projectId,a.kind,u].join("|"));if(r.has(m))continue;r.add(m);let l=o.provenance.sourcePath?[o.provenance.sourcePath]:[],S=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:m,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,kind:a.kind,type:p,content:c,confidence:a.confidence,importance:Sr(a.kind,p,c),tags:[p],provenance:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventIds:[o.id],sourceEventIds:S,sourcePaths:l,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}function ft(t){return String(t).padStart(12,"0")}function vr(t){return t.remotePrefix.replace("/sessions/","/memory/learned/")}var re=class{constructor(e){this.storage=e}storage;async write(e,n,r){if(r.length===0||n.length===0)return null;let s=Math.min(...n.map(p=>p.sequence)),o=Math.max(...n.map(p=>p.sequence)),i={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,candidateCount:r.length,candidates:r},d=JSON.stringify(i,null,2)+`
13
+ `,c=v(r.map(p=>p.fingerprint).sort().join("|")).slice(0,16),a=[vr(e),"batches",`${ft(s)}-${ft(o)}-${c}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,d,"application/json"),a}};function Ir(t,e){if(!kr(t))return{events:[],nextOffset:e};let n=xr(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=wr(t,"r");try{jr(i,o,0,s,r)}finally{br(i)}let d=o.toString("utf8"),c=d.lastIndexOf(`
14
+ `);if(c<0)return{events:[],nextOffset:r};let a=d.slice(0,c+1);return{events:a.split(`
15
+ `).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var se=class{constructor(e){this.options=e;this.journal=new re(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["memory.learner.offset"]??0),r=Number.isFinite(n)?n:0,s=Ir(this.options.wal.eventsFile,r);if(s.events.length===0)return{scannedEvents:0,candidates:0,journalWritten:!1,nextOffset:s.nextOffset};let o=pt(this.options.identity,s.events),i=!1;return o.length>0&&(i=!!await this.journal.write(this.options.identity,s.events,o)),this.options.wal.setSourceCursor("memory.learner.offset",s.nextOffset),{scannedEvents:s.events.length,candidates:o.length,journalWritten:i,nextOffset:s.nextOffset}}};import{closeSync as Mr,existsSync as Ar,openSync as Nr,readSync as _r,statSync as $r}from"node:fs";var Er=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function D(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function gt(t){return D(t).toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function L(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))L(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Er.has(r)||["data","payload","parts","messages"].includes(r))&&L(s,e,n+1)}}function oe(t){return/\b(cancelled|canceled)\b|đã hủy|bỏ qua/iu.test(t)?"cancelled":/\b(blocked|blocker)\b|đang vướng|bị vướng|đang kẹt|chưa thể/iu.test(t)?"blocked":/\b(completed|complete|done|finished|passed)\b|hoàn thành|hoàn tất|đã xong|đã làm xong|\bxong\b/iu.test(t)?"completed":/\bin[\s_-]*progress\b|working on|đang làm|đang thực hiện|đang xử lý|đang triển khai/iu.test(t)?"in_progress":"pending"}function mt(t){let e=D(t);return/^(?:đang\s+làm|đang\s+thực\s+hiện|đang\s+xử\s+lý|đang\s+triển\s+khai|hoàn\s+thành|hoàn\s+tất|đã\s+xong|đã\s+làm\s+xong|xong|pending|in[\s_-]*progress|completed|complete|done|finished|blocked|cancelled|canceled)[.!]*$/iu.test(e)}function j(t,e,n,r,s={}){let o=D(r),i=s.key??gt(o);return{version:1,id:v([t.projectId,n,i,e.id,o,s.status??"",s.order??""].join("|")).slice(0,32),projectId:t.projectId,kind:n,key:i,text:o,status:s.status,order:s.order,confidence:s.confidence??.85,occurredAt:e.timestamp,sequence:e.sequence,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId}}function Or(t,e,n){let r=D(n);if(r.length<5||r.length>1200)return[];let s=[],o=/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r),i=r.match(/^(?:mục tiêu|goal|objective)\s*(?::|-)\s*(.+)$/iu);i?.[1]&&s.push(j(t,e,"goal",i[1],{confidence:.97}));let d=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);d?.[1]&&s.push(j(t,e,"plan",d[1],{confidence:.95}));let c=/\b(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?([^.;\n]{0,220})/giu,a;for(;!o&&(a=c.exec(r));){let m=Number(a[1]),l=D(a[2]??""),S=l&&!mt(l)?`Phase ${m} - ${l}`:`Phase ${m}`;s.push(j(t,e,"phase",S,{key:`phase:${m}`,order:m,status:oe(r),confidence:.93}))}let p=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);p?.[2]&&s.push(j(t,e,"task",p[2],{status:p[1].trim()?"completed":oe(p[2]),confidence:.96}));let u=r.match(/^(?:todo|task|việc)\s*(\d+)?(?:\s*[:.\-–—]\s*|\s+)(.+)$/iu);if(u?.[2]){let m=u[1]?Number(u[1]):void 0,l=D(u[2]),S=mt(l);s.push(j(t,e,"task",S&&m!==void 0?`TODO ${m}`:l,{key:m!==void 0?`task:${m}`:gt(l),order:m,status:oe(r),confidence:.93}))}if(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r)){let m=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");m&&s.push(j(t,e,"next_action",m,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(j(t,e,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(j(t,e,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(j(t,e,"decision",r,{confidence:.9})),s}function ht(t,e){if(e.length===0)return[];let n=[],r=new Set;function s(i){r.has(i.id)||(r.add(i.id),n.push(i))}for(let i of e){if(i.type==="decision"){let c=[];L(i.data,c);for(let a of c)s(j(t,i,"decision",a,{confidence:1}))}if(i.type==="todo"){let c=[];L(i.data,c);for(let a of c)s(j(t,i,"task",a,{status:oe(a),confidence:1}))}if(["file_write","file_edit"].includes(i.type))for(let c of["filePath","path","file"]){let a=i.data[c];typeof a=="string"&&a&&s(j(t,i,"file",a,{confidence:1}))}if(i.type==="test"){let c=[];L(i.data,c);for(let a of c)s(j(t,i,"test",a,{confidence:1}))}let d=[];L(i.data,d);for(let c of d)for(let a of c.split(/\n+/u))for(let p of Or(t,i,a))s(p)}let o=e[e.length-1];return s(j(t,o,"session",`${t.agent}:${t.nativeSessionId}`,{key:t.sessionKey,confidence:1})),n}function yt(t){return String(t).padStart(12,"0")}var ie=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(a=>a.sequence)),s=Math.max(...n.map(a=>a.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:r,lastSequence:s,observations:n},i=JSON.stringify(o,null,2)+`
16
+ `,d=v(n.map(a=>a.id).sort().join("|")).slice(0,16),c=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${yt(r)}-${yt(s)}-${d}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,i,"application/json"),c}};import{join as St}from"node:path";import{mkdirSync as Pr}from"node:fs";function Cr(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function F(t,e=20){let n=[],r=new Set;for(let s of t.slice().reverse()){let o=Cr(s);if(!(!o||r.has(o))&&(r.add(o),n.push(s),n.length>=e))break}return n.reverse()}function Tr(t){return t.kind==="phase"?/^Phase\s+\d+$/iu.test(t.text):t.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(t.text):!1}function vt(t,e){let n=e.status??t?.status??"pending",r=n;t&&(t.status==="completed"&&n!=="completed"?r="completed":n==="pending"&&(t.status==="in_progress"||t.status==="blocked")&&(r=t.status));let s=t&&Tr(e)?t.title:e.text;return{id:t?.id??v(e.key).slice(0,24),title:s,status:r,order:e.order??t?.order,confidence:Math.max(e.confidence,t?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function Rr(t,e){let n=`projects/${t.id}/work/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,d)=>i.key.localeCompare(d.key))){let i=await e.getText(o.key);if(i)try{let d=JSON.parse(i);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}async function ae(t,e){let r=(await Rr(t,e)).flatMap(f=>f.observations).sort((f,x)=>{let Fe=f.occurredAt.localeCompare(x.occurredAt);if(Fe!==0)return Fe;let Ke=f.sequence-x.sequence;return Ke!==0?Ke:f.id.localeCompare(x.id)}),s=new Map,o=new Map,i,d,c,a=[],p=[],u=[],m=[],l=[],S=[];for(let f of r)switch(f.kind){case"goal":i=f.text;break;case"plan":d=f.text;break;case"phase":s.set(f.key,vt(s.get(f.key),f));break;case"task":o.set(f.key,vt(o.get(f.key),f));break;case"decision":a.push(f.text);break;case"blocker":p.push(f.text);break;case"warning":u.push(f.text);break;case"next_action":m.push(f.text);break;case"file":l.push(f.text);break;case"test":S.push(f.text);break;case"session":c={agent:f.agent,nativeSessionId:f.nativeSessionId,sessionKey:f.sessionKey,updatedAt:f.occurredAt};break}let y=Array.from(s.values()).sort((f,x)=>(f.order??Number.MAX_SAFE_INTEGER)-(x.order??Number.MAX_SAFE_INTEGER)),g=Array.from(o.values()).sort((f,x)=>(f.order??Number.MAX_SAFE_INTEGER)-(x.order??Number.MAX_SAFE_INTEGER)),h=y.find(f=>f.status==="in_progress")??y.find(f=>f.status==="blocked")??y.find(f=>f.status==="pending"),w=g.find(f=>f.status==="in_progress")??g.find(f=>f.status==="blocked")??g.find(f=>f.status==="pending"),C=F([...m,...w?[w.title]:[],...!w&&h?[h.title]:[],...g.filter(f=>f.status==="pending").slice(0,5).map(f=>f.title)],8),$=F([...p,...y.filter(f=>f.status==="blocked").map(f=>f.title),...g.filter(f=>f.status==="blocked").map(f=>f.title)],20),T={version:1,projectId:t.id,projectName:t.name,goal:i,plan:d,phases:y,tasks:g,decisions:F(a,20),blockers:$,warnings:F(u,20),nextActions:C,filesTouched:F(l,30),tests:F(S,20),currentPhase:h,currentTask:w,progress:{phasesTotal:y.length,phasesCompleted:y.filter(f=>f.status==="completed").length,tasksTotal:g.length,tasksCompleted:g.filter(f=>f.status==="completed").length,blocked:y.filter(f=>f.status==="blocked").length+g.filter(f=>f.status==="blocked").length},lastSession:c,updatedAt:r.length?r[r.length-1].occurredAt:new Date().toISOString()},A=St(t.rootPath,".toolnet","work");return Pr(A,{recursive:!0}),I(St(A,"current.json"),T),await e.put(`projects/${t.id}/work/current.json`,JSON.stringify(T,null,2)+`
17
+ `,"application/json"),T}async function ce(t,e){let n=await e.getText(`projects/${t.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function Lr(t,e){if(!Ar(t))return{events:[],nextOffset:e};let n=$r(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=Nr(t,"r");try{_r(i,o,0,s,r)}finally{Mr(i)}let d=o.toString("utf8"),c=d.lastIndexOf(`
18
+ `);if(c<0)return{events:[],nextOffset:r};let a=d.slice(0,c+1);return{events:a.split(`
19
+ `).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var ue=class{constructor(e){this.options=e;this.journal=new ie(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.continuity.offset"]??0),r=Lr(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=ht(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await ae(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.continuity.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{closeSync as Vr,existsSync as Ur,openSync as Hr,readSync as Yr,statSync as Gr}from"node:fs";var Dr=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function K(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function Te(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))Te(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Dr.has(r)||["data","payload","parts","messages"].includes(r))&&Te(s,e,n+1)}}function O(t,e,n,r,s,o=.95){let i=K(r);return{version:1,id:v([t.projectId,n,s.type,s.key??"",i.toLowerCase(),e.id].join("|")).slice(0,32),projectId:t.projectId,kind:n,value:i,scope:s.type,scopeKey:s.key,scopeOrder:s.order,confidence:o,evidence:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId,sequence:e.sequence,occurredAt:e.timestamp}}}function P(t,e){let n=t.toLowerCase();for(let r of e){let s=r.toLowerCase();if(n.startsWith(`${s}:`)||n.startsWith(`${s} -`)||n.startsWith(`${s} \u2014`))return K(t.slice(r.length+1))}return null}function Fr(t){let e=t.trimStart();return e.startsWith("- ")||e.startsWith("* ")||/^\d+[.)]\s+/u.test(e)}function Kr(t){return K(t.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function bt(t,e){let n=[],r=new Set;function s(o){!o.value||o.value.length<3||r.has(o.id)||(r.add(o.id),n.push(o))}for(let o of e){let i=[];Te(o.data,i);for(let d of i){let c={type:"project"},a=null;for(let p of d.split(/\r?\n/u)){let u=K(p);if(!u){a=null;continue}let m=u.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(m){let x=Number(m[1]);c={type:"phase",key:`phase:${x}`,order:x,title:K(m[2]??"")},a=null;continue}let l=u.match(/^(?:todo|task|việc)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(l){let x=Number(l[1]);c={type:"task",key:`task:${x}`,order:x,title:K(l[2]??"")},a=null;continue}let S=P(u,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(S){s(O(t,o,"mission",S,{type:"project"},.99)),a=null;continue}let y=P(u,["current objective","active objective","m\u1EE5c ti\xEAu hi\u1EC7n t\u1EA1i","objective","m\u1EE5c ti\xEAu","m\u1EE5c \u0111\xEDch"]);if(y){s(O(t,o,c.type==="phase"?"phase_objective":"objective",y,c,.98)),a=null;continue}let g=P(u,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(g){s(O(t,o,c.type==="phase"?"phase_why":"why",g,c,.98)),a=null;continue}let h=P(u,["desired outcome","final outcome","k\u1EBFt qu\u1EA3 cu\u1ED1i","k\u1EBFt qu\u1EA3 mong mu\u1ED1n","m\u1EE5c ti\xEAu cu\u1ED1i"]);if(h){s(O(t,o,"desired_outcome",h,{type:"project"},.98)),a=null;continue}let w=P(u,["plan rationale","approach rationale","why this approach","t\u1EA1i sao ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn ki\u1EBFn tr\xFAc"]);if(w){s(O(t,o,"plan_rationale",w,{type:"project"},.98)),a=null;continue}let C=P(u,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(C){s(O(t,o,"phase_deliverable",C,c,.97)),a=null;continue}let $=P(u,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if($){s(O(t,o,"acceptance_criterion",$,c,.98)),a="acceptance_criterion";continue}let T=P(u,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(T){s(O(t,o,"dependency",T,c,.97)),a="dependency";continue}let A=P(u,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(A){s(O(t,o,"open_question",A,c,.95)),a="open_question";continue}let f=P(u,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(f){s(O(t,o,"constraint",f,c,.97)),a="constraint";continue}if(/^(?:acceptance criteria|definition of done|done khi|tiêu chí hoàn thành)\s*:?\s*$/iu.test(u)){a="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(u)){a="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(u)){a="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(u)){a="constraint";continue}if(a&&Fr(p)){s(O(t,o,a,Kr(p),c,.96));continue}a=null}}}return n}function kt(t){return String(t).padStart(12,"0")}var de=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(c=>c.evidence.sequence)),s=Math.max(...n.map(c=>c.evidence.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,firstSequence:r,lastSequence:s,createdAt:new Date().toISOString(),observations:n},i=v(n.map(c=>c.id).sort().join("|")).slice(0,16),d=[`projects/${e.projectId}`,"work","semantic","observations",e.agent,e.nativeSessionId,`${kt(r)}-${kt(s)}-${i}.json`].join("/");return await this.storage.exists(d)||await this.storage.put(d,JSON.stringify(o,null,2)+`
20
+ `,"application/json"),d}};import{mkdirSync as Wr}from"node:fs";import{join as wt}from"node:path";function Br(t){return{value:t.value,confidence:t.confidence,evidence:t.evidence}}function zr(t,e){if(!e)return!0;let n=t.evidence.occurredAt.localeCompare(e.evidence.occurredAt);return n!==0?n>0:t.evidence.sessionKey===e.evidence.sessionKey?t.evidence.sequence>=e.evidence.sequence:t.confidence>=e.confidence}function R(t,e){return zr(e,t)?e:t}function M(t,e=30){let n=new Set,r=[];for(let s of t){let o=s.value.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim();!o||n.has(o)||(n.add(o),r.push(s))}return r.slice(-e)}async function qr(t,e){let n=`projects/${t.id}/work/semantic/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,d)=>i.key.localeCompare(d.key))){let i=await e.getText(o.key);if(i)try{let d=JSON.parse(i);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}function Jr(t){return{key:t.scopeKey??`phase:${t.scopeOrder??0}`,order:t.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function jt(t,e){let r=(await qr(t,e)).flatMap(y=>y.observations).sort((y,g)=>{let h=y.evidence.occurredAt.localeCompare(g.evidence.occurredAt);return h!==0?h:y.evidence.sessionKey===g.evidence.sessionKey?y.evidence.sequence-g.evidence.sequence:y.id.localeCompare(g.id)}),s,o,i,d,c,a=new Map,p=[],u=[],m=[];for(let y of r){let g=Br(y);if(y.scope==="phase"&&y.scopeKey){let h=a.get(y.scopeKey)??Jr(y);switch(y.kind){case"phase_objective":h.objective=R(h.objective,g);break;case"phase_why":h.why=R(h.why,g);break;case"phase_deliverable":h.deliverable=R(h.deliverable,g);break;case"acceptance_criterion":h.acceptanceCriteria.push(g);break;case"dependency":h.dependencies.push(g);break;case"open_question":h.openQuestions.push(g);break;case"constraint":h.constraints.push(g);break;case"note":h.notes.push(g);break}a.set(h.key,h);continue}switch(y.kind){case"mission":s=R(s,g);break;case"objective":o=R(o,g);break;case"why":i=R(i,g);break;case"desired_outcome":d=R(d,g);break;case"plan_rationale":c=R(c,g);break;case"open_question":p.push(g);break;case"constraint":u.push(g);break;case"note":m.push(g);break}}for(let y of a.values())y.acceptanceCriteria=M(y.acceptanceCriteria,20),y.dependencies=M(y.dependencies,15),y.openQuestions=M(y.openQuestions,15),y.constraints=M(y.constraints,15),y.notes=M(y.notes,20);let l={version:1,projectId:t.id,projectName:t.name,mission:s,activeObjective:o,why:i,desiredOutcome:d,planRationale:c,phases:Array.from(a.values()).sort((y,g)=>y.order-g.order),openQuestions:M(p,20),constraints:M(u,20),notes:M(m,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},S=wt(t.rootPath,".toolnet","work");return Wr(S,{recursive:!0}),I(wt(S,"semantic-current.json"),l),await e.put(`projects/${t.id}/work/semantic/current.json`,JSON.stringify(l,null,2)+`
21
+ `,"application/json"),l}async function xt(t,e){let n=await e.getText(`projects/${t.id}/work/semantic/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function Qr(t,e){if(!Ur(t))return{events:[],nextOffset:e};let n=Gr(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=Buffer.alloc(n-r),o=Hr(t,"r");try{Yr(o,s,0,s.length,r)}finally{Vr(o)}let i=s.toString("utf8"),d=i.lastIndexOf(`
22
+ `);if(d<0)return{events:[],nextOffset:r};let c=i.slice(0,d+1);return{events:c.split(`
23
+ `).filter(Boolean).flatMap(a=>{try{return[JSON.parse(a)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var le=class{constructor(e){this.options=e;this.journal=new de(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.semantic.offset"]??0),r=Qr(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=bt(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await jt(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.semantic.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{mkdirSync as as}from"node:fs";import{join as Re}from"node:path";import{existsSync as Ot,mkdirSync as Xr,readFileSync as Zr,statSync as It,writeFileSync as es}from"node:fs";import{dirname as ts,join as ns}from"node:path";var Et=64*1024,rs=`# ToolNet Project Operating Manual
50
24
 
51
25
  This file contains persistent instructions for AI agents working on this project.
52
26
 
@@ -89,30 +63,37 @@ Things an AI agent should always remember.
89
63
  <!--
90
64
  - [advisory] Prefer small focused files.
91
65
  -->
92
- `;function Fe(t){return ia(t.rootPath,".toolnet","PROJECT.md")}function ca(t){return t.normalize("NFKC").replace(/\s+/g," ").trim()}function ua(t){let e=[],n=new Set,r=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=r.exec(t);){let o=s[1].toLowerCase(),i=ca(s[2]);if(!i)continue;let a=`${o}:${i.toLowerCase()}`;n.has(a)||(n.add(a),e.push({id:w(a).slice(0,24),mode:o,text:i,source:"manual"}))}return e}function la(t){let e=Fe(t);return nr(e)||(na(oa(e),{recursive:!0}),sa(e,aa,{encoding:"utf8",mode:384})),e}function ze(t,e=!1){let n=e?la(t):Fe(t);if(!nr(n))return null;if(er(n).size>tr)throw new Error(`PROJECT.md exceeds ${tr} bytes`);let s=ra(n,"utf8");return{path:n,content:s,digest:w(s),rules:ua(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(er(n).mtimeMs).toISOString()}}function T(t,e){let n=new Set,r=[];for(let s of t){let o=s.replace(/\s+/g," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();if(!n.has(i)&&(n.add(i),r.push(o),r.length>=e))break}return r}function rr(t){if(t)return{id:t.id,title:t.title,status:t.status}}function da(t){let e=t.slice(-10).join(`
93
- `).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(e)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(e)?"passing":"unknown"}function pa(t){return w(JSON.stringify(t))}function sr(t){let{project:e,identity:n,state:r}=t,s=r.filesTouched.at(-1),o=r.phases.filter(g=>g.status==="completed").map(g=>g.title),i=r.tasks.filter(g=>g.status==="completed").map(g=>g.title),a=r.phases.filter(g=>g.status!=="completed"&&g.status!=="cancelled").map(g=>g.title),c=r.tasks.filter(g=>g.status!=="completed"&&g.status!=="cancelled").map(g=>g.title),u=T(r.nextActions,10),p=T([...c,...u],15),l=T(r.tests.slice().reverse(),10),m=T(r.filesTouched.slice().reverse(),20),d={schema:"toolnet.handoff.v2",version:2,project:{id:e.id,name:e.name},source:{agent:n.agent,nativeSessionId:n.nativeSessionId,sessionKey:n.sessionKey,sequence:t.sequence,reason:t.reason},capturedAt:t.capturedAt??new Date().toISOString(),goal:r.goal,current:{phase:rr(r.currentPhase),task:rr(r.currentTask),file:s},completed:{phases:T(o,20),tasks:T(i,30)},remaining:{phases:T(a,20),tasks:T(c,30),todos:p},nextAction:u[0],blockers:T(r.blockers.slice().reverse(),10),decisions:T(r.decisions.slice().reverse(),10),files:{current:s,recent:m},tests:{status:da(r.tests),recent:l},attention:T(t.attention??[],20),progress:r.progress},{capturedAt:f,source:h,...y}=d;return{...d,stateDigest:pa(y)}}function fa(t){return t.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.nextActions.length>0||t.blockers.length>0}var Be=class{constructor(e){this.options=e}options;async capture(e,n){let r=await Ke(this.options.project,this.options.storage);if(r||(r=await $e(this.options.project,this.options.storage)),!fa(r))return null;let s=ze(this.options.project,!1),i=[...s?s.rules.filter(f=>f.mode==="enforce").map(f=>f.text):[],...r.warnings].slice(0,20),a=sr({project:this.options.project,identity:this.options.identity,state:r,reason:e,sequence:n,attention:i}),c=a.stateDigest,u=w([this.options.project.id,this.options.identity.sessionKey,c].join("|")).slice(0,24),p=new Date().toISOString(),l={version:1,id:u,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:p,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:n},goal:r.goal,plan:r.plan,progress:r.progress,currentPhase:r.currentPhase,currentTask:r.currentTask,incompletePhases:r.phases.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),incompleteTasks:r.tasks.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),nextActions:r.nextActions.slice(0,10),blockers:r.blockers.slice(0,10),decisions:r.decisions.slice(-10),warnings:r.warnings.slice(-10),attention:i,filesTouched:r.filesTouched.slice(-20),tests:r.tests.slice(-15),stateDigest:c,continuity:a},m=`projects/${this.options.project.id}/work/handoffs/${u}.json`;await this.options.storage.exists(m)||await this.options.storage.put(m,JSON.stringify(l,null,2)+`
94
- `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(l,null,2)+`
95
- `,"application/json");let d=gt(this.options.project.rootPath,".toolnet","work","handoffs");return ma(d,{recursive:!0}),E(gt(d,`${u}.json`),l),E(gt(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),l),l}};async function or(t,e){let n=await e.getText(`projects/${t.id}/work/handoff-latest.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}var Ve=class{identity;wal;remote;sanitizer=new ee;learner;continuity;semantic;handoff;title;metadata;constructor(e){this.identity=Lt(e.project,e.agent,e.nativeSessionId),this.title=e.title,this.metadata=this.sanitizer.sanitizeValue(e.metadata??{}),this.wal=new ve(this.identity),this.remote=new we(e.storage,e.maxEventsPerChunk??100,e.maxChunkBytes??512*1024),this.learner=new Re({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.continuity=new Le({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.semantic=new We({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.handoff=new Be({project:e.project,storage:e.storage,identity:this.identity})}sanitizeEvent(e){let n=e.provenance?{...e.provenance,metadata:this.sanitizer.sanitizeValue(e.provenance.metadata)}:void 0;return{...e,data:this.sanitizer.sanitizeValue(e.data??{}),provenance:n}}start(e={}){let n=this.wal.loadState();return this.record({type:n.lastSequence===0?"session_start":"session_resume",data:e,provenance:{source:this.identity.agent}})}record(e){return this.wal.append([this.sanitizeEvent(e)])[0]}recordMany(e){return this.wal.append(e.map(n=>this.sanitizeEvent(n)))}setSourceCursor(e,n){this.wal.setSourceCursor(e,n)}async flush(){let e=this.wal.readPending(),n=this.wal.loadState(),r=await this.remote.append(this.identity,e.events,n.sourceCursors,{title:this.title,metadata:this.metadata});if(e.events.length>0){let s=e.events[e.events.length-1];this.wal.markRemote(s.sequence,e.endOffset)}if(process.env.TOOLNET_SESSION_LEARNING!=="0")try{await this.learner.learnNew()}catch{}if(process.env.TOOLNET_WORK_CONTINUITY!=="0")try{await this.continuity.learnNew()}catch{}if(process.env.TOOLNET_SEMANTIC_CONTINUITY!=="0")try{await this.semantic.learnNew()}catch{}if(process.env.TOOLNET_SMART_HANDOFF!=="0"&&e.events.length>0)try{let s=e.events[e.events.length-1],o=["session_idle","session_end","session_compact"].includes(s.type)?s.type:"checkpoint";await this.handoff.capture(o,s.sequence)}catch{}return r}async idle(e={}){return this.record({type:"session_idle",data:e,provenance:{source:this.identity.agent}}),this.flush()}async end(e={}){return this.record({type:"session_end",data:e,provenance:{source:this.identity.agent}}),this.flush()}status(){return this.wal.loadState()}recoverRemote(){return this.remote.recover(this.identity)}};var ga=[/^<SYSTEM MESSAGE>/i,/^<EPHEMERAL MESSAGE>/i,/^<system>/i,/^<ephemeral>/i,/^ManageTask:/i,/^Task \d+ status:/i,/^Task \d+ killed/i,/^Task \d+ loading/i,/^Thought for \d+ tokens/i,/^Prioritizing Tool Usage/i,/^Tool call:/i,/^Tool response:/i,/^npm notice/i,/^npm WARN/i,/^added \d+ packages/i,/^removed \d+ packages/i,/^up to date/i,/^\d+ packages are looking for funding/i,/^run `npm fund` for details/i,/^[\d.]+%/,/^\[={10,}\]/,/^Loading\.\.\./i,/^Processing\.\.\./i,/^bash-\d+\.\d+\$/,/^\$ /,/^\s*$/],ya=[/api[_-]?key[:\s=]+[^\s]+/gi,/token[:\s=]+[^\s]+/gi,/secret[:\s=]+[^\s]+/gi,/password[:\s=]+[^\s]+/gi,/bearer\s+[^\s]+/gi,/authorization:\s*[^\s]+/gi],ha=["decision","decided","rule","convention","architecture","pattern","fixed","resolved","implemented","created","updated","deleted","deployed","blocker","blocked","issue","bug","error","next","todo","action","requirement","must","should","important"];function Sa(t){let e=t.toLowerCase();return ha.some(n=>e.includes(n))}function wa(t){if(!t.trim())return!0;for(let e of ga)if(e.test(t))return!0;return Sa(t),!1}function va(t){let e=t;for(let n of ya)e=e.replace(n,r=>{let s=r.split(/[:\s=]+/);return s.length>1?`${s[0]}: [REDACTED]`:"[REDACTED]"});return e}function yt(t){let e=t.trim();return e?wa(e)?{content:"",filtered:!0,reason:"noise"}:{content:va(e),filtered:!1}:{content:"",filtered:!0,reason:"empty"}}function qe(t){let e={};for(let[n,r]of Object.entries(t))if(typeof r=="string"){let s=yt(r);s.filtered||(e[n]=s.content)}else r&&typeof r=="object"&&!Array.isArray(r)?e[n]=qe(r):Array.isArray(r)?e[n]=r.map(s=>{if(typeof s=="string"){let o=yt(s);return o.filtered?null:o.content}return s&&typeof s=="object"?qe(s):s}).filter(s=>s!==null):e[n]=r;return e}function ir(t){let e=typeof t.type=="string"?t.type.toLowerCase():"";if(e.includes("system")||e.includes("ephemeral")||e==="tool_call"&&!t.result)return!0;if(t.data&&typeof t.data=="object"){let n=t.data,r=typeof n.content=="string"?n.content:"";if(r&&yt(r).filtered)return!0}return!1}function mr(){try{let e=ba("opencode",["db","path"],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:5e3}).trim();if(e)return e}catch{}if(process.env.OPENCODE_DB)return process.env.OPENCODE_DB;let t=process.env.XDG_DATA_HOME??ar(xa(),".local","share");return ar(t,"opencode","opencode.db")}function b(t){return typeof t=="string"?t:""}function V(t){if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="bigint")return Number(t);if(typeof t=="string"){let e=Number(t);if(Number.isFinite(e))return e}return 0}function ht(t){if(t&&typeof t=="object"&&!Buffer.isBuffer(t))return t;if(typeof t!="string")return{};try{let e=JSON.parse(t);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{}}function Y(t){let e=V(t);if(e<=0)return new Date().toISOString();e<1e11&&(e*=1e3);let n=new Date(e);return Number.isNaN(n.getTime())?new Date().toISOString():n.toISOString()}function Je(t,e){if(!e)return!1;let n=cr(t),r=cr(e);if(n===r)return!0;let s=Ca(n,r);return s!==""&&s!==".."&&!s.startsWith(`..${process.platform==="win32"?"\\":"/"}`)&&!ja(s)}function ur(t){if(!t)return{time:-1,id:""};try{let e=JSON.parse(t);return{time:typeof e.time=="number"?e.time:-1,id:typeof e.id=="string"?e.id:""}}catch{return{time:-1,id:""}}}function lr(t){return JSON.stringify(t)}function fr(t){if(!ka(t))throw new Error(`OpenCode database not found: ${t}`);let e=new Ia(t,{readOnly:!0});return e.exec("PRAGMA query_only = ON"),e.exec("PRAGMA busy_timeout = 3000"),e}function Aa(t,e){let n=t.prepare(`
66
+ `;function pe(t){return ns(t.rootPath,".toolnet","PROJECT.md")}function ss(t){return t.normalize("NFKC").replace(/\s+/g," ").trim()}function os(t){let e=[],n=new Set,r=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=r.exec(t);){let o=s[1].toLowerCase(),i=ss(s[2]);if(!i)continue;let d=`${o}:${i.toLowerCase()}`;n.has(d)||(n.add(d),e.push({id:v(d).slice(0,24),mode:o,text:i,source:"manual"}))}return e}function is(t){let e=pe(t);return Ot(e)||(Xr(ts(e),{recursive:!0}),es(e,rs,{encoding:"utf8",mode:384})),e}function fe(t,e=!1){let n=e?is(t):pe(t);if(!Ot(n))return null;if(It(n).size>Et)throw new Error(`PROJECT.md exceeds ${Et} bytes`);let s=Zr(n,"utf8");return{path:n,content:s,digest:v(s),rules:os(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(It(n).mtimeMs).toISOString()}}function cs(t){return{goal:t.goal,plan:t.plan,phases:t.phases.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),tasks:t.tasks.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),decisions:t.decisions,blockers:t.blockers,warnings:t.warnings,nextActions:t.nextActions,filesTouched:t.filesTouched,tests:t.tests}}function us(t){return t.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.nextActions.length>0||t.blockers.length>0}var me=class{constructor(e){this.options=e}options;async capture(e,n){let r=await ce(this.options.project,this.options.storage);if(r||(r=await ae(this.options.project,this.options.storage)),!us(r))return null;let s=fe(this.options.project,!1),o=s?s.rules.filter(m=>m.mode==="enforce").map(m=>m.text):[],i=v(JSON.stringify(cs(r))),d=v([this.options.project.id,this.options.identity.sessionKey,i].join("|")).slice(0,24),c=new Date().toISOString(),a={version:1,id:d,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:c,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:n},goal:r.goal,plan:r.plan,progress:r.progress,currentPhase:r.currentPhase,currentTask:r.currentTask,incompletePhases:r.phases.filter(m=>m.status!=="completed"&&m.status!=="cancelled"),incompleteTasks:r.tasks.filter(m=>m.status!=="completed"&&m.status!=="cancelled"),nextActions:r.nextActions.slice(0,10),blockers:r.blockers.slice(0,10),decisions:r.decisions.slice(-10),warnings:r.warnings.slice(-10),attention:[...o,...r.warnings].slice(0,20),filesTouched:r.filesTouched.slice(-20),tests:r.tests.slice(-15),stateDigest:i},p=`projects/${this.options.project.id}/work/handoffs/${d}.json`;await this.options.storage.exists(p)||await this.options.storage.put(p,JSON.stringify(a,null,2)+`
67
+ `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(a,null,2)+`
68
+ `,"application/json");let u=Re(this.options.project.rootPath,".toolnet","work","handoffs");return as(u,{recursive:!0}),I(Re(u,`${d}.json`),a),I(Re(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),a),a}};async function Pt(t,e){let n=await e.getText(`projects/${t.id}/work/handoff-latest.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}var ge=class{identity;wal;remote;sanitizer=new J;learner;continuity;semantic;handoff;title;metadata;constructor(e){this.identity=nt(e.project,e.agent,e.nativeSessionId),this.title=e.title,this.metadata=this.sanitizer.sanitizeValue(e.metadata??{}),this.wal=new ne(this.identity),this.remote=new te(e.storage,e.maxEventsPerChunk??100,e.maxChunkBytes??512*1024),this.learner=new se({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.continuity=new ue({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.semantic=new le({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.handoff=new me({project:e.project,storage:e.storage,identity:this.identity})}sanitizeEvent(e){let n=e.provenance?{...e.provenance,metadata:this.sanitizer.sanitizeValue(e.provenance.metadata)}:void 0;return{...e,data:this.sanitizer.sanitizeValue(e.data??{}),provenance:n}}start(e={}){let n=this.wal.loadState();return this.record({type:n.lastSequence===0?"session_start":"session_resume",data:e,provenance:{source:this.identity.agent}})}record(e){return this.wal.append([this.sanitizeEvent(e)])[0]}recordMany(e){return this.wal.append(e.map(n=>this.sanitizeEvent(n)))}setSourceCursor(e,n){this.wal.setSourceCursor(e,n)}async flush(){let e=this.wal.readPending(),n=this.wal.loadState(),r=await this.remote.append(this.identity,e.events,n.sourceCursors,{title:this.title,metadata:this.metadata});if(e.events.length>0){let s=e.events[e.events.length-1];this.wal.markRemote(s.sequence,e.endOffset)}if(process.env.TOOLNET_SESSION_LEARNING!=="0")try{await this.learner.learnNew()}catch{}if(process.env.TOOLNET_WORK_CONTINUITY!=="0")try{await this.continuity.learnNew()}catch{}if(process.env.TOOLNET_SEMANTIC_CONTINUITY!=="0")try{await this.semantic.learnNew()}catch{}if(process.env.TOOLNET_SMART_HANDOFF!=="0"&&e.events.length>0)try{let s=e.events[e.events.length-1],o=["session_idle","session_end","session_compact"].includes(s.type)?s.type:"checkpoint";await this.handoff.capture(o,s.sequence)}catch{}return r}async idle(e={}){return this.record({type:"session_idle",data:e,provenance:{source:this.identity.agent}}),this.flush()}async end(e={}){return this.record({type:"session_end",data:e,provenance:{source:this.identity.agent}}),this.flush()}status(){return this.wal.loadState()}recoverRemote(){return this.remote.recover(this.identity)}};var ds=[/^<SYSTEM MESSAGE>/i,/^<EPHEMERAL MESSAGE>/i,/^<system>/i,/^<ephemeral>/i,/^ManageTask:/i,/^Task \d+ status:/i,/^Task \d+ killed/i,/^Task \d+ loading/i,/^Thought for \d+ tokens/i,/^Prioritizing Tool Usage/i,/^Tool call:/i,/^Tool response:/i,/^npm notice/i,/^npm WARN/i,/^added \d+ packages/i,/^removed \d+ packages/i,/^up to date/i,/^\d+ packages are looking for funding/i,/^run `npm fund` for details/i,/^[\d.]+%/,/^\[={10,}\]/,/^Loading\.\.\./i,/^Processing\.\.\./i,/^bash-\d+\.\d+\$/,/^\$ /,/^\s*$/],ls=[/api[_-]?key[:\s=]+[^\s]+/gi,/token[:\s=]+[^\s]+/gi,/secret[:\s=]+[^\s]+/gi,/password[:\s=]+[^\s]+/gi,/bearer\s+[^\s]+/gi,/authorization:\s*[^\s]+/gi],ps=["decision","decided","rule","convention","architecture","pattern","fixed","resolved","implemented","created","updated","deleted","deployed","blocker","blocked","issue","bug","error","next","todo","action","requirement","must","should","important"];function fs(t){let e=t.toLowerCase();return ps.some(n=>e.includes(n))}function ms(t){if(!t.trim())return!0;for(let e of ds)if(e.test(t))return!0;return fs(t),!1}function gs(t){let e=t;for(let n of ls)e=e.replace(n,r=>{let s=r.split(/[:\s=]+/);return s.length>1?`${s[0]}: [REDACTED]`:"[REDACTED]"});return e}function Me(t){let e=t.trim();return e?ms(e)?{content:"",filtered:!0,reason:"noise"}:{content:gs(e),filtered:!1}:{content:"",filtered:!0,reason:"empty"}}function he(t){let e={};for(let[n,r]of Object.entries(t))if(typeof r=="string"){let s=Me(r);s.filtered||(e[n]=s.content)}else r&&typeof r=="object"&&!Array.isArray(r)?e[n]=he(r):Array.isArray(r)?e[n]=r.map(s=>{if(typeof s=="string"){let o=Me(s);return o.filtered?null:o.content}return s&&typeof s=="object"?he(s):s}).filter(s=>s!==null):e[n]=r;return e}function Ct(t){let e=typeof t.type=="string"?t.type.toLowerCase():"";if(e.includes("system")||e.includes("ephemeral")||e==="tool_call"&&!t.result)return!0;if(t.data&&typeof t.data=="object"){let n=t.data,r=typeof n.content=="string"?n.content:"";if(r&&Me(r).filtered)return!0}return!1}function ye(t){return t?Math.ceil(t.length/3.5):0}function Se(t,e){if(!t)return"";if(ye(t)<=e)return t;let r=Math.floor(e*3.5),s=t.slice(0,r),o=s.lastIndexOf("."),i=s.lastIndexOf(`
69
+ `),d=Math.max(o,i);return d>r*.7?s.slice(0,d+1):s}function N(){let t=H(),e=process.env.TOOLNET_SESSION_SAVE||"summary",n=process.env.TOOLNET_RAW_TRANSCRIPT==="on"||e==="archive"||e==="full",r=process.env.TOOLNET_MEMORY_PROMOTION||"conservative",s=parseFloat(process.env.TOOLNET_PROMOTE_MIN_SCORE||"0.65"),o=parseInt(process.env.TOOLNET_SESSION_SUMMARY_MAX_TOKENS||"700",10),i=parseInt(process.env.TOOLNET_DURABLE_MEMORY_MAX_ITEMS_PER_SESSION||"10",10),d=n,c=process.env.TOOLNET_RAW_TRANSCRIPT_REMOTE==="on"||e==="full";return{sessionSave:e,rawTranscript:n,memoryPromotion:r,promoteMinScore:s,sessionSummaryMaxTokens:o,durableMemoryMaxItemsPerSession:i,archiveLocal:d,archiveRemote:c}}function Tt(t){return(t||N()).rawTranscript}function Rt(t){return(t||N()).durableMemoryMaxItemsPerSession}function Mt(t){return(t||N()).sessionSummaryMaxTokens}function At(t){return(t||N()).archiveRemote}function hs(t){return t.replace(/\b[A-Za-z0-9_-]{20,}\b/g,"[REDACTED]").replace(/api[_-]?key[:\s=]+[^\s]+/gi,"api_key=[REDACTED]").replace(/token[:\s=]+[^\s]+/gi,"token=[REDACTED]").replace(/secret[:\s=]+[^\s]+/gi,"secret=[REDACTED]").replace(/password[:\s=]+[^\s]+/gi,"password=[REDACTED]")}function ys(t,e){let n=t.toLowerCase(),r=.5,s=["nh\u1EDB","remember","quy t\u1EAFc","rule","t\u1EEB gi\u1EDD","from now","kh\xF4ng \u0111\u01B0\u1EE3c","must not","lu\xF4n lu\xF4n","always","never","critical","important","blocker","deploy","production","architecture"];for(let i of s)n.includes(i)&&(r+=.15);e==="rule"||e==="architecture"||e==="blocker"?r+=.2:e==="decision"||e==="deploy"?r+=.15:(e==="fix"||e==="next_action")&&(r+=.1),t.length<20?r-=.3:t.length>500&&(r-=.1);let o=[/npm (notice|warn|ERR)/i,/\d+ packages? in \d+/i,/found \d+ vulnerabilities/i,/up to date/i,/added \d+ packages/i,/^(ok|done|success|error|warning)$/i];for(let i of o)i.test(t)&&(r-=.4);return Math.max(0,Math.min(1,r))}function Ss(t,e){let n=[],r=new Set;for(let i of t){let d=i.split(`
70
+ `).filter(c=>c.trim());for(let c of d){let a=c.trim();if(a.length<15)continue;let p=a.toLowerCase().replace(/\s+/g," ");if(r.has(p))continue;r.add(p);let u="decision";/\b(rule|quy tắc|policy|standard|convention)\b/i.test(a)||/\b(always|never|must|should|từ giờ|không được)\b/i.test(a)?u="rule":/\b(fix|fixed|bug|issue|error|lỗi)\b/i.test(a)?u="fix":/\b(blocker|blocked|stuck|cannot|không thể)\b/i.test(a)?u="blocker":/\b(next|todo|action|task|cần làm)\b/i.test(a)?u="next_action":/\b(deploy|release|publish|ship)\b/i.test(a)?u="deploy":/\b(architecture|design|structure|pattern)\b/i.test(a)?u="architecture":/\.(ts|js|py|go|rs|java|cpp|c|h)\b/i.test(a)&&(u="file");let m=ys(a,u);if(m<.3)continue;let l=hs(a);n.push({category:u,text:l,importance:m,sourceSessionId:e})}}let s=N(),o=Rt(s);return n.sort((i,d)=>d.importance-i.importance).slice(0,o)}function vs(t){let e=N(),n=Mt(e),o=t.join(`
71
+
72
+ `).split(`
73
+ `).filter(i=>{let d=i.trim();return d.length>20&&!d.startsWith("npm")&&!d.startsWith("\u2713")&&!d.startsWith("Error:")}).slice(0,20).join(`
74
+ `);return Se(o,n)}function Nt(t,e){let r=(Array.isArray(t)?t:t.split(`
75
+
76
+ `).filter(l=>l.trim())).map(l=>typeof l=="string"?l:JSON.stringify(l)).filter(l=>l.trim()),s=Ss(r,e),o=s.filter(l=>l.category==="decision").map(l=>l.text),i=s.filter(l=>l.category==="rule").map(l=>l.text),d=s.filter(l=>l.category==="file").map(l=>l.text),c=s.filter(l=>l.category==="fix").map(l=>l.text),a=s.filter(l=>l.category==="blocker").map(l=>l.text),p=s.filter(l=>l.category==="next_action").map(l=>l.text),u=s.filter(l=>l.category==="deploy").map(l=>l.text);return{summary:vs(r),decisions:o,projectRules:i,filesChanged:d,bugsFixed:c,commands:u,blockers:a,nextActions:p,durableFacts:s}}function Kt(){return process.env.OPENCODE_DB_PATH??js(ks(),".local","share","opencode","opencode.db")}function k(t){return typeof t=="string"?t:""}function _(t){if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="bigint")return Number(t);if(typeof t=="string"){let e=Number(t);if(Number.isFinite(e))return e}return 0}function Ae(t){if(t&&typeof t=="object"&&!Buffer.isBuffer(t))return t;if(typeof t!="string")return{};try{let e=JSON.parse(t);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{}}function W(t){let e=_(t);if(e<=0)return new Date().toISOString();e<1e11&&(e*=1e3);let n=new Date(e);return Number.isNaN(n.getTime())?new Date().toISOString():n.toISOString()}function ve(t,e){if(!e)return!1;let n=_t(t),r=_t(e);if(n===r)return!0;let s=xs(n,r);return s!==""&&s!==".."&&!s.startsWith(`..${process.platform==="win32"?"\\":"/"}`)&&!ws(s)}function $t(t){if(!t)return{time:-1,id:""};try{let e=JSON.parse(t);return{time:typeof e.time=="number"?e.time:-1,id:typeof e.id=="string"?e.id:""}}catch{return{time:-1,id:""}}}function Lt(t){return JSON.stringify(t)}function Wt(t){if(!bs(t))throw new Error(`OpenCode database not found: ${t}`);let e=new Is(t,{readOnly:!0});return e.exec("PRAGMA query_only = ON"),e.exec("PRAGMA busy_timeout = 3000"),e}function Es(t,e){let n=t.prepare(`
96
77
  SELECT *
97
78
  FROM "session"
98
79
  WHERE id = ?
99
80
  LIMIT 1
100
- `).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function gr(t,e,n){let r=b(e.directory);if(r&&Je(n.rootPath,r))return!0;let s=b(e.project_id);if(s){try{let o=t.prepare(`
81
+ `).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function Bt(t,e,n){let r=k(e.directory);if(r&&ve(n.rootPath,r))return!0;let s=k(e.project_id);if(s){try{let o=t.prepare(`
101
82
  SELECT *
102
83
  FROM "project"
103
84
  WHERE id = ?
104
85
  LIMIT 1
105
- `).get(s);if(o)for(let i of["worktree","directory","path"]){let a=b(o[i]);if(a&&Je(n.rootPath,a))return!0}}catch{}try{if(t.prepare(`
86
+ `).get(s);if(o)for(let i of["worktree","directory","path"]){let d=k(o[i]);if(d&&ve(n.rootPath,d))return!0}}catch{}try{if(t.prepare(`
106
87
  SELECT directory
107
88
  FROM "project_directory"
108
89
  WHERE project_id = ?
109
- `).all(s).some(i=>Je(n.rootPath,b(i.directory))))return!0}catch{}}try{let o=t.prepare(`
90
+ `).all(s).some(i=>ve(n.rootPath,k(i.directory))))return!0}catch{}}try{let o=t.prepare(`
110
91
  SELECT data
111
92
  FROM "message"
112
93
  WHERE session_id = ?
113
94
  ORDER BY time_created DESC
114
95
  LIMIT 20
115
- `).all(b(e.id));for(let i of o){let a=ht(i.data),c=a.path&&typeof a.path=="object"?a.path:{};for(let u of[b(c.cwd),b(c.root)])if(u&&Je(n.rootPath,u))return!0}}catch{}return!1}function dr(t,e,n,r){let s=`
96
+ `).all(k(e.id));for(let i of o){let d=Ae(i.data),c=d.path&&typeof d.path=="object"?d.path:{};for(let a of[k(c.cwd),k(c.root)])if(a&&ve(n.rootPath,a))return!0}}catch{}return!1}function Dt(t,e,n,r){let s=`
116
97
  SELECT *,
117
98
  COALESCE(
118
99
  time_updated,
@@ -143,10 +124,7 @@ Things an AI agent should always remember.
143
124
  0
144
125
  ) ASC,
145
126
  id ASC
146
- `;return t.prepare(s).all(n,r.time,r.time,r.id)}function pr(t,e){let n=t[t.length-1];return n?{time:V(n.__clock),id:b(n.id)}:e}function Ea(t,e){let n=ht(e.data),r=b(n.role),s=V(e.__clock),o=b(e.id),i="message";return r==="user"?i="user_prompt":r==="assistant"&&(i="assistant_message"),{clock:s,order:0,event:{type:i,timestamp:Y(s),role:r||void 0,sourceEventId:`message:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{messageId:o,...n},provenance:{source:"opencode",sourcePath:t,sourceTable:"message",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}function Pa(t){let e={...t},n=t.state&&typeof t.state=="object"&&!Array.isArray(t.state)?{...t.state}:void 0;if(n){let r=n.output;if(typeof r=="string"){let s=r.replace(/\r\n/g,`
147
- `),o=500;n.outputSummary=s.length<=o?s:`${s.slice(0,350)}
148
- ...[ToolNet truncated ${s.length-o} chars]...
149
- ${s.slice(-150)}`,delete n.output}else r!==void 0&&(n.outputSummary="[non-text tool output omitted]",delete n.output);if(n.input&&typeof n.input=="object"&&!Array.isArray(n.input)){let s={...n.input};for(let[o,i]of Object.entries(s))typeof i=="string"&&i.length>1e3&&(s[o]=`${i.slice(0,1e3)}...[ToolNet truncated]`);n.input=s}e.state=n}return e}function Ma(t,e){let n=ht(e.data),r=b(n.type),s=V(e.__clock),o=b(e.id),i=b(e.message_id),a="message_part";return r==="tool"?a="tool_call":r==="snapshot"&&(a="artifact"),{clock:s,order:1,event:{type:a,timestamp:Y(s),sourceEventId:`part:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{partId:o,messageId:i,...r==="tool"?Pa(n):n},provenance:{source:"opencode",sourcePath:t,sourceTable:"part",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}async function St(t){let e=t.dbPath??mr(),n=fr(e);try{let r=Aa(n,t.nativeSessionId);if(!gr(n,r,t.project))throw new Error(["OpenCode session does not belong to current ToolNet project.",`Session: ${t.nativeSessionId}`,`Project: ${t.project.rootPath}`,`Session directory: ${b(r.directory)||"unknown"}`].join(" "));let s=new Ve({project:t.project,storage:t.storage,agent:"opencode",nativeSessionId:t.nativeSessionId,title:b(r.title)||void 0,metadata:{source:"opencode.db",openCodeProjectId:b(r.project_id)||void 0,directory:b(r.directory)||void 0}}),o=s.status(),i=ur(o.sourceCursors["opencode.message"]),a=ur(o.sourceCursors["opencode.part"]),c=dr(n,"message",t.nativeSessionId,i),u=dr(n,"part",t.nativeSessionId,a),p=[];if(o.lastSequence===0){let g=V(r.time_created);p.push({clock:g,order:-1,event:{type:"session_start",timestamp:Y(g),sourceEventId:`session:${t.nativeSessionId}:created:${g}`,data:{title:b(r.title)||void 0,directory:b(r.directory)||void 0,openCodeProjectId:b(r.project_id)||void 0},provenance:{source:"opencode",sourcePath:e,sourceTable:"session",sourceRowId:t.nativeSessionId}}})}p.push(...c.map(g=>Ea(e,g))),p.push(...u.map(g=>Ma(e,g)));let l=V(r.time_updated)||V(r.time_created);t.compacted&&p.push({clock:l,order:98,event:{type:"session_compact",timestamp:Y(l),sourceEventId:`session:${t.nativeSessionId}:compact:${l}`,data:{},provenance:{source:"opencode"}}}),t.error?p.push({clock:l,order:99,event:{type:"error",timestamp:Y(l),sourceEventId:`session:${t.nativeSessionId}:error:${l}`,data:{source:"session.error"},provenance:{source:"opencode"}}}):t.idle&&p.push({clock:l,order:100,event:{type:"session_idle",timestamp:Y(l),sourceEventId:`session:${t.nativeSessionId}:idle:${l}`,data:{},provenance:{source:"opencode"}}}),p.sort((g,v)=>g.clock-v.clock||g.order-v.order);let m=p.filter(g=>!ir(g.event.data)).map(g=>({...g,event:{...g.event,data:qe(g.event.data)}})),d=s.recordMany(m.map(g=>g.event)),f=pr(c,i),h=pr(u,a);if(s.setSourceCursor("opencode.message",lr(f)),s.setSourceCursor("opencode.part",lr(h)),t.idle&&m.length>0)try{let g=m.map(A=>JSON.stringify(A.event.data)),v=je(g,t.nativeSessionId);s.setSourceCursor("opencode.session.summary",v.summary),s.setSourceCursor("opencode.session.facts_count",v.durableFacts.length),Qt()&&!tn()&&s.setSourceCursor("opencode.raw_transcript.archived","local")}catch{}let y=await s.flush();return{nativeSessionId:t.nativeSessionId,importedMessages:c.length,importedParts:u.length,recordedEvents:d.length,eventCount:y.eventCount,chunkCount:y.chunkCount,status:y.status}}finally{n.close()}}async function yr(t){let e=t.dbPath??mr(),n=fr(e),r=[];try{let o=n.prepare(`
127
+ `;return t.prepare(s).all(n,r.time,r.time,r.id)}function Ft(t,e){let n=t[t.length-1];return n?{time:_(n.__clock),id:k(n.id)}:e}function Os(t,e){let n=Ae(e.data),r=k(n.role),s=_(e.__clock),o=k(e.id),i="message";return r==="user"?i="user_prompt":r==="assistant"&&(i="assistant_message"),{clock:s,order:0,event:{type:i,timestamp:W(s),role:r||void 0,sourceEventId:`message:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{messageId:o,...n},provenance:{source:"opencode",sourcePath:t,sourceTable:"message",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}function Ps(t,e){let n=Ae(e.data),r=k(n.type),s=_(e.__clock),o=k(e.id),i=k(e.message_id),d="message_part";return r==="tool"?d="tool_call":r==="snapshot"&&(d="artifact"),{clock:s,order:1,event:{type:d,timestamp:W(s),sourceEventId:`part:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{partId:o,messageId:i,...n},provenance:{source:"opencode",sourcePath:t,sourceTable:"part",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}async function Ne(t){let e=t.dbPath??Kt(),n=Wt(e);try{let r=Es(n,t.nativeSessionId);if(!Bt(n,r,t.project))throw new Error(["OpenCode session does not belong to current ToolNet project.",`Session: ${t.nativeSessionId}`,`Project: ${t.project.rootPath}`,`Session directory: ${k(r.directory)||"unknown"}`].join(" "));let s=new ge({project:t.project,storage:t.storage,agent:"opencode",nativeSessionId:t.nativeSessionId,title:k(r.title)||void 0,metadata:{source:"opencode.db",openCodeProjectId:k(r.project_id)||void 0,directory:k(r.directory)||void 0}}),o=s.status(),i=$t(o.sourceCursors["opencode.message"]),d=$t(o.sourceCursors["opencode.part"]),c=Dt(n,"message",t.nativeSessionId,i),a=Dt(n,"part",t.nativeSessionId,d),p=[];if(o.lastSequence===0){let h=_(r.time_created);p.push({clock:h,order:-1,event:{type:"session_start",timestamp:W(h),sourceEventId:`session:${t.nativeSessionId}:created:${h}`,data:{title:k(r.title)||void 0,directory:k(r.directory)||void 0,openCodeProjectId:k(r.project_id)||void 0},provenance:{source:"opencode",sourcePath:e,sourceTable:"session",sourceRowId:t.nativeSessionId}}})}p.push(...c.map(h=>Os(e,h))),p.push(...a.map(h=>Ps(e,h)));let u=_(r.time_updated)||_(r.time_created);t.compacted&&p.push({clock:u,order:98,event:{type:"session_compact",timestamp:W(u),sourceEventId:`session:${t.nativeSessionId}:compact:${u}`,data:{},provenance:{source:"opencode"}}}),t.error?p.push({clock:u,order:99,event:{type:"error",timestamp:W(u),sourceEventId:`session:${t.nativeSessionId}:error:${u}`,data:{source:"session.error"},provenance:{source:"opencode"}}}):t.idle&&p.push({clock:u,order:100,event:{type:"session_idle",timestamp:W(u),sourceEventId:`session:${t.nativeSessionId}:idle:${u}`,data:{},provenance:{source:"opencode"}}}),p.sort((h,w)=>h.clock-w.clock||h.order-w.order);let m=p.filter(h=>!Ct(h.event.data)).map(h=>({...h,event:{...h.event,data:he(h.event.data)}})),l=s.recordMany(m.map(h=>h.event)),S=Ft(c,i),y=Ft(a,d);if(s.setSourceCursor("opencode.message",Lt(S)),s.setSourceCursor("opencode.part",Lt(y)),t.idle&&m.length>0)try{let h=m.map(C=>JSON.stringify(C.event.data)),w=Nt(h,t.nativeSessionId);s.setSourceCursor("opencode.session.summary",w.summary),s.setSourceCursor("opencode.session.facts_count",w.durableFacts.length),Tt()&&!At()&&s.setSourceCursor("opencode.raw_transcript.archived","local")}catch{}let g=await s.flush();return{nativeSessionId:t.nativeSessionId,importedMessages:c.length,importedParts:a.length,recordedEvents:l.length,eventCount:g.eventCount,chunkCount:g.chunkCount,status:g.status}}finally{n.close()}}async function zt(t){let e=t.dbPath??Kt(),n=Wt(e),r=[];try{let o=n.prepare(`
150
128
  SELECT *
151
129
  FROM "session"
152
130
  ORDER BY
@@ -155,225 +133,27 @@ ${s.slice(-150)}`,delete n.output}else r!==void 0&&(n.outputSummary="[non-text t
155
133
  time_created,
156
134
  0
157
135
  ) DESC
158
- `).all();for(let i of o){if(!gr(n,i,t.project))continue;let a=b(i.id);if(a&&r.push(a),r.length>=(t.limit??100))break}}finally{n.close()}let s=[];for(let o of r)s.push(await St({project:t.project,storage:t.storage,nativeSessionId:o,dbPath:e}));return s}import{existsSync as Ra,mkdirSync as kr,readFileSync as Na,writeFileSync as br}from"node:fs";import{join as _a}from"node:path";import{homedir as Ta}from"node:os";import{join as He}from"node:path";function Ge(t={}){let e=t.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return e?He(e,"opencode"):He(t.home??Ta(),".config","opencode")}function hr(t={}){return He(Ge(t),"plugins")}function Sr(t={}){return He(Ge(t),"AGENTS.md")}var Oa="memory_agent_ask";function wr(){return`
159
- [TOOLNET MEMORY AGENT]
160
-
161
- Tool available:
162
- - ${Oa}
163
-
164
- Use it automatically BEFORE guessing when:
165
-
166
- - The user asks to continue, resume, or pick up previous work.
167
- - The user says things like:
168
- - "ti\u1EBFp t\u1EE5c task l\xFAc n\xE3y"
169
- - "l\xE0m ti\u1EBFp ph\u1EA7n \u0111ang d\u1EDF"
170
- - "agent tr\u01B0\u1EDBc \u0111ang l\xE0m g\xEC?"
171
- - "d\u1EEBng \u1EDF \u0111\xE2u?"
172
- - "todo n\xE0o ch\u01B0a xong?"
173
- - "continue the previous task"
174
- - "resume the last session"
175
- - Previous-agent state, unfinished work, blockers,
176
- decisions, touched files, or next actions are unclear.
177
- - Fast startup context is not enough to safely continue.
178
-
179
- Preferred mode:
180
-
181
- - mode="local"
182
- for direct factual questions such as:
183
- current task, last file, blocker, completed TODOs.
184
-
185
- - mode="ai"
186
- for composite or ambiguous continuity questions
187
- that benefit from ToolNet Memory Agent reasoning.
188
-
189
- Do NOT call it automatically when:
190
-
191
- - Normal startup context already gives enough information.
192
- - The question is unrelated to previous project work.
193
- - The answer is obvious from current repository evidence.
194
-
195
- Rules:
196
-
197
- - Never invent previous work.
198
- - Current repository evidence overrides stale memory.
199
- - NEVER reconstruct previous work by reading ToolNet internal session files.
200
- - NEVER read/list/search .toolnet/sessions/**, session state.json,
201
- events.jsonl, or raw transcripts to discover previous-agent state.
202
- - Do not search the filesystem for the implementation/schema of
203
- memory_agent_ask. Invoke the MCP tool directly when deeper
204
- continuity is required.
205
- - Do not dump raw transcripts or full memory.
206
- - After receiving the ToolNet answer, continue the task
207
- instead of asking the user to repeat known context.
208
- - If ToolNet says information is not recorded, say so.
209
- `.trim()}var vr="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",wt="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function $a(){let t=Sr();kr(Ge(),{recursive:!0});let e=`${vr}
210
- ## ToolNet Memory
211
-
212
- ToolNet Memory is available for projects that already contain a valid \`.toolnet/project.json\`.
213
-
214
- Rules:
215
-
216
- 1. Do not create a ToolNet project automatically.
217
- 2. If no valid \`.toolnet/project.json\` exists in the current project or an ancestor, ignore ToolNet Memory.
218
- 3. Normal startup context must stay small and selective.
219
- 4. Do not automatically run deep recovery commands.
220
- 5. Use ToolNet MCP or selective retrieval when older project knowledge is actually needed.
221
- 6. Raw transcripts must not be injected into prompts.
222
- 7. Current repository evidence has priority over stale memory when they conflict.
223
-
224
-
225
- ${wr()}
226
-
227
- ${wt}`,n=Ra(t)?Na(t,"utf8"):"",r=n.indexOf(vr),s=n.indexOf(wt);return r>=0&&s>=r?n=n.slice(0,r)+e+n.slice(s+wt.length):(n=n.trimEnd(),n&&(n+=`
228
-
229
- `),n+=e),br(t,n.trimEnd()+`
230
- `,{encoding:"utf8",mode:384}),t}function xr(t={}){let e=t.directory??hr();kr(e,{recursive:!0}),$a();let n=_a(e,"toolnet-memory.js"),r=t.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`
231
- // Generated by ToolNet Memory.
232
- // OpenCode integration:
233
- // - project gated
234
- // - selective context injection
235
- // - incremental session checkpoints
236
- // - periodic durability sync
237
- // - best-effort shutdown flush
238
-
239
- import fs from "node:fs"
240
- import path from "node:path"
241
- import os from "node:os"
242
-
243
- const TOOLNET_BINARY =
244
- ${JSON.stringify(r)}
245
-
246
- const CONTEXT_MAX_TOKENS = 700
247
-
248
- const CONTEXT_CACHE_MS = 5000
249
-
250
- const PERIODIC_SYNC_MS = 30000
251
-
252
- const SYNC_TIMEOUT_MS = 15000
253
-
254
- const STATUS_FILE = path.join(
255
- os.homedir(),
256
- ".config",
257
- "toolnet-memory",
258
- "opencode-sync-status.json"
259
- )
260
-
261
- function writeStatus(data) {
262
- try {
263
- fs.mkdirSync(
264
- path.dirname(
265
- STATUS_FILE
266
- ),
267
- {
268
- recursive: true,
269
- }
270
- )
136
+ `).all();for(let i of o){if(!Bt(n,i,t.project))continue;let d=k(i.id);if(d&&r.push(d),r.length>=(t.limit??100))break}}finally{n.close()}let s=[];for(let o of r)s.push(await Ne({project:t.project,storage:t.storage,nativeSessionId:o,dbPath:e}));return s}import{existsSync as Cs,mkdirSync as Jt,readFileSync as Ts,writeFileSync as Vt}from"node:fs";import{homedir as $e}from"node:os";import{join as be}from"node:path";var qt="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",_e="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function Rs(){let t=be($e(),".config","opencode","AGENTS.md");Jt(be($e(),".config","opencode"),{recursive:!0});let e=`${qt}
137
+ ## ToolNet Memory \u2014 Project Continuity
271
138
 
272
- fs.writeFileSync(
273
- STATUS_FILE,
274
- JSON.stringify(
275
- {
276
- timestamp:
277
- new Date()
278
- .toISOString(),
279
- ...data,
280
- },
281
- null,
282
- 2
283
- ) + "\\n"
284
- )
285
- } catch {
286
- // Status reporting must
287
- // never break OpenCode.
288
- }
289
- }
290
-
291
- function validProjectManifest(
292
- file
293
- ) {
294
- try {
295
- const parsed =
296
- JSON.parse(
297
- fs.readFileSync(
298
- file,
299
- "utf8"
300
- )
301
- )
302
-
303
- return Boolean(
304
- parsed &&
305
- typeof parsed ===
306
- "object" &&
307
- typeof parsed.id ===
308
- "string" &&
309
- parsed.id.length > 0
310
- )
311
- } catch {
312
- return false
313
- }
314
- }
315
-
316
- function findProjectRoot(
317
- inputDirectory
318
- ) {
319
- let current =
320
- path.resolve(
321
- inputDirectory
322
- )
323
-
324
- const filesystemRoot =
325
- path.parse(
326
- current
327
- ).root
328
-
329
- while (true) {
330
- const manifest =
331
- path.join(
332
- current,
333
- ".toolnet",
334
- "project.json"
335
- )
336
-
337
- if (
338
- fs.existsSync(
339
- manifest
340
- ) &&
341
- validProjectManifest(
342
- manifest
343
- )
344
- ) {
345
- return current
346
- }
347
-
348
- if (
349
- current ===
350
- filesystemRoot
351
- ) {
352
- break
353
- }
354
-
355
- const parent =
356
- path.dirname(
357
- current
358
- )
139
+ When the current workspace belongs to a ToolNet project, identified by a nearest ancestor containing \`.toolnet/project.json\`:
359
140
 
360
- if (
361
- parent === current
362
- ) {
363
- break
364
- }
141
+ 1. Before planning, editing, or running implementation commands, read that project root's \`.toolnet/context/startup.md\`.
142
+ 2. Treat its PROJECT RULES, MISSION, CURRENT OBJECTIVE, rationale, current phase/task, Definition of Done, blockers and next actions as project continuity context.
143
+ 3. Do not restart work already marked completed unless repository evidence proves it must be revisited.
144
+ 4. Verify current repository state before continuing old work.
145
+ 5. If \`.toolnet/context/startup.md\` is missing, run \`toolnet-memory context:sync --project <project-root>\`, then read it.
146
+ 6. Never invent missing rationale. If ToolNet says a reason was not explicitly recorded, inspect the implementation or ask rather than guessing.
365
147
 
366
- current = parent
367
- }
148
+ This applies automatically to every ToolNet-managed project.
149
+ ${_e}`,n=Cs(t)?Ts(t,"utf8"):"",r=n.indexOf(qt),s=n.indexOf(_e);return r>=0&&s>=r?n=n.slice(0,r)+e+n.slice(s+_e.length):(n=n.trimEnd(),n&&(n+=`
368
150
 
369
- return null
370
- }
151
+ `),n+=e),Vt(t,n.trimEnd()+`
152
+ `,{encoding:"utf8",mode:384}),t}function Ut(t={}){let e=t.directory??be($e(),".config","opencode","plugins");Jt(e,{recursive:!0}),Rs();let n=be(e,"toolnet-memory.js"),r=t.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`// Generated by ToolNet Memory.
153
+ // OpenCode session capture + continuity bootstrap.
371
154
 
372
- function getSessionId(
373
- event
374
- ) {
375
- const p =
376
- event?.properties ?? {}
155
+ function getSessionId(event) {
156
+ const p = event?.properties ?? {}
377
157
 
378
158
  const candidates = [
379
159
  p.sessionID,
@@ -382,493 +162,164 @@ function getSessionId(
382
162
  p.session?.id,
383
163
  ]
384
164
 
385
- return (
386
- candidates.find(
387
- value =>
388
- typeof value ===
389
- "string" &&
390
- value.length > 0
391
- ) ?? null
392
- )
165
+ return candidates.find(
166
+ value => typeof value === "string" && value.length > 0
167
+ ) ?? null
393
168
  }
394
169
 
395
- async function runWithTimeout(
396
- args,
397
- {
398
- stdout = "ignore",
399
- timeout =
400
- SYNC_TIMEOUT_MS,
401
- } = {}
402
- ) {
403
- const child =
404
- Bun.spawn(
405
- args,
406
- {
407
- stdin:
408
- "ignore",
409
- stdout,
410
- stderr:
411
- "ignore",
412
- }
413
- )
414
-
415
- let timer
416
-
417
- const timeoutPromise =
418
- new Promise(
419
- (_, reject) => {
420
- timer =
421
- setTimeout(
422
- () => {
423
- try {
424
- child.kill()
425
- } catch {}
426
-
427
- reject(
428
- new Error(
429
- "ToolNet command timeout"
430
- )
431
- )
432
- },
433
- timeout
434
- )
435
- }
436
- )
437
-
438
- try {
439
- const exitCode =
440
- await Promise.race([
441
- child.exited,
442
- timeoutPromise,
443
- ])
444
-
445
- if (
446
- typeof exitCode ===
447
- "number" &&
448
- exitCode !== 0
449
- ) {
450
- throw new Error(
451
- \`ToolNet exited with code \${exitCode}\`
170
+ export const ToolNetMemoryPlugin = async ({ directory }) => {
171
+ const binary = ${JSON.stringify(r)}
172
+
173
+ async function refreshContext() {
174
+ try {
175
+ const child = Bun.spawn(
176
+ [
177
+ binary,
178
+ "context:sync",
179
+ "--project",
180
+ directory,
181
+ ],
182
+ {
183
+ stdin: "ignore",
184
+ stdout: "ignore",
185
+ stderr: "ignore",
186
+ }
452
187
  )
453
- }
454
188
 
455
- return child
456
- } finally {
457
- if (timer) {
458
- clearTimeout(
459
- timer
460
- )
189
+ await child.exited
190
+ } catch {
191
+ // Context sync must never break OpenCode startup.
461
192
  }
462
193
  }
463
- }
464
194
 
465
- export const ToolNetMemoryPlugin =
466
- async ({
467
- directory,
468
- }) => {
469
- /*
470
- * CRITICAL:
471
- * Never auto-create a ToolNet
472
- * project just because OpenCode
473
- * happens to start in /root,
474
- * /tmp, $HOME, etc.
475
- */
476
- const projectRoot =
477
- findProjectRoot(
478
- directory
195
+ async function readContext() {
196
+ try {
197
+ const child = Bun.spawn(
198
+ [
199
+ binary,
200
+ "context:print",
201
+ "--project",
202
+ directory,
203
+ "--tokens",
204
+ "900",
205
+ ],
206
+ {
207
+ stdin: "ignore",
208
+ stdout: "pipe",
209
+ stderr: "ignore",
210
+ }
479
211
  )
480
212
 
481
- if (!projectRoot) {
482
- writeStatus({
483
- active: false,
484
- reason:
485
- "no-toolnet-project",
486
- directory,
487
- })
213
+ const text =
214
+ await new Response(
215
+ child.stdout
216
+ ).text()
488
217
 
489
- return {}
490
- }
218
+ await child.exited
491
219
 
492
- writeStatus({
493
- active: true,
494
- projectRoot,
495
- state:
496
- "plugin-loaded",
497
- })
220
+ return text.trim()
221
+ } catch {
222
+ return ""
223
+ }
224
+ }
498
225
 
499
- let lastSessionId =
500
- null
226
+ function sync(sessionId, flag) {
227
+ if (!sessionId) return
501
228
 
502
- let syncChain =
503
- Promise.resolve()
229
+ try {
230
+ const args = [
231
+ binary,
232
+ "session:opencode-sync",
233
+ sessionId,
234
+ "--project",
235
+ directory,
236
+ ]
504
237
 
505
- let contextCache = {
506
- value: "",
507
- expiresAt: 0,
508
- }
238
+ if (flag) {
239
+ args.push(flag)
240
+ }
509
241
 
510
- async function readContext() {
511
- const now =
512
- Date.now()
242
+ const child = Bun.spawn(args, {
243
+ stdin: "ignore",
244
+ stdout: "ignore",
245
+ stderr: "ignore",
246
+ })
513
247
 
514
248
  if (
515
- contextCache.value &&
516
- now <
517
- contextCache.expiresAt
249
+ typeof child.unref === "function"
518
250
  ) {
519
- return (
520
- contextCache.value
521
- )
251
+ child.unref()
522
252
  }
253
+ } catch {
254
+ // Memory capture must never break OpenCode.
255
+ }
256
+ }
523
257
 
524
- try {
525
- const child =
526
- Bun.spawn(
527
- [
528
- TOOLNET_BINARY,
529
- "context:print",
530
- "--project",
531
- projectRoot,
532
- "--tokens",
533
- String(
534
- CONTEXT_MAX_TOKENS
535
- ),
536
- ],
537
- {
538
- stdin:
539
- "ignore",
540
- stdout:
541
- "pipe",
542
- stderr:
543
- "ignore",
544
- }
545
- )
546
-
547
- const textPromise =
548
- new Response(
549
- child.stdout
550
- ).text()
551
-
552
- const exitCode =
553
- await child.exited
554
-
555
- if (
556
- exitCode !== 0
557
- ) {
558
- return ""
559
- }
560
-
561
- const text =
562
- (
563
- await textPromise
564
- ).trim()
565
-
566
- contextCache = {
567
- value: text,
568
- expiresAt:
569
- now +
570
- CONTEXT_CACHE_MS,
571
- }
258
+ /*
259
+ * Pull the latest project brief from ToolNet remote storage
260
+ * before the new OpenCode session starts doing work.
261
+ */
262
+ await refreshContext()
572
263
 
573
- return text
574
- } catch {
575
- return ""
576
- }
577
- }
264
+ return {
265
+ event: async ({ event }) => {
266
+ const sessionId =
267
+ getSessionId(event)
578
268
 
579
- async function syncNow(
580
- sessionId,
581
- flag,
582
- reason
583
- ) {
584
269
  if (!sessionId) {
585
270
  return
586
271
  }
587
272
 
588
- const args = [
589
- TOOLNET_BINARY,
590
- "session:opencode-sync",
591
- sessionId,
592
- "--project",
593
- projectRoot,
594
- ]
595
-
596
- if (flag) {
597
- args.push(
598
- flag
599
- )
273
+ if (event.type === "session.idle") {
274
+ sync(sessionId, "--idle")
275
+ return
600
276
  }
601
277
 
602
- try {
603
- await runWithTimeout(
604
- args
605
- )
606
-
607
- writeStatus({
608
- active: true,
609
- projectRoot,
610
- sessionId,
611
- reason,
612
- state:
613
- "sync-success",
614
- })
615
- } catch (error) {
616
- writeStatus({
617
- active: true,
618
- projectRoot,
619
- sessionId,
620
- reason,
621
- state:
622
- "sync-failed",
623
- error:
624
- error instanceof
625
- Error
626
- ? error.message
627
- : String(
628
- error
629
- ),
630
- })
631
-
632
- throw error
278
+ if (event.type === "session.compacted") {
279
+ sync(sessionId, "--compacted")
280
+ return
633
281
  }
634
- }
635
282
 
636
- function queueSync(
637
- sessionId,
638
- flag,
639
- reason
640
- ) {
641
- if (!sessionId) {
642
- return syncChain
283
+ if (event.type === "session.error") {
284
+ sync(sessionId, "--error")
643
285
  }
644
-
645
- lastSessionId =
646
- sessionId
647
-
648
- syncChain =
649
- syncChain
650
- .catch(
651
- () =>
652
- undefined
653
- )
654
- .then(
655
- () =>
656
- syncNow(
657
- sessionId,
658
- flag,
659
- reason
660
- )
661
- )
662
-
663
- return syncChain
664
- }
286
+ },
665
287
 
666
288
  /*
667
- * Periodic durability checkpoint.
668
- *
669
- * This is intentionally independent
670
- * from session.idle/dispose because
671
- * abrupt SSH/process termination may
672
- * skip shutdown hooks.
673
- *
674
- * unref() prevents the timer itself
675
- * from keeping OpenCode alive.
289
+ * Official OpenCode compaction hook.
290
+ * Preserve ToolNet's semantic state after context compaction.
676
291
  */
677
- const periodic =
678
- setInterval(
679
- () => {
680
- if (
681
- lastSessionId
682
- ) {
683
- void queueSync(
684
- lastSessionId,
685
- null,
686
- "periodic"
687
- )
688
- }
689
- },
690
- PERIODIC_SYNC_MS
691
- )
692
-
693
- if (
694
- typeof periodic.unref ===
695
- "function"
696
- ) {
697
- periodic.unref()
698
- }
699
-
700
- return {
701
- event: async ({
702
- event,
703
- }) => {
704
- const sessionId =
705
- getSessionId(
706
- event
707
- )
708
-
709
- if (sessionId) {
710
- lastSessionId =
711
- sessionId
712
- }
713
-
714
- if (
715
- event.type ===
716
- "session.idle"
717
- ) {
718
- await queueSync(
719
- sessionId,
720
- "--idle",
721
- "session.idle"
722
- )
723
-
724
- return
725
- }
726
-
727
- if (
728
- event.type ===
729
- "session.compacted"
730
- ) {
731
- await queueSync(
732
- sessionId,
733
- "--compacted",
734
- "session.compacted"
735
- )
736
-
737
- contextCache = {
738
- value: "",
739
- expiresAt: 0,
740
- }
741
-
742
- return
743
- }
292
+ "experimental.session.compacting": async (_input, output) => {
293
+ const context =
294
+ await readContext()
744
295
 
745
- if (
746
- event.type ===
747
- "session.error"
748
- ) {
749
- await queueSync(
750
- sessionId,
751
- "--error",
752
- "session.error"
753
- )
754
-
755
- return
756
- }
757
- },
758
-
759
- /*
760
- * VERIFIED on OpenCode 1.18.14:
761
- * this hook fires on real model turns.
762
- *
763
- * It remains experimental, therefore
764
- * AGENTS.md + MCP stay as fallbacks.
765
- */
766
- "experimental.chat.system.transform":
767
- async (
768
- _input,
769
- output
770
- ) => {
771
- const context =
772
- await readContext()
773
-
774
- if (!context) {
775
- return
776
- }
777
-
778
- if (
779
- Array.isArray(
780
- output?.system
781
- )
782
- ) {
783
- output.system.push(
784
- context
785
- )
786
-
787
- return
788
- }
789
-
790
- if (
791
- typeof output?.system ===
792
- "string"
793
- ) {
794
- output.system =
795
- output.system
796
- ? \`\${output.system}\\n\\n\${context}\`
797
- : context
798
- }
799
- },
800
-
801
- /*
802
- * Optional compaction survival hook.
803
- * We keep it as a supplementary path,
804
- * never as the only continuity path.
805
- */
806
- "experimental.session.compacting":
807
- async (
808
- _input,
809
- output
810
- ) => {
811
- const context =
812
- await readContext()
813
-
814
- if (
815
- context &&
816
- Array.isArray(
817
- output?.context
818
- )
819
- ) {
820
- output.context.push(
821
- context
822
- )
823
- }
824
- },
825
-
826
- /*
827
- * VERIFIED for clean OpenCode exits.
828
- * Best effort only: kill -9 / crash /
829
- * machine loss cannot guarantee this.
830
- */
831
- dispose: async () => {
832
- clearInterval(
833
- periodic
296
+ if (
297
+ context &&
298
+ Array.isArray(
299
+ output.context
834
300
  )
835
-
836
- if (
837
- lastSessionId
838
- ) {
839
- try {
840
- await queueSync(
841
- lastSessionId,
842
- "--idle",
843
- "dispose"
844
- )
845
- } catch {
846
- // Status already recorded.
847
- }
848
- }
849
-
850
- try {
851
- await syncChain
852
- } catch {
853
- // Do not block OpenCode shutdown.
854
- }
855
- },
856
- }
301
+ ) {
302
+ output.context.push(
303
+ context
304
+ )
305
+ }
306
+ },
857
307
  }
858
- `;return br(n,s.trimStart(),{encoding:"utf8",mode:384}),n}import{existsSync as Mp,mkdirSync as Wa,readFileSync as Tp,writeFileSync as Fa}from"node:fs";import{dirname as za,join as Cr}from"node:path";function vt(t){if(!t)return 0;let e=Array.from(t).length,n=t.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,n*1.3))}function k(t,e){let n=t.replace(/\s+/g," ").trim();return n.length<=e?n:n.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function Ka(t){let e=[],n=!1;for(let r of t.split(/\r?\n/u)){let s=r.trim();if(s.includes("<!--")&&(n=!0),n){s.includes("-->")&&(n=!1);continue}let o=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||o.startsWith("- [enforce]")||o.startsWith("* [enforce]")||o.startsWith("- [advisory]")||o.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(k(s,280)),e.length>=16))break}return e}function La(t){let e=[],n=[];for(let r of t.split(/\\r?\\n/u)){let s=r.trim(),o=s.toLowerCase(),a=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(u=>o.startsWith(u));if(!a)continue;let c=s.slice(a.length).trim();c&&(a.includes("enforce")?e.push(c):n.push(c))}return{enforce:e,advisory:n}}function Da(t,e){let n=[];for(let r of t){let s=[...n,r].join(`
859
- `);if(vt(s)<=e){n.push(r);continue}let o=vt(n.join(`
860
- `)),i=Math.max(0,e-o);if(i>=16){let a=Math.floor(i*3.2),c=k(r,a);c&&n.push(c)}break}return n.join(`
861
- `).trim()}async function jr(t){let e=Math.max(256,Math.min(2e3,t.maxTokens??1e3)),n=ze(t.project,!1),r=n?.content??"";r||(r=await t.storage.getText(`projects/${t.project.id}/project/manual.md`)??"");let s=La(r),o=n?n.rules.filter(d=>d.mode==="enforce").map(d=>d.text):s.enforce,i=n?n.rules.filter(d=>d.mode==="advisory").map(d=>d.text):s.advisory,a=r?Ka(r):[],c=await Ke(t.project,t.storage),u=await Zn(t.project,t.storage),p=await or(t.project,t.storage),l=[];if(l.push("[TOOLNET PROJECT CONTEXT]"),l.push(`Project: ${t.project.name}`),l.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),r&&l.push(`Full operating manual: ${Fe(t.project)}`),o.length){l.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let d of o.slice(0,24))l.push(`- [ENFORCE] ${k(d,240)}`)}if(i.length){l.push("","PROJECT PREFERENCES");for(let d of i.slice(0,10))l.push(`- ${k(d,220)}`)}if(u&&(u.mission&&l.push("","MISSION",k(u.mission.value,420)),u.activeObjective&&l.push("","CURRENT OBJECTIVE",k(u.activeObjective.value,420)),u.why&&l.push("","WHY THIS WORK MATTERS",k(u.why.value,420)),u.desiredOutcome&&l.push("","DESIRED OUTCOME",k(u.desiredOutcome.value,420)),u.planRationale&&l.push("","WHY THIS APPROACH",k(u.planRationale.value,420))),c){if(l.push("","ACTIVE WORK"),c.goal&&l.push(`Goal: ${k(c.goal,320)}`),c.plan&&l.push(`Plan: ${k(c.plan,320)}`),l.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&l.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&u){let d=u.phases.find(f=>f.order===c.currentPhase?.order);d&&(d.objective&&l.push(`Phase objective: ${k(d.objective.value,340)}`),d.why?l.push(`Why this phase: ${k(d.why.value,340)}`):l.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),d.deliverable&&l.push(`Deliverable: ${k(d.deliverable.value,340)}`),d.dependencies.length&&l.push(`Depends on: ${d.dependencies.slice(0,4).map(f=>k(f.value,180)).join("; ")}`),d.acceptanceCriteria.length&&(l.push("","DEFINITION OF DONE"),d.acceptanceCriteria.slice(0,6).forEach(f=>{l.push(`- ${k(f.value,260)}`)})),d.openQuestions.length&&(l.push("","OPEN QUESTIONS FOR CURRENT PHASE"),d.openQuestions.slice(0,4).forEach(f=>{l.push(`- ${k(f.value,260)}`)})))}c.currentTask&&l.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(l.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((d,f)=>{l.push(`${f+1}. ${k(d,260)}`)})),c.blockers.length&&(l.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(d=>{l.push(`- ${k(d,260)}`)})),c.warnings.length&&(l.push("","ATTENTION"),c.warnings.slice(-5).forEach(d=>{l.push(`- ${k(d,260)}`)})),c.decisions.length&&(l.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(d=>{l.push(`- ${k(d,260)}`)})),c.lastSession&&l.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(u&&u.openQuestions.length&&(l.push("","UNRESOLVED QUESTIONS"),u.openQuestions.slice(0,5).forEach(d=>{l.push(`- ${k(d.value,260)}`)})),p&&l.push(`Latest handoff: ${p.reason} / ${p.sourceSession.agent}`),a.length){l.push("","OPERATING NOTES");for(let d of a)l.push(`- ${d}`)}l.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let m=Da(l,e);return{version:1,projectId:t.project.id,projectName:t.project.name,text:m,estimatedTokens:vt(m),maxTokens:e,hasManual:!!r,hasWorkState:!!c,hasHandoff:!!p,generatedAt:new Date().toISOString()}}function Ba(t){return Cr(t.rootPath,".toolnet","context","startup.md")}function Va(t){return Cr(t.rootPath,".toolnet","context","startup.json")}function qa(t,e){let n=Ba(t);Wa(za(n),{recursive:!0}),Fa(n,e.text.endsWith(`
308
+ }
309
+ `;return Vt(n,s,{encoding:"utf8",mode:384}),n}import{existsSync as Ic,mkdirSync as _s,readFileSync as Ec,writeFileSync as $s}from"node:fs";import{dirname as Ls,join as Yt}from"node:path";function Le(t){if(!t)return 0;let e=Array.from(t).length,n=t.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,n*1.3))}function b(t,e){let n=t.replace(/\s+/g," ").trim();return n.length<=e?n:n.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function Ms(t){let e=[],n=!1;for(let r of t.split(/\r?\n/u)){let s=r.trim();if(s.includes("<!--")&&(n=!0),n){s.includes("-->")&&(n=!1);continue}let o=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||o.startsWith("- [enforce]")||o.startsWith("* [enforce]")||o.startsWith("- [advisory]")||o.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(b(s,280)),e.length>=16))break}return e}function As(t){let e=[],n=[];for(let r of t.split(/\\r?\\n/u)){let s=r.trim(),o=s.toLowerCase(),d=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(a=>o.startsWith(a));if(!d)continue;let c=s.slice(d.length).trim();c&&(d.includes("enforce")?e.push(c):n.push(c))}return{enforce:e,advisory:n}}function Ns(t,e){let n=[];for(let r of t){let s=[...n,r].join(`
310
+ `);if(Le(s)<=e){n.push(r);continue}let o=Le(n.join(`
311
+ `)),i=Math.max(0,e-o);if(i>=16){let d=Math.floor(i*3.2),c=b(r,d);c&&n.push(c)}break}return n.join(`
312
+ `).trim()}async function Ht(t){let e=Math.max(256,Math.min(2e3,t.maxTokens??1e3)),n=fe(t.project,!1),r=n?.content??"";r||(r=await t.storage.getText(`projects/${t.project.id}/project/manual.md`)??"");let s=As(r),o=n?n.rules.filter(l=>l.mode==="enforce").map(l=>l.text):s.enforce,i=n?n.rules.filter(l=>l.mode==="advisory").map(l=>l.text):s.advisory,d=r?Ms(r):[],c=await ce(t.project,t.storage),a=await xt(t.project,t.storage),p=await Pt(t.project,t.storage),u=[];if(u.push("[TOOLNET PROJECT CONTEXT]"),u.push(`Project: ${t.project.name}`),u.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),r&&u.push(`Full operating manual: ${pe(t.project)}`),o.length){u.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let l of o.slice(0,24))u.push(`- [ENFORCE] ${b(l,240)}`)}if(i.length){u.push("","PROJECT PREFERENCES");for(let l of i.slice(0,10))u.push(`- ${b(l,220)}`)}if(a&&(a.mission&&u.push("","MISSION",b(a.mission.value,420)),a.activeObjective&&u.push("","CURRENT OBJECTIVE",b(a.activeObjective.value,420)),a.why&&u.push("","WHY THIS WORK MATTERS",b(a.why.value,420)),a.desiredOutcome&&u.push("","DESIRED OUTCOME",b(a.desiredOutcome.value,420)),a.planRationale&&u.push("","WHY THIS APPROACH",b(a.planRationale.value,420))),c){if(u.push("","ACTIVE WORK"),c.goal&&u.push(`Goal: ${b(c.goal,320)}`),c.plan&&u.push(`Plan: ${b(c.plan,320)}`),u.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&u.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&a){let l=a.phases.find(S=>S.order===c.currentPhase?.order);l&&(l.objective&&u.push(`Phase objective: ${b(l.objective.value,340)}`),l.why?u.push(`Why this phase: ${b(l.why.value,340)}`):u.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),l.deliverable&&u.push(`Deliverable: ${b(l.deliverable.value,340)}`),l.dependencies.length&&u.push(`Depends on: ${l.dependencies.slice(0,4).map(S=>b(S.value,180)).join("; ")}`),l.acceptanceCriteria.length&&(u.push("","DEFINITION OF DONE"),l.acceptanceCriteria.slice(0,6).forEach(S=>{u.push(`- ${b(S.value,260)}`)})),l.openQuestions.length&&(u.push("","OPEN QUESTIONS FOR CURRENT PHASE"),l.openQuestions.slice(0,4).forEach(S=>{u.push(`- ${b(S.value,260)}`)})))}c.currentTask&&u.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(u.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((l,S)=>{u.push(`${S+1}. ${b(l,260)}`)})),c.blockers.length&&(u.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(l=>{u.push(`- ${b(l,260)}`)})),c.warnings.length&&(u.push("","ATTENTION"),c.warnings.slice(-5).forEach(l=>{u.push(`- ${b(l,260)}`)})),c.decisions.length&&(u.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(l=>{u.push(`- ${b(l,260)}`)})),c.lastSession&&u.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(a&&a.openQuestions.length&&(u.push("","UNRESOLVED QUESTIONS"),a.openQuestions.slice(0,5).forEach(l=>{u.push(`- ${b(l.value,260)}`)})),p&&u.push(`Latest handoff: ${p.reason} / ${p.sourceSession.agent}`),d.length){u.push("","OPERATING NOTES");for(let l of d)u.push(`- ${l}`)}u.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let m=Ns(u,e);return{version:1,projectId:t.project.id,projectName:t.project.name,text:m,estimatedTokens:Le(m),maxTokens:e,hasManual:!!r,hasWorkState:!!c,hasHandoff:!!p,generatedAt:new Date().toISOString()}}function Ds(t){return Yt(t.rootPath,".toolnet","context","startup.md")}function Fs(t){return Yt(t.rootPath,".toolnet","context","startup.json")}function Ks(t,e){let n=Ds(t);_s(Ls(n),{recursive:!0}),$s(n,e.text.endsWith(`
862
313
  `)?e.text:e.text+`
863
- `,{encoding:"utf8",mode:384}),E(Va(t),e)}async function Ir(t,e,n=800){let s=(await jr({project:t,storage:e,maxTokens:n})).text;be(s)>n&&(s=xe(s,n),s+=`
314
+ `,{encoding:"utf8",mode:384}),I(Fs(t),e)}async function Gt(t,e,n=800){let s=(await Ht({project:t,storage:e,maxTokens:n})).text;ye(s)>n&&(s=Se(s,n),s+=`
864
315
 
865
316
  [Context trimmed by ToolNet Memory token budget]
866
- `);let i={version:1,projectId:t.id,projectName:t.name,text:s,digest:w(s),estimatedTokens:be(s),generatedAt:new Date().toISOString()};return qa(t,i),await e.put(`projects/${t.id}/context/startup.md`,i.text+`
317
+ `);let i={version:1,projectId:t.id,projectName:t.name,text:s,digest:v(s),estimatedTokens:ye(s),generatedAt:new Date().toISOString()};return Ks(t,i),await e.put(`projects/${t.id}/context/startup.md`,i.text+`
867
318
  `,"text/markdown"),await e.put(`projects/${t.id}/context/startup.json`,JSON.stringify(i,null,2)+`
868
- `,"application/json"),i}function Ue(t,e){let n=t.indexOf(e);if(!(n<0))return t[n+1]}function kt(t,e){return t.includes(e)}function Ja(t){let e=pe(),n=Ot(Mt({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new Se(n,t.id,t.name,t.remote??t.name)}async function Ha(){let[t="help",...e]=process.argv.slice(2);if(t==="install-plugin"){let i=xr({binary:Ue(e,"--bin")});console.log(`\u2705 OpenCode plugin installed: ${i}`),console.log("OpenCode will load it automatically on next start.");return}let n=Ue(e,"--project")??process.cwd(),r=new fe().detect(n),s=Ja(r),o=Ue(e,"--db");if(t==="sync"){let i=e.find(l=>!l.startsWith("--")&&l!==n&&l!==o);if(!i)throw new Error("Usage: session:opencode-sync <session-id>");let a=kt(e,"--idle"),c=kt(e,"--error"),u=kt(e,"--compacted"),p=await St({project:r,storage:s,nativeSessionId:i,dbPath:o,idle:a,error:c,compacted:u});if(a||u||c)try{await Ir(r,s,800)}catch{}console.log(JSON.stringify(p,null,2));return}if(t==="recover"){let i=Ue(e,"--limit"),a=i?Number(i):100,c=await yr({project:r,storage:s,dbPath:o,limit:Number.isFinite(a)?a:100});console.log(JSON.stringify({project:r.name,sessions:c.length,importedMessages:c.reduce((u,p)=>u+p.importedMessages,0),importedParts:c.reduce((u,p)=>u+p.importedParts,0)},null,2));return}console.log(`OpenCode Session Adapter
319
+ `,"application/json"),i}function ke(t,e){let n=t.indexOf(e);if(!(n<0))return t[n+1]}function De(t,e){return t.includes(e)}function Ws(t){let e=H(),n=Ge(He({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new ee(n,t.id,t.name,t.remote??t.name)}async function Bs(){let[t="help",...e]=process.argv.slice(2);if(t==="install-plugin"){let i=Ut({binary:ke(e,"--bin")});console.log(`\u2705 OpenCode plugin installed: ${i}`),console.log("OpenCode will load it automatically on next start.");return}let n=ke(e,"--project")??process.cwd(),r=new G().detect(n),s=Ws(r),o=ke(e,"--db");if(t==="sync"){let i=e.find(u=>!u.startsWith("--")&&u!==n&&u!==o);if(!i)throw new Error("Usage: session:opencode-sync <session-id>");let d=De(e,"--idle"),c=De(e,"--error"),a=De(e,"--compacted"),p=await Ne({project:r,storage:s,nativeSessionId:i,dbPath:o,idle:d,error:c,compacted:a});if(d||a||c)try{await Gt(r,s,800)}catch{}console.log(JSON.stringify(p,null,2));return}if(t==="recover"){let i=ke(e,"--limit"),d=i?Number(i):100,c=await zt({project:r,storage:s,dbPath:o,limit:Number.isFinite(d)?d:100});console.log(JSON.stringify({project:r.name,sessions:c.length,importedMessages:c.reduce((a,p)=>a+p.importedMessages,0),importedParts:c.reduce((a,p)=>a+p.importedParts,0)},null,2));return}console.log(`OpenCode Session Adapter
869
320
 
870
321
  Commands:
871
322
  sync <session-id> [--project PATH] [--idle]
872
323
  recover [--project PATH] [--limit N]
873
324
  install-plugin [--bin PATH]
874
- `)}Ha().catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});
325
+ `)}Bs().catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});