toolnet-memory 0.2.20 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/toolnet-memory +71 -0
- package/bundle/agy-hook.js +40 -39
- package/bundle/agy.js +82 -34
- package/bundle/auto-integrate.js +66 -19
- package/bundle/claude-hook.js +73 -0
- package/bundle/claude.js +3 -0
- package/bundle/codex-context.js +19 -19
- package/bundle/codex.js +61 -60
- package/bundle/context-runtime.js +30 -30
- package/bundle/context.js +15 -14
- package/bundle/continuity-certify.js +49 -0
- package/bundle/doctor.js +4 -4
- package/bundle/full-index.js +18 -8
- package/bundle/graph-index.js +4 -4
- package/bundle/handoff-refresh.js +8 -8
- package/bundle/impact.js +3 -3
- package/bundle/incremental.js +4 -4
- package/bundle/init.js +763 -0
- package/bundle/learner.js +5 -5
- package/bundle/mcp.js +17 -15
- package/bundle/memory-agent.js +10 -11
- package/bundle/memory-query.js +7 -7
- package/bundle/opencode.js +54 -53
- package/bundle/production-certify.js +5 -0
- package/bundle/project-manual.js +6 -6
- package/bundle/recovery-certify.js +55 -0
- package/bundle/runtime.js +10 -10
- package/bundle/semantic.js +6 -6
- package/bundle/setup.js +69 -22
- package/bundle/snapshot.js +4 -4
- package/bundle/update.js +4 -1
- package/bundle/work-continuity.js +6 -6
- package/package.json +1 -1
package/bundle/opencode.js
CHANGED
|
@@ -1,26 +1,34 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function
|
|
3
|
-
`,{encoding:"utf8",mode:384}),un(s,r)}function We(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=hn(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>we(X(r,p))),i=gn(n,o?r:void 0);if(i){let p=je(i),u=yn(p);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),Be(i,u)),We(u,i)}let l=new Date().toISOString(),c=dn(r),a={version:1,id:fn(r),name:c,remote:c,rootPath:r,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return Be(r,a),We(a,r)}};var Sn=[{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}],Q=class{scan(e){let n=[];for(let r of Sn){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 Q;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 Bn}from"node:os";import{join as Wn}from"node:path";import{DeleteObjectCommand as vn,GetObjectCommand as bn,HeadObjectCommand as kn,ListObjectsV2Command as wn,PutObjectCommand as jn,S3Client as xn}from"@aws-sdk/client-s3";import{getSignedUrl as En}from"@aws-sdk/s3-request-presigner";var Z=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new xn({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 jn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await En(this.client,new bn({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 kn({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 vn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new wn({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 In,readFile as On,readdir as Pn,rm as Tn,stat as Ve,writeFile as Cn}from"node:fs/promises";import{dirname as Rn,join as Mn,relative as Ue,resolve as An}from"node:path";var V=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return An(this.root,n)}async put(e,n){let r=this.path(e);await In(Rn(r),{recursive:!0}),await Cn(r,n)}async get(e){try{return await On(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 Tn(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 l=await Pn(i,{withFileTypes:!0});for(let c of l){let a=Mn(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 Nn,GetObjectCommand as _n,HeadObjectCommand as $n,ListObjectsV2Command as Ln,PutObjectCommand as Dn,S3Client as Fn}from"@aws-sdk/client-s3";import{getSignedUrl as Kn}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 Fn({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 Dn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await Kn(this.client,new _n({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 $n({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 Nn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new Ln({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??Wn(Bn(),".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 zn(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(l){if(o=l,i>=n)break;let c=Math.min(s,r*2**(i-1)),a=Math.floor(Math.random()*Math.max(1,c*.2));await zn(c+a)}throw o}var qn=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:qn.has(r)?(...o)=>Ye(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Xe(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 Qe(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=Xe(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(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}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=
|
|
5
|
-
`,{encoding:"utf8",mode:384}),
|
|
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
|
|
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),
|
|
1
|
+
import{existsSync as an,readFileSync as cn}from"node:fs";import{homedir as un}from"node:os";import{join as ln}from"node:path";function dn(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 pn(){let t=process.env.TOOLNET_GLOBAL_ENV??ln(un(),".config","toolnet-memory",".env");if(!an(t))return;let e=cn(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]=dn(r.slice(s+1)))}}pn();function q(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function V(t,e){if(!t)return e;let n=Number(t);return Number.isFinite(n)?n:e}function G(){return{memory:{autoCapture:q(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:q(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:q(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:q(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:V(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:V(process.env.MEMORY_RERANK_TOP,10),finalContext:V(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:V(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:q(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:V(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as mn}from"node:crypto";import{existsSync as Ce,mkdirSync as fn,readFileSync as gn,renameSync as yn,writeFileSync as hn}from"node:fs";import{basename as Sn,dirname as Q,join as Z,parse as Je,resolve as J}from"node:path";var He=".toolnet",vn="project.json";function bn(t){return mn("sha256").update(t).digest("hex").slice(0,16)}function Ee(t){return Z(t,He,vn)}function kn(t){return Ce(Ee(t))}function wn(t,e){let n=J(t),r=Je(n).root;for(;;){if(kn(n))return n;if(n===r||e&&n===J(e))break;let s=Q(n);if(s===n)break;n=s}return null}function xn(t){let e=J(t),n=Je(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>Ce(Z(e,o))))return e;if(e===n)break;let s=Q(e);if(s===e)break;e=s}return J(t)}function jn(t){let e;try{e=JSON.parse(gn(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:Q(Q(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 qe(t,e){let n=Z(t,He);fn(n,{recursive:!0});let r=Ee(t),s=`${r}.tmp-${process.pid}`;hn(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),yn(s,r)}function Ve(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 X=class{detect(e=process.cwd()){let n=J(e),r=xn(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>Ce(Z(r,p))),i=wn(n,o?r:void 0);if(i){let p=Ee(i),l=jn(p);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),qe(i,l)),Ve(l,i)}let u=new Date().toISOString(),c=Sn(r),a={version:1,id:bn(r),name:c,remote:c,rootPath:r,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0};return qe(r,a),Ve(a,r)}};var In=[{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}],ee=class{scan(e){let n=[];for(let r of In){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 H=class{scanner=new ee;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 Un}from"node:os";import{join as Yn}from"node:path";import{DeleteObjectCommand as Cn,GetObjectCommand as En,HeadObjectCommand as On,ListObjectsV2Command as Pn,PutObjectCommand as Tn,S3Client as Mn}from"@aws-sdk/client-s3";import{getSignedUrl as Rn}from"@aws-sdk/s3-request-presigner";var te=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Mn({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 Tn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await Rn(this.client,new En({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 On({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 Cn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new Pn({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 Ue,mkdir as An,readFile as Nn,readdir as _n,rm as $n,stat as Ye,writeFile as Ln}from"node:fs/promises";import{dirname as Dn,join as Fn,relative as Ge,resolve as Kn}from"node:path";var U=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return Kn(this.root,n)}async put(e,n){let r=this.path(e);await An(Dn(r),{recursive:!0}),await Ln(r,n)}async get(e){try{return await Nn(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 Ue(this.path(e)),!0}catch{return!1}}async delete(e){await $n(this.path(e),{force:!0})}async list(e=""){let n=this.path(e),r=[];try{await Ue(n)}catch{return r}let s=async i=>{let u=await _n(i,{withFileTypes:!0});for(let c of u){let a=Fn(i,c.name);if(c.isDirectory()){await s(a);continue}let p=await Ye(a);r.push({key:Ge(this.root,a),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await Ye(n);return o.isDirectory()?await s(n):r.push({key:Ge(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as Wn,GetObjectCommand as zn,HeadObjectCommand as Bn,ListObjectsV2Command as qn,PutObjectCommand as Vn,S3Client as Jn}from"@aws-sdk/client-s3";import{getSignedUrl as Hn}from"@aws-sdk/s3-request-presigner";var Y=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Jn({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 Vn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await Hn(this.client,new zn({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 Bn({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 Wn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new qn({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 Oe(t,e){return console.warn(e),new U(t)}function Qe(t){let e=t.localRoot??Yn(Un(),".toolnet-memory","storage");if(t.provider==="r2"){let n=t.r2;return n?.accountId&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new Y({name:"r2",endpoint:`https://${n.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:n.bucket,forcePathStyle:!0,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Oe(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 Y({name:"s3",endpoint:n.endpoint,region:n.region??"us-east-1",bucket:n.bucket,forcePathStyle:n.forcePathStyle??!1,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Oe(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 te({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Oe(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new U(e)}function Gn(t){return new Promise(e=>setTimeout(e,t))}async function Xe(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(u){if(o=u,i>=n)break;let c=Math.min(s,r*2**(i-1)),a=Math.floor(Math.random()*Math.max(1,c*.2));await Gn(c+a)}throw o}var Qn=new Set(["put","get","getText","delete","list"]);function Ze(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:Qn.has(r)?(...o)=>Xe(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function et(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 tt(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 ne=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=et(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(u){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${u instanceof Error?u.message:String(u)}`)}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=tt(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 Ds}from"node:fs";import{execFileSync as Fs}from"node:child_process";import{homedir as Ks}from"node:os";import{isAbsolute as Ws,join as Kt,relative as zs,resolve as Wt}from"node:path";import{DatabaseSync as Bs}from"node:sqlite";import{join as sr}from"node:path";import{createHash as Xn}from"node:crypto";import{dirname as Zn}from"node:path";import{mkdirSync as er,readFileSync as tr,renameSync as nr,writeFileSync as rr}from"node:fs";function v(t){return Xn("sha256").update(t).digest("hex")}function Pe(t){if(Array.isArray(t))return t.map(Pe);if(t&&typeof t=="object"){let e=t,n={};for(let r of Object.keys(e).sort())n[r]=Pe(e[r]);return n}return t}function nt(t){return JSON.stringify(Pe(t))}function rt(t){try{return JSON.parse(tr(t,"utf8"))}catch{return null}}function I(t,e){er(Zn(t),{recursive:!0});let n=`${t}.${process.pid}.tmp`;rr(n,JSON.stringify(e,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),nr(n,t)}function st(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 ot(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=st(r.toLowerCase(),"agent"),i=st(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:sr(t.rootPath,".toolnet","sessions",o,i)}}function it(t){return String(t).padStart(12,"0")}var re=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 u=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!u)continue;let c=Number(u[1]),a=Number(u[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,u)=>i.start-u.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),u=n.filter(g=>g.sequence>i.maxSequence),c=0;for(let g of this.split(u)){let m=g[0],w=g[g.length-1],T=g.map(_=>JSON.stringify(_)).join(`
|
|
8
8
|
`)+`
|
|
9
|
-
|
|
9
|
+
`,D=v(T).slice(0,16),M=[e.remotePrefix,"events",`${it(m.sequence)}-${it(w.sequence)}-${D}.jsonl`].join("/");await this.storage.exists(M)||await this.storage.put(M,T,"application/x-ndjson"),c+=g.length}let a=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 y=new Date().toISOString(),d=n[0],S={version:1,projectId:e.projectId,projectName:e.projectName,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,status:l,createdAt:o?.createdAt??d?.timestamp??y,updatedAt:p?.timestamp??y,firstEventAt:o?.firstEventAt??d?.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 h={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:y};return await this.putJson(`${e.remotePrefix}/cursor.json`,h),await this.putJson(`${e.remotePrefix}/session.json`,S),{uploadedEvents:c,lastRemoteSequence:a.maxSequence,eventCount:S.eventCount,chunkCount:S.chunkCount,status:l}}};import{closeSync as Te,existsSync as or,fsyncSync as ir,mkdirSync as ar,openSync as Me,readSync as cr,rmSync as at,statSync as ct,writeSync as ur}from"node:fs";import{join as Re}from"node:path";var lr=12e4,dr=80,pr=2e3;function mr(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}var se=class{constructor(e){this.identity=e;ar(e.localDirectory,{recursive:!0}),this.eventsFile=Re(e.localDirectory,"events.jsonl"),this.stateFile=Re(e.localDirectory,"state.json"),this.lockFile=Re(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 rt(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(e){I(this.stateFile,e)}acquireLock(){for(let e=0;e<dr;e+=1)try{return Me(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-ct(this.lockFile).mtimeMs>lr){at(this.lockFile,{force:!0});continue}}catch{}mr(25)}throw new Error(`Session journal is locked: ${this.lockFile}`)}withLock(e){let n=this.acquireLock();try{return e()}finally{Te(n),at(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 y=l.timestamp??new Date().toISOString(),d=l.data??{},S=l.provenance?.rawDigest??v(nt(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,y,S].join("|"),g=v(h).slice(0,32);if(r.has(g))continue;s+=1;let m={version:1,id:g,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,type:l.type,timestamp:y,data:d,provenance:{...l.provenance,rawDigest:S}};l.role!==void 0&&(m.role=l.role),l.sourceEventId!==void 0&&(m.sourceEventId=l.sourceEventId),l.sourceSequence!==void 0&&(m.sourceSequence=l.sourceSequence),o.push(m),r.add(g)}if(o.length===0)return[];let i=o.map(l=>JSON.stringify(l)).join(`
|
|
10
10
|
`)+`
|
|
11
|
-
`,
|
|
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
|
|
13
|
-
|
|
14
|
-
`);if(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
`,"
|
|
22
|
-
`);if(
|
|
23
|
-
`).filter(Boolean).flatMap(
|
|
11
|
+
`,u=Me(this.eventsFile,"a",384);try{ur(u,i,null,"utf8"),ir(u)}finally{Te(u)}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(-pr);return this.saveStateUnsafe({...n,status:a,updatedAt:c.timestamp,lastSequence:c.sequence,recentEventIds:p}),o})}readPending(){return this.withLock(()=>{let e=this.loadStateUnsafe();if(!or(this.eventsFile))return{events:[],startOffset:e.remoteByteOffset,endOffset:e.remoteByteOffset};let n=ct(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=Me(this.eventsFile,"r");try{cr(i,o,0,s,r)}finally{Te(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 Wr,existsSync as zr,openSync as Br,readSync as qr,statSync as Vr}from"node:fs";function ut(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 mt=[/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],fr=[/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],gr=[/\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],yr=[/\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],hr=[/đã 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],lt=[/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],Sr=[/\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],vr=[/đườ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],br=[/\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],dt=new Set(["content","text","message","prompt","summary","description","reason","title","last_assistant_message","lastAssistantMessage","input_messages","inputMessages"]),kr=new Set(["payload","data","content","message","messages","parts","summary"]);function C(t,e){return e.some(n=>n.test(t))}function ft(t){return t.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function wr(t){return ft(t).toLowerCase().replace(/[^\p{L}\p{N}:/._-]+/gu," ").replace(/\s+/g," ").trim()}function xr(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 Ae(t,e,n,r=0){if(!(r>6)){if(typeof t=="string"){(!e||dt.has(e))&&n.push(t);return}if(Array.isArray(t)){for(let s of t.slice(0,50))Ae(s,e,n,r+1);return}if(!(!t||typeof t!="object"))for(let[s,o]of Object.entries(t))(dt.has(s)||kr.has(s))&&Ae(o,s,n,r+1)}}function jr(t){let e=[];Ae(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=ft(o);if(xr(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function pt(t){return(t.role??(typeof t.data.role=="string"?t.data.role:"")).toLowerCase()}function Ir(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&&C(t,mt)?{kind:"rule",confidence:.98}:r&&C(t,fr)?{kind:"rule",confidence:.92}:C(t,gr)?{kind:C(t,lt)?"architecture":"decision",confidence:r?.93:.86}:r&&C(t,yr)?{kind:"todo",confidence:.87}:C(t,lt)&&C(t,Sr)?{kind:"architecture",confidence:r?.88:.82}:s&&C(t,hr)?{kind:"fix",confidence:.8}:r&&C(t,vr)&&C(t,br)?{kind:"context",confidence:.79}:null}function Cr(t){switch(t){case"rule":return"rule";case"decision":case"architecture":return"decision";case"todo":return"todo";case"fix":case"context":return"code"}}function Er(t,e,n){return t==="rule"&&C(n,mt)?"critical":t==="architecture"||t==="decision"||t==="rule"?"high":t==="fix"||t==="context"?"normal":ut(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,u=pt(o);i&&u&&s.set(i,u)}for(let o of e){let i=pt(o),u=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&u&&(i=s.get(u)??"");for(let c of jr(o)){let a=Ir(c,i,o);if(!a||a.confidence<.75)continue;let p=Cr(a.kind),l=wr(c),y=v([t.projectId,a.kind,l].join("|"));if(r.has(y))continue;r.add(y);let d=o.provenance.sourcePath?[o.provenance.sourcePath]:[],S=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:y,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,kind:a.kind,type:p,content:c,confidence:a.confidence,importance:Er(a.kind,p,c),tags:[p],provenance:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventIds:[o.id],sourceEventIds:S,sourcePaths:d,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}function oe(t){return t?Math.ceil(t.length/3.5):0}function ie(t,e){if(!t)return"";if(oe(t)<=e)return t;let r=Math.floor(e*3.5),s=t.slice(0,r),o=s.lastIndexOf("."),i=s.lastIndexOf(`
|
|
13
|
+
`),u=Math.max(o,i);return u>r*.7?s.slice(0,u+1):s}function $(){let t=G(),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),u=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:u,archiveRemote:c}}function yt(t){return(t||$()).rawTranscript}function ht(t){return(t||$()).durableMemoryMaxItemsPerSession}function St(t){return(t||$()).sessionSummaryMaxTokens}function vt(t){return(t||$()).archiveRemote}function Or(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 Pr(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 Tr(t,e){let n=[],r=new Set;for(let i of t){let u=i.split(`
|
|
14
|
+
`).filter(c=>c.trim());for(let c of u){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 l="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)?l="rule":/\b(fix|fixed|bug|issue|error|lỗi)\b/i.test(a)?l="fix":/\b(blocker|blocked|stuck|cannot|không thể)\b/i.test(a)?l="blocker":/\b(next|todo|action|task|cần làm)\b/i.test(a)?l="next_action":/\b(deploy|release|publish|ship)\b/i.test(a)?l="deploy":/\b(architecture|design|structure|pattern)\b/i.test(a)?l="architecture":/\.(ts|js|py|go|rs|java|cpp|c|h)\b/i.test(a)&&(l="file");let y=Pr(a,l);if(y<.3)continue;let d=Or(a);n.push({category:l,text:d,importance:y,sourceSessionId:e})}}let s=$(),o=ht(s);return n.sort((i,u)=>u.importance-i.importance).slice(0,o)}function Mr(t){let e=$(),n=St(e),o=t.join(`
|
|
15
|
+
|
|
16
|
+
`).split(`
|
|
17
|
+
`).filter(i=>{let u=i.trim();return u.length>20&&!u.startsWith("npm")&&!u.startsWith("\u2713")&&!u.startsWith("Error:")}).slice(0,20).join(`
|
|
18
|
+
`);return ie(o,n)}function ae(t,e){let r=(Array.isArray(t)?t:t.split(`
|
|
19
|
+
|
|
20
|
+
`).filter(d=>d.trim())).map(d=>typeof d=="string"?d:JSON.stringify(d)).filter(d=>d.trim()),s=Tr(r,e),o=s.filter(d=>d.category==="decision").map(d=>d.text),i=s.filter(d=>d.category==="rule").map(d=>d.text),u=s.filter(d=>d.category==="file").map(d=>d.text),c=s.filter(d=>d.category==="fix").map(d=>d.text),a=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:Mr(r),decisions:o,projectRules:i,filesChanged:u,bugsFixed:c,commands:l,blockers:a,nextActions:p,durableFacts:s}}function R(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 Rr(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 Ar(t){switch(t){case"critical":return 1;case"high":return .85;case"normal":return .6;case"temporary":return .25}}function Nr(t){let e=Ar(t.importance);return Math.max(0,Math.min(1,e*.75+t.confidence*.25))}function _r(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 $r(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 Lr(t){let e=_r(t),n=Nr(t),r=$r(t.content);return{...t,knowledgeClass:e,importanceScore:n,retrievalTerms:r,tags:R([...t.tags,`class:${e}`,`kind:${t.kind}`])}}function Dr(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 Fr(t,e,n){let r=ae(Dr(e),t.nativeSessionId),s=n.filter(a=>a.kind==="todo").map(a=>a.content),o=n.flatMap(a=>a.provenance.sourcePaths),i=n.filter(a=>a.kind==="architecture").map(a=>a.content),u=R([...s,...r.nextActions]),c=R([...r.nextActions,...s]);return{summary:r.summary,state:{task:c[0]??u[0],decisions:R(r.decisions),files:R([...r.filesChanged,...o]),todos:u,completed:R(r.bugsFixed),blockers:R(r.blockers),nextActions:c,architecture:R(i)}}}function bt(t,e){let n=Rr(e),r=gt(t,n).map(Lr),s=r.filter(a=>a.knowledgeClass!=="transient").sort((a,p)=>p.importanceScore-a.importanceScore),{summary:o,state:i}=Fr(t,n,s),u=s.map(a=>({fingerprint:a.fingerprint,kind:a.kind,knowledgeClass:a.knowledgeClass,importanceScore:a.importanceScore,content:a.content,terms:a.retrievalTerms})),c=a=>r.filter(p=>p.knowledgeClass===a).length;return{version:2,normalizedEvents:n,summary:o,state:i,candidates:s,retrievalIndex:u,stats:{inputEvents:e.length,normalizedEvents:n.length,extractedCandidates:r.length,persistedCandidates:s.length,permanent:c("permanent"),task:c("task"),session:c("session"),transient:c("transient")}}}function kt(t){return String(t).padStart(12,"0")}function Kr(t){return t.remotePrefix.replace("/sessions/","/memory/learned/")}var ce=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},u=JSON.stringify(i,null,2)+`
|
|
21
|
+
`,c=v(r.map(p=>p.fingerprint).sort().join("|")).slice(0,16),a=[Kr(e),"batches",`${kt(s)}-${kt(o)}-${c}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,u,"application/json"),a}};function Jr(t,e){if(!zr(t))return{events:[],nextOffset:e};let n=Vr(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=Br(t,"r");try{qr(i,o,0,s,r)}finally{Wr(i)}let u=o.toString("utf8"),c=u.lastIndexOf(`
|
|
22
|
+
`);if(c<0)return{events:[],nextOffset:r};let a=u.slice(0,c+1);return{events:a.split(`
|
|
23
|
+
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var ue=class{constructor(e){this.options=e;this.journal=new ce(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=Jr(this.options.wal.eventsFile,r);if(s.events.length===0)return{scannedEvents:0,candidates:0,journalWritten:!1,nextOffset:s.nextOffset};let o=bt(this.options.identity,s.events),i=o.candidates,u=!1;return i.length>0&&(u=!!await this.journal.write(this.options.identity,s.events,i)),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.learner.offset",s.nextOffset),{scannedEvents:s.events.length,candidates:i.length,journalWritten:u,nextOffset:s.nextOffset}}};import{closeSync as Zr,existsSync as es,openSync as ts,readSync as ns,statSync as rs}from"node:fs";var Hr=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 xt(t){return K(t).toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function F(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))F(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Hr.has(r)||["data","payload","parts","messages"].includes(r))&&F(s,e,n+1)}}function le(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 wt(t){let e=K(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 x(t,e,n,r,s={}){let o=K(r),i=s.key??xt(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 Ur(t,e,n){let r=K(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(x(t,e,"goal",i[1],{confidence:.97}));let u=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);u?.[1]&&s.push(x(t,e,"plan",u[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 y=Number(a[1]),d=K(a[2]??""),S=d&&!wt(d)?`Phase ${y} - ${d}`:`Phase ${y}`;s.push(x(t,e,"phase",S,{key:`phase:${y}`,order:y,status:le(r),confidence:.93}))}let p=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);p?.[2]&&s.push(x(t,e,"task",p[2],{status:p[1].trim()?"completed":le(p[2]),confidence:.96}));let l=r.match(/^(?:todo|task|việc)\s*(\d+)?(?:\s*[:.\-–—]\s*|\s+)(.+)$/iu);if(l?.[2]){let y=l[1]?Number(l[1]):void 0,d=K(l[2]),S=wt(d);s.push(x(t,e,"task",S&&y!==void 0?`TODO ${y}`:d,{key:y!==void 0?`task:${y}`:xt(d),order:y,status:le(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 y=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");y&&s.push(x(t,e,"next_action",y,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(x(t,e,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(x(t,e,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(x(t,e,"decision",r,{confidence:.9})),s}function jt(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=[];F(i.data,c);for(let a of c)s(x(t,i,"decision",a,{confidence:1}))}if(i.type==="todo"){let c=[];F(i.data,c);for(let a of c)s(x(t,i,"task",a,{status:le(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(x(t,i,"file",a,{confidence:1}))}if(i.type==="test"){let c=[];F(i.data,c);for(let a of c)s(x(t,i,"test",a,{confidence:1}))}let u=[];F(i.data,u);for(let c of u)for(let a of c.split(/\n+/u))for(let p of Ur(t,i,a))s(p)}let o=e[e.length-1];return s(x(t,o,"session",`${t.agent}:${t.nativeSessionId}`,{key:t.sessionKey,confidence:1})),n}function It(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(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)+`
|
|
24
|
+
`,u=v(n.map(a=>a.id).sort().join("|")).slice(0,16),c=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${It(r)}-${It(s)}-${u}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,i,"application/json"),c}};import{join as Ct}from"node:path";import{mkdirSync as Yr}from"node:fs";function Gr(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function W(t,e=20){let n=[],r=new Set;for(let s of t.slice().reverse()){let o=Gr(s);if(!(!o||r.has(o))&&(r.add(o),n.push(s),n.length>=e))break}return n.reverse()}function Qr(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 Et(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&&Qr(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 Xr(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,u)=>i.key.localeCompare(u.key))){let i=await e.getText(o.key);if(i)try{let u=JSON.parse(i);u.version===1&&Array.isArray(u.observations)&&s.push(u)}catch{}}return s}async function pe(t,e){let r=(await Xr(t,e)).flatMap(f=>f.observations).sort((f,j)=>{let ze=f.occurredAt.localeCompare(j.occurredAt);if(ze!==0)return ze;let Be=f.sequence-j.sequence;return Be!==0?Be:f.id.localeCompare(j.id)}),s=new Map,o=new Map,i,u,c,a=[],p=[],l=[],y=[],d=[],S=[];for(let f of r)switch(f.kind){case"goal":i=f.text;break;case"plan":u=f.text;break;case"phase":s.set(f.key,Et(s.get(f.key),f));break;case"task":o.set(f.key,Et(o.get(f.key),f));break;case"decision":a.push(f.text);break;case"blocker":p.push(f.text);break;case"warning":l.push(f.text);break;case"next_action":y.push(f.text);break;case"file":d.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 h=Array.from(s.values()).sort((f,j)=>(f.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),g=Array.from(o.values()).sort((f,j)=>(f.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),m=h.find(f=>f.status==="in_progress")??h.find(f=>f.status==="blocked")??h.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"),T=W([...y,...w?[w.title]:[],...!w&&m?[m.title]:[],...g.filter(f=>f.status==="pending").slice(0,5).map(f=>f.title)],8),D=W([...p,...h.filter(f=>f.status==="blocked").map(f=>f.title),...g.filter(f=>f.status==="blocked").map(f=>f.title)],20),M={version:1,projectId:t.id,projectName:t.name,goal:i,plan:u,phases:h,tasks:g,decisions:W(a,20),blockers:D,warnings:W(l,20),nextActions:T,filesTouched:W(d,30),tests:W(S,20),currentPhase:m,currentTask:w,progress:{phasesTotal:h.length,phasesCompleted:h.filter(f=>f.status==="completed").length,tasksTotal:g.length,tasksCompleted:g.filter(f=>f.status==="completed").length,blocked:h.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()},_=Ct(t.rootPath,".toolnet","work");return Yr(_,{recursive:!0}),I(Ct(_,"current.json"),M),await e.put(`projects/${t.id}/work/current.json`,JSON.stringify(M,null,2)+`
|
|
25
|
+
`,"application/json"),M}async function me(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 ss(t,e){if(!es(t))return{events:[],nextOffset:e};let n=rs(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=ts(t,"r");try{ns(i,o,0,s,r)}finally{Zr(i)}let u=o.toString("utf8"),c=u.lastIndexOf(`
|
|
26
|
+
`);if(c<0)return{events:[],nextOffset:r};let a=u.slice(0,c+1);return{events:a.split(`
|
|
27
|
+
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var fe=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.continuity.offset"]??0),r=ss(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=jt(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await pe(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 ms,existsSync as fs,openSync as gs,readSync as ys,statSync as hs}from"node:fs";var os=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function z(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function Ne(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))Ne(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(os.has(r)||["data","payload","parts","messages"].includes(r))&&Ne(s,e,n+1)}}function E(t,e,n,r,s,o=.95){let i=z(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 z(t.slice(r.length+1))}return null}function is(t){let e=t.trimStart();return e.startsWith("- ")||e.startsWith("* ")||/^\d+[.)]\s+/u.test(e)}function as(t){return z(t.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function Ot(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=[];Ne(o.data,i);for(let u of i){let c={type:"project"},a=null;for(let p of u.split(/\r?\n/u)){let l=z(p);if(!l){a=null;continue}let y=l.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(y){let j=Number(y[1]);c={type:"phase",key:`phase:${j}`,order:j,title:z(y[2]??"")},a=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:z(d[2]??"")},a=null;continue}let S=P(l,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(S){s(E(t,o,"mission",S,{type:"project"},.99)),a=null;continue}let h=P(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(E(t,o,c.type==="phase"?"phase_objective":"objective",h,c,.98)),a=null;continue}let g=P(l,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(g){s(E(t,o,c.type==="phase"?"phase_why":"why",g,c,.98)),a=null;continue}let m=P(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(m){s(E(t,o,"desired_outcome",m,{type:"project"},.98)),a=null;continue}let w=P(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(w){s(E(t,o,"plan_rationale",w,{type:"project"},.98)),a=null;continue}let T=P(l,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(T){s(E(t,o,"phase_deliverable",T,c,.97)),a=null;continue}let D=P(l,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if(D){s(E(t,o,"acceptance_criterion",D,c,.98)),a="acceptance_criterion";continue}let M=P(l,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(M){s(E(t,o,"dependency",M,c,.97)),a="dependency";continue}let _=P(l,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(_){s(E(t,o,"open_question",_,c,.95)),a="open_question";continue}let f=P(l,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(f){s(E(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(l)){a="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(l)){a="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(l)){a="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(l)){a="constraint";continue}if(a&&is(p)){s(E(t,o,a,as(p),c,.96));continue}a=null}}}return n}function Pt(t){return String(t).padStart(12,"0")}var ge=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),u=[`projects/${e.projectId}`,"work","semantic","observations",e.agent,e.nativeSessionId,`${Pt(r)}-${Pt(s)}-${i}.json`].join("/");return await this.storage.exists(u)||await this.storage.put(u,JSON.stringify(o,null,2)+`
|
|
28
|
+
`,"application/json"),u}};import{mkdirSync as cs}from"node:fs";import{join as Tt}from"node:path";function us(t){return{value:t.value,confidence:t.confidence,evidence:t.evidence}}function ls(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 A(t,e){return ls(e,t)?e:t}function N(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 ds(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,u)=>i.key.localeCompare(u.key))){let i=await e.getText(o.key);if(i)try{let u=JSON.parse(i);u.version===1&&Array.isArray(u.observations)&&s.push(u)}catch{}}return s}function ps(t){return{key:t.scopeKey??`phase:${t.scopeOrder??0}`,order:t.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function Mt(t,e){let r=(await ds(t,e)).flatMap(h=>h.observations).sort((h,g)=>{let m=h.evidence.occurredAt.localeCompare(g.evidence.occurredAt);return m!==0?m:h.evidence.sessionKey===g.evidence.sessionKey?h.evidence.sequence-g.evidence.sequence:h.id.localeCompare(g.id)}),s,o,i,u,c,a=new Map,p=[],l=[],y=[];for(let h of r){let g=us(h);if(h.scope==="phase"&&h.scopeKey){let m=a.get(h.scopeKey)??ps(h);switch(h.kind){case"phase_objective":m.objective=A(m.objective,g);break;case"phase_why":m.why=A(m.why,g);break;case"phase_deliverable":m.deliverable=A(m.deliverable,g);break;case"acceptance_criterion":m.acceptanceCriteria.push(g);break;case"dependency":m.dependencies.push(g);break;case"open_question":m.openQuestions.push(g);break;case"constraint":m.constraints.push(g);break;case"note":m.notes.push(g);break}a.set(m.key,m);continue}switch(h.kind){case"mission":s=A(s,g);break;case"objective":o=A(o,g);break;case"why":i=A(i,g);break;case"desired_outcome":u=A(u,g);break;case"plan_rationale":c=A(c,g);break;case"open_question":p.push(g);break;case"constraint":l.push(g);break;case"note":y.push(g);break}}for(let h of a.values())h.acceptanceCriteria=N(h.acceptanceCriteria,20),h.dependencies=N(h.dependencies,15),h.openQuestions=N(h.openQuestions,15),h.constraints=N(h.constraints,15),h.notes=N(h.notes,20);let d={version:1,projectId:t.id,projectName:t.name,mission:s,activeObjective:o,why:i,desiredOutcome:u,planRationale:c,phases:Array.from(a.values()).sort((h,g)=>h.order-g.order),openQuestions:N(p,20),constraints:N(l,20),notes:N(y,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},S=Tt(t.rootPath,".toolnet","work");return cs(S,{recursive:!0}),I(Tt(S,"semantic-current.json"),d),await e.put(`projects/${t.id}/work/semantic/current.json`,JSON.stringify(d,null,2)+`
|
|
29
|
+
`,"application/json"),d}async function Rt(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 Ss(t,e){if(!fs(t))return{events:[],nextOffset:e};let n=hs(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=gs(t,"r");try{ys(o,s,0,s.length,r)}finally{ms(o)}let i=s.toString("utf8"),u=i.lastIndexOf(`
|
|
30
|
+
`);if(u<0)return{events:[],nextOffset:r};let c=i.slice(0,u+1);return{events:c.split(`
|
|
31
|
+
`).filter(Boolean).flatMap(a=>{try{return[JSON.parse(a)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var ye=class{constructor(e){this.options=e;this.journal=new ge(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.semantic.offset"]??0),r=Ss(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=Ot(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await Mt(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 Ts}from"node:fs";import{join as _e}from"node:path";import{existsSync as _t,mkdirSync as vs,readFileSync as bs,statSync as At,writeFileSync as ks}from"node:fs";import{dirname as ws,join as xs}from"node:path";var Nt=64*1024,js=`# ToolNet Project Operating Manual
|
|
24
32
|
|
|
25
33
|
This file contains persistent instructions for AI agents working on this project.
|
|
26
34
|
|
|
@@ -63,37 +71,30 @@ Things an AI agent should always remember.
|
|
|
63
71
|
<!--
|
|
64
72
|
- [advisory] Prefer small focused files.
|
|
65
73
|
-->
|
|
66
|
-
`;function
|
|
67
|
-
|
|
68
|
-
`,"application/json")
|
|
69
|
-
|
|
70
|
-
`).filter(c=>c.trim());for(let c of l){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=vs(a,u);if(m<.3)continue;let d=Ss(a);n.push({category:u,text:d,importance:m,sourceSessionId:e})}}let s=N(),o=Rt(s);return n.sort((i,l)=>l.importance-i.importance).slice(0,o)}function ks(t){let e=N(),n=Mt(e),o=t.join(`
|
|
71
|
-
|
|
72
|
-
`).split(`
|
|
73
|
-
`).filter(i=>{let l=i.trim();return l.length>20&&!l.startsWith("npm")&&!l.startsWith("\u2713")&&!l.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(d=>d.trim())).map(d=>typeof d=="string"?d:JSON.stringify(d)).filter(d=>d.trim()),s=bs(r,e),o=s.filter(d=>d.category==="decision").map(d=>d.text),i=s.filter(d=>d.category==="rule").map(d=>d.text),l=s.filter(d=>d.category==="file").map(d=>d.text),c=s.filter(d=>d.category==="fix").map(d=>d.text),a=s.filter(d=>d.category==="blocker").map(d=>d.text),p=s.filter(d=>d.category==="next_action").map(d=>d.text),u=s.filter(d=>d.category==="deploy").map(d=>d.text);return{summary:ks(r),decisions:o,projectRules:i,filesChanged:l,bugsFixed:c,commands:u,blockers:a,nextActions:p,durableFacts:s}}function Bt(){try{let e=js("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??_t(xs(),".local","share");return _t(t,"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 B(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=Is(n,r);return s!==""&&s!==".."&&!s.startsWith(`..${process.platform==="win32"?"\\":"/"}`)&&!Es(s)}function Lt(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 Dt(t){return JSON.stringify(t)}function Wt(t){if(!ws(t))throw new Error(`OpenCode database not found: ${t}`);let e=new Os(t,{readOnly:!0});return e.exec("PRAGMA query_only = ON"),e.exec("PRAGMA busy_timeout = 3000"),e}function Ps(t,e){let n=t.prepare(`
|
|
74
|
+
`;function he(t){return xs(t.rootPath,".toolnet","PROJECT.md")}function Is(t){return t.normalize("NFKC").replace(/\s+/g," ").trim()}function Cs(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=Is(s[2]);if(!i)continue;let u=`${o}:${i.toLowerCase()}`;n.has(u)||(n.add(u),e.push({id:v(u).slice(0,24),mode:o,text:i,source:"manual"}))}return e}function Es(t){let e=he(t);return _t(e)||(vs(ws(e),{recursive:!0}),ks(e,js,{encoding:"utf8",mode:384})),e}function Se(t,e=!1){let n=e?Es(t):he(t);if(!_t(n))return null;if(At(n).size>Nt)throw new Error(`PROJECT.md exceeds ${Nt} bytes`);let s=bs(n,"utf8");return{path:n,content:s,digest:v(s),rules:Cs(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(At(n).mtimeMs).toISOString()}}function O(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 $t(t){if(t)return{id:t.id,title:t.title,status:t.status}}function Os(t){let e=t.slice(-10).join(`
|
|
75
|
+
`).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(e)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(e)?"passing":"unknown"}function Ps(t){return v(JSON.stringify(t))}function Lt(t){let{project:e,identity:n,state:r}=t,s=r.filesTouched.at(-1),o=r.phases.filter(m=>m.status==="completed").map(m=>m.title),i=r.tasks.filter(m=>m.status==="completed").map(m=>m.title),u=r.phases.filter(m=>m.status!=="completed"&&m.status!=="cancelled").map(m=>m.title),c=r.tasks.filter(m=>m.status!=="completed"&&m.status!=="cancelled").map(m=>m.title),a=O(r.nextActions,10),p=O([...c,...a],15),l=O(r.tests.slice().reverse(),10),y=O(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:$t(r.currentPhase),task:$t(r.currentTask),file:s},completed:{phases:O(o,20),tasks:O(i,30)},remaining:{phases:O(u,20),tasks:O(c,30),todos:p},nextAction:a[0],blockers:O(r.blockers.slice().reverse(),10),decisions:O(r.decisions.slice().reverse(),10),files:{current:s,recent:y},tests:{status:Os(r.tests),recent:l},attention:O(t.attention??[],20),progress:r.progress},{capturedAt:S,source:h,...g}=d;return{...d,stateDigest:Ps(g)}}function Ms(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 ve=class{constructor(e){this.options=e}options;async capture(e,n){let r=await me(this.options.project,this.options.storage);if(r||(r=await pe(this.options.project,this.options.storage)),!Ms(r))return null;let s=Se(this.options.project,!1),i=[...s?s.rules.filter(S=>S.mode==="enforce").map(S=>S.text):[],...r.warnings].slice(0,20),u=Lt({project:this.options.project,identity:this.options.identity,state:r,reason:e,sequence:n,attention:i}),c=u.stateDigest,a=v([this.options.project.id,this.options.identity.sessionKey,c].join("|")).slice(0,24),p=new Date().toISOString(),l={version:1,id:a,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(S=>S.status!=="completed"&&S.status!=="cancelled"),incompleteTasks:r.tasks.filter(S=>S.status!=="completed"&&S.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:u},y=`projects/${this.options.project.id}/work/handoffs/${a}.json`;await this.options.storage.exists(y)||await this.options.storage.put(y,JSON.stringify(l,null,2)+`
|
|
76
|
+
`,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(l,null,2)+`
|
|
77
|
+
`,"application/json");let d=_e(this.options.project.rootPath,".toolnet","work","handoffs");return Ts(d,{recursive:!0}),I(_e(d,`${a}.json`),l),I(_e(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),l),l}};async function Dt(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 be=class{identity;wal;remote;sanitizer=new H;learner;continuity;semantic;handoff;title;metadata;constructor(e){this.identity=ot(e.project,e.agent,e.nativeSessionId),this.title=e.title,this.metadata=this.sanitizer.sanitizeValue(e.metadata??{}),this.wal=new se(this.identity),this.remote=new re(e.storage,e.maxEventsPerChunk??100,e.maxChunkBytes??512*1024),this.learner=new ue({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.continuity=new fe({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.semantic=new ye({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.handoff=new ve({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 Rs=[/^<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*$/],As=[/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],Ns=["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 _s(t){let e=t.toLowerCase();return Ns.some(n=>e.includes(n))}function $s(t){if(!t.trim())return!0;for(let e of Rs)if(e.test(t))return!0;return _s(t),!1}function Ls(t){let e=t;for(let n of As)e=e.replace(n,r=>{let s=r.split(/[:\s=]+/);return s.length>1?`${s[0]}: [REDACTED]`:"[REDACTED]"});return e}function $e(t){let e=t.trim();return e?$s(e)?{content:"",filtered:!0,reason:"noise"}:{content:Ls(e),filtered:!1}:{content:"",filtered:!0,reason:"empty"}}function ke(t){let e={};for(let[n,r]of Object.entries(t))if(typeof r=="string"){let s=$e(r);s.filtered||(e[n]=s.content)}else r&&typeof r=="object"&&!Array.isArray(r)?e[n]=ke(r):Array.isArray(r)?e[n]=r.map(s=>{if(typeof s=="string"){let o=$e(s);return o.filtered?null:o.content}return s&&typeof s=="object"?ke(s):s}).filter(s=>s!==null):e[n]=r;return e}function Ft(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&&$e(r).filtered)return!0}return!1}function Jt(){try{let e=Fs("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??Kt(Ks(),".local","share");return Kt(t,"opencode","opencode.db")}function k(t){return typeof t=="string"?t:""}function L(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 Le(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 B(t){let e=L(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 we(t,e){if(!e)return!1;let n=Wt(t),r=Wt(e);if(n===r)return!0;let s=zs(n,r);return s!==""&&s!==".."&&!s.startsWith(`..${process.platform==="win32"?"\\":"/"}`)&&!Ws(s)}function zt(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 Bt(t){return JSON.stringify(t)}function Ht(t){if(!Ds(t))throw new Error(`OpenCode database not found: ${t}`);let e=new Bs(t,{readOnly:!0});return e.exec("PRAGMA query_only = ON"),e.exec("PRAGMA busy_timeout = 3000"),e}function qs(t,e){let n=t.prepare(`
|
|
77
78
|
SELECT *
|
|
78
79
|
FROM "session"
|
|
79
80
|
WHERE id = ?
|
|
80
81
|
LIMIT 1
|
|
81
|
-
`).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function
|
|
82
|
+
`).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function Ut(t,e,n){let r=k(e.directory);if(r&&we(n.rootPath,r))return!0;let s=k(e.project_id);if(s){try{let o=t.prepare(`
|
|
82
83
|
SELECT *
|
|
83
84
|
FROM "project"
|
|
84
85
|
WHERE id = ?
|
|
85
86
|
LIMIT 1
|
|
86
|
-
`).get(s);if(o)for(let i of["worktree","directory","path"]){let
|
|
87
|
+
`).get(s);if(o)for(let i of["worktree","directory","path"]){let u=k(o[i]);if(u&&we(n.rootPath,u))return!0}}catch{}try{if(t.prepare(`
|
|
87
88
|
SELECT directory
|
|
88
89
|
FROM "project_directory"
|
|
89
90
|
WHERE project_id = ?
|
|
90
|
-
`).all(s).some(i=>
|
|
91
|
+
`).all(s).some(i=>we(n.rootPath,k(i.directory))))return!0}catch{}}try{let o=t.prepare(`
|
|
91
92
|
SELECT data
|
|
92
93
|
FROM "message"
|
|
93
94
|
WHERE session_id = ?
|
|
94
95
|
ORDER BY time_created DESC
|
|
95
96
|
LIMIT 20
|
|
96
|
-
`).all(k(e.id));for(let i of o){let
|
|
97
|
+
`).all(k(e.id));for(let i of o){let u=Le(i.data),c=u.path&&typeof u.path=="object"?u.path:{};for(let a of[k(c.cwd),k(c.root)])if(a&&we(n.rootPath,a))return!0}}catch{}return!1}function qt(t,e,n,r){let s=`
|
|
97
98
|
SELECT *,
|
|
98
99
|
COALESCE(
|
|
99
100
|
time_updated,
|
|
@@ -124,10 +125,10 @@ Things an AI agent should always remember.
|
|
|
124
125
|
0
|
|
125
126
|
) ASC,
|
|
126
127
|
id ASC
|
|
127
|
-
`;return t.prepare(s).all(n,r.time,r.time,r.id)}function
|
|
128
|
+
`;return t.prepare(s).all(n,r.time,r.time,r.id)}function Vt(t,e){let n=t[t.length-1];return n?{time:L(n.__clock),id:k(n.id)}:e}function Vs(t,e){let n=Le(e.data),r=k(n.role),s=L(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:B(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 Js(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,`
|
|
128
129
|
`),o=500;n.outputSummary=s.length<=o?s:`${s.slice(0,350)}
|
|
129
130
|
...[ToolNet truncated ${s.length-o} chars]...
|
|
130
|
-
${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
|
|
131
|
+
${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 Hs(t,e){let n=Le(e.data),r=k(n.type),s=L(e.__clock),o=k(e.id),i=k(e.message_id),u="message_part";return r==="tool"?u="tool_call":r==="snapshot"&&(u="artifact"),{clock:s,order:1,event:{type:u,timestamp:B(s),sourceEventId:`part:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{partId:o,messageId:i,...r==="tool"?Js(n):n},provenance:{source:"opencode",sourcePath:t,sourceTable:"part",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}async function De(t){let e=t.dbPath??Jt(),n=Ht(e);try{let r=qs(n,t.nativeSessionId);if(!Ut(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 be({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=zt(o.sourceCursors["opencode.message"]),u=zt(o.sourceCursors["opencode.part"]),c=qt(n,"message",t.nativeSessionId,i),a=qt(n,"part",t.nativeSessionId,u),p=[];if(o.lastSequence===0){let m=L(r.time_created);p.push({clock:m,order:-1,event:{type:"session_start",timestamp:B(m),sourceEventId:`session:${t.nativeSessionId}:created:${m}`,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(m=>Vs(e,m))),p.push(...a.map(m=>Hs(e,m)));let l=L(r.time_updated)||L(r.time_created);t.compacted&&p.push({clock:l,order:98,event:{type:"session_compact",timestamp:B(l),sourceEventId:`session:${t.nativeSessionId}:compact:${l}`,data:{},provenance:{source:"opencode"}}}),t.error?p.push({clock:l,order:99,event:{type:"error",timestamp:B(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:B(l),sourceEventId:`session:${t.nativeSessionId}:idle:${l}`,data:{},provenance:{source:"opencode"}}}),p.sort((m,w)=>m.clock-w.clock||m.order-w.order);let y=p.filter(m=>!Ft(m.event.data)).map(m=>({...m,event:{...m.event,data:ke(m.event.data)}})),d=s.recordMany(y.map(m=>m.event)),S=Vt(c,i),h=Vt(a,u);if(s.setSourceCursor("opencode.message",Bt(S)),s.setSourceCursor("opencode.part",Bt(h)),t.idle&&y.length>0)try{let m=y.map(T=>JSON.stringify(T.event.data)),w=ae(m,t.nativeSessionId);s.setSourceCursor("opencode.session.summary",w.summary),s.setSourceCursor("opencode.session.facts_count",w.durableFacts.length),yt()&&!vt()&&s.setSourceCursor("opencode.raw_transcript.archived","local")}catch{}let g=await s.flush();return{nativeSessionId:t.nativeSessionId,importedMessages:c.length,importedParts:a.length,recordedEvents:d.length,eventCount:g.eventCount,chunkCount:g.chunkCount,status:g.status}}finally{n.close()}}async function Yt(t){let e=t.dbPath??Jt(),n=Ht(e),r=[];try{let o=n.prepare(`
|
|
131
132
|
SELECT *
|
|
132
133
|
FROM "session"
|
|
133
134
|
ORDER BY
|
|
@@ -136,11 +137,11 @@ ${s.slice(-150)}`,delete n.output}else r!==void 0&&(n.outputSummary="[non-text t
|
|
|
136
137
|
time_created,
|
|
137
138
|
0
|
|
138
139
|
) DESC
|
|
139
|
-
`).all();for(let i of o){if(!
|
|
140
|
+
`).all();for(let i of o){if(!Ut(n,i,t.project))continue;let u=k(i.id);if(u&&r.push(u),r.length>=(t.limit??100))break}}finally{n.close()}let s=[];for(let o of r)s.push(await De({project:t.project,storage:t.storage,nativeSessionId:o,dbPath:e}));return s}import{existsSync as Gs,mkdirSync as en,readFileSync as Qs,writeFileSync as tn}from"node:fs";import{join as Xs}from"node:path";import{homedir as Us}from"node:os";import{join as xe}from"node:path";function je(t={}){let e=t.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return e?xe(e,"opencode"):xe(t.home??Us(),".config","opencode")}function Gt(t={}){return xe(je(t),"plugins")}function Qt(t={}){return xe(je(t),"AGENTS.md")}var Ys="memory_agent_ask";function Xt(){return`
|
|
140
141
|
[TOOLNET MEMORY AGENT]
|
|
141
142
|
|
|
142
143
|
Tool available:
|
|
143
|
-
- ${
|
|
144
|
+
- ${Ys}
|
|
144
145
|
|
|
145
146
|
Use it automatically BEFORE guessing when:
|
|
146
147
|
|
|
@@ -187,7 +188,7 @@ Rules:
|
|
|
187
188
|
- After receiving the ToolNet answer, continue the task
|
|
188
189
|
instead of asking the user to repeat known context.
|
|
189
190
|
- If ToolNet says information is not recorded, say so.
|
|
190
|
-
`.trim()}var
|
|
191
|
+
`.trim()}var Zt="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",Fe="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function Zs(){let t=Qt();en(je(),{recursive:!0});let e=`${Zt}
|
|
191
192
|
## ToolNet Memory
|
|
192
193
|
|
|
193
194
|
ToolNet Memory is available for projects that already contain a valid \`.toolnet/project.json\`.
|
|
@@ -203,12 +204,12 @@ Rules:
|
|
|
203
204
|
7. Current repository evidence has priority over stale memory when they conflict.
|
|
204
205
|
|
|
205
206
|
|
|
206
|
-
${
|
|
207
|
+
${Xt()}
|
|
207
208
|
|
|
208
|
-
${
|
|
209
|
+
${Fe}`,n=Gs(t)?Qs(t,"utf8"):"",r=n.indexOf(Zt),s=n.indexOf(Fe);return r>=0&&s>=r?n=n.slice(0,r)+e+n.slice(s+Fe.length):(n=n.trimEnd(),n&&(n+=`
|
|
209
210
|
|
|
210
|
-
`),n+=e),
|
|
211
|
-
`,{encoding:"utf8",mode:384}),t}function
|
|
211
|
+
`),n+=e),tn(t,n.trimEnd()+`
|
|
212
|
+
`,{encoding:"utf8",mode:384}),t}function nn(t={}){let e=t.directory??Gt();en(e,{recursive:!0}),Zs();let n=Xs(e,"toolnet-memory.js"),r=t.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`
|
|
212
213
|
// Generated by ToolNet Memory.
|
|
213
214
|
// OpenCode integration:
|
|
214
215
|
// - project gated
|
|
@@ -836,20 +837,20 @@ export const ToolNetMemoryPlugin =
|
|
|
836
837
|
},
|
|
837
838
|
}
|
|
838
839
|
}
|
|
839
|
-
`;return
|
|
840
|
-
`);if(
|
|
841
|
-
`)),i=Math.max(0,e-o);if(i>=16){let
|
|
842
|
-
`).trim()}async function
|
|
840
|
+
`;return tn(n,s.trimStart(),{encoding:"utf8",mode:384}),n}import{existsSync as fu,mkdirSync as ro,readFileSync as gu,writeFileSync as so}from"node:fs";import{dirname as oo,join as sn}from"node:path";function Ke(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 eo(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 to(t){let e=[],n=[];for(let r of t.split(/\\r?\\n/u)){let s=r.trim(),o=s.toLowerCase(),u=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(a=>o.startsWith(a));if(!u)continue;let c=s.slice(u.length).trim();c&&(u.includes("enforce")?e.push(c):n.push(c))}return{enforce:e,advisory:n}}function no(t,e){let n=[];for(let r of t){let s=[...n,r].join(`
|
|
841
|
+
`);if(Ke(s)<=e){n.push(r);continue}let o=Ke(n.join(`
|
|
842
|
+
`)),i=Math.max(0,e-o);if(i>=16){let u=Math.floor(i*3.2),c=b(r,u);c&&n.push(c)}break}return n.join(`
|
|
843
|
+
`).trim()}async function rn(t){let e=Math.max(256,Math.min(2e3,t.maxTokens??1e3)),n=Se(t.project,!1),r=n?.content??"";r||(r=await t.storage.getText(`projects/${t.project.id}/project/manual.md`)??"");let s=to(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,u=r?eo(r):[],c=await me(t.project,t.storage),a=await Rt(t.project,t.storage),p=await Dt(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: ${he(t.project)}`),o.length){l.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let d of o.slice(0,24))l.push(`- [ENFORCE] ${b(d,240)}`)}if(i.length){l.push("","PROJECT PREFERENCES");for(let d of i.slice(0,10))l.push(`- ${b(d,220)}`)}if(a&&(a.mission&&l.push("","MISSION",b(a.mission.value,420)),a.activeObjective&&l.push("","CURRENT OBJECTIVE",b(a.activeObjective.value,420)),a.why&&l.push("","WHY THIS WORK MATTERS",b(a.why.value,420)),a.desiredOutcome&&l.push("","DESIRED OUTCOME",b(a.desiredOutcome.value,420)),a.planRationale&&l.push("","WHY THIS APPROACH",b(a.planRationale.value,420))),c){if(l.push("","ACTIVE WORK"),c.goal&&l.push(`Goal: ${b(c.goal,320)}`),c.plan&&l.push(`Plan: ${b(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&&a){let d=a.phases.find(S=>S.order===c.currentPhase?.order);d&&(d.objective&&l.push(`Phase objective: ${b(d.objective.value,340)}`),d.why?l.push(`Why this phase: ${b(d.why.value,340)}`):l.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),d.deliverable&&l.push(`Deliverable: ${b(d.deliverable.value,340)}`),d.dependencies.length&&l.push(`Depends on: ${d.dependencies.slice(0,4).map(S=>b(S.value,180)).join("; ")}`),d.acceptanceCriteria.length&&(l.push("","DEFINITION OF DONE"),d.acceptanceCriteria.slice(0,6).forEach(S=>{l.push(`- ${b(S.value,260)}`)})),d.openQuestions.length&&(l.push("","OPEN QUESTIONS FOR CURRENT PHASE"),d.openQuestions.slice(0,4).forEach(S=>{l.push(`- ${b(S.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,S)=>{l.push(`${S+1}. ${b(d,260)}`)})),c.blockers.length&&(l.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(d=>{l.push(`- ${b(d,260)}`)})),c.warnings.length&&(l.push("","ATTENTION"),c.warnings.slice(-5).forEach(d=>{l.push(`- ${b(d,260)}`)})),c.decisions.length&&(l.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(d=>{l.push(`- ${b(d,260)}`)})),c.lastSession&&l.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(a&&a.openQuestions.length&&(l.push("","UNRESOLVED QUESTIONS"),a.openQuestions.slice(0,5).forEach(d=>{l.push(`- ${b(d.value,260)}`)})),p&&l.push(`Latest handoff: ${p.reason} / ${p.sourceSession.agent}`),u.length){l.push("","OPERATING NOTES");for(let d of u)l.push(`- ${d}`)}l.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let y=no(l,e);return{version:1,projectId:t.project.id,projectName:t.project.name,text:y,estimatedTokens:Ke(y),maxTokens:e,hasManual:!!r,hasWorkState:!!c,hasHandoff:!!p,generatedAt:new Date().toISOString()}}function io(t){return sn(t.rootPath,".toolnet","context","startup.md")}function ao(t){return sn(t.rootPath,".toolnet","context","startup.json")}function co(t,e){let n=io(t);ro(oo(n),{recursive:!0}),so(n,e.text.endsWith(`
|
|
843
844
|
`)?e.text:e.text+`
|
|
844
|
-
`,{encoding:"utf8",mode:384}),
|
|
845
|
+
`,{encoding:"utf8",mode:384}),I(ao(t),e)}async function on(t,e,n=800){let s=(await rn({project:t,storage:e,maxTokens:n})).text;oe(s)>n&&(s=ie(s,n),s+=`
|
|
845
846
|
|
|
846
847
|
[Context trimmed by ToolNet Memory token budget]
|
|
847
|
-
`);let i={version:1,projectId:t.id,projectName:t.name,text:s,digest:v(s),estimatedTokens:
|
|
848
|
+
`);let i={version:1,projectId:t.id,projectName:t.name,text:s,digest:v(s),estimatedTokens:oe(s),generatedAt:new Date().toISOString()};return co(t,i),await e.put(`projects/${t.id}/context/startup.md`,i.text+`
|
|
848
849
|
`,"text/markdown"),await e.put(`projects/${t.id}/context/startup.json`,JSON.stringify(i,null,2)+`
|
|
849
|
-
`,"application/json"),i}function
|
|
850
|
+
`,"application/json"),i}function Ie(t,e){let n=t.indexOf(e);if(!(n<0))return t[n+1]}function We(t,e){return t.includes(e)}function uo(t){let e=G(),n=Ze(Qe({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new ne(n,t.id,t.name,t.remote??t.name)}async function lo(){let[t="help",...e]=process.argv.slice(2);if(t==="install-plugin"){let i=nn({binary:Ie(e,"--bin")});console.log(`\u2705 OpenCode plugin installed: ${i}`),console.log("OpenCode will load it automatically on next start.");return}let n=Ie(e,"--project")??process.cwd(),r=new X().detect(n),s=uo(r),o=Ie(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 u=We(e,"--idle"),c=We(e,"--error"),a=We(e,"--compacted"),p=await De({project:r,storage:s,nativeSessionId:i,dbPath:o,idle:u,error:c,compacted:a});if(u||a||c)try{await on(r,s,800)}catch{}console.log(JSON.stringify(p,null,2));return}if(t==="recover"){let i=Ie(e,"--limit"),u=i?Number(i):100,c=await Yt({project:r,storage:s,dbPath:o,limit:Number.isFinite(u)?u: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
|
|
850
851
|
|
|
851
852
|
Commands:
|
|
852
853
|
sync <session-id> [--project PATH] [--idle]
|
|
853
854
|
recover [--project PATH] [--limit N]
|
|
854
855
|
install-plugin [--bin PATH]
|
|
855
|
-
`)}
|
|
856
|
+
`)}lo().catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});
|