toolnet-memory 0.2.21 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +9 -0
- package/bin/toolnet-memory +5 -0
- package/bundle/agy-hook.js +66 -46
- package/bundle/agy.js +61 -43
- package/bundle/api.js +52 -0
- package/bundle/claude-hook.js +37 -32
- package/bundle/codex-context.js +29 -24
- package/bundle/codex.js +78 -60
- package/bundle/context-runtime.js +38 -33
- package/bundle/handoff-refresh.js +10 -10
- package/bundle/mcp.js +18 -16
- package/bundle/memory-agent.js +8 -8
- package/bundle/memory-query.js +6 -6
- package/bundle/opencode.js +69 -51
- package/bundle/runtime.js +11 -11
- package/dist/sdk/public.d.ts +2 -0
- package/dist/sdk/public.js +2 -0
- package/dist/sdk/remote-client.d.ts +41 -0
- package/dist/sdk/remote-client.js +185 -0
- package/dist/sdk/types.d.ts +402 -0
- package/dist/sdk/types.js +1 -0
- package/package.json +14 -5
package/bundle/opencode.js
CHANGED
|
@@ -1,34 +1,52 @@
|
|
|
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}),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=
|
|
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 Ar,readFileSync as Er}from"node:fs";import{homedir as Pr}from"node:os";import{join as Mr}from"node:path";function Tr(t){let e=t.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Or(){let t=process.env.TOOLNET_GLOBAL_ENV??Mr(Pr(),".config","toolnet-memory",".env");if(!Ar(t))return;let e=Er(t,"utf8");for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Tr(r.slice(s+1)))}}Or();function X(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function Q(t,e){if(!t)return e;let n=Number(t);return Number.isFinite(n)?n:e}function pe(){return{memory:{autoCapture:X(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:X(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:X(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:X(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:Q(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:Q(process.env.MEMORY_RERANK_TOP,10),finalContext:Q(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:Q(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:X(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:Q(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Rr}from"node:crypto";import{existsSync as Ye,mkdirSync as Nr,readFileSync as _r,renameSync as $r,writeFileSync as Kr}from"node:fs";import{basename as Lr,dirname as me,join as ge,parse as Ct,resolve as Z}from"node:path";var It=".toolnet",Dr="project.json";function Wr(t){return Rr("sha256").update(t).digest("hex").slice(0,16)}function Xe(t){return ge(t,It,Dr)}function Fr(t){return Ye(Xe(t))}function zr(t,e){let n=Z(t),r=Ct(n).root;for(;;){if(Fr(n))return n;if(n===r||e&&n===Z(e))break;let s=me(n);if(s===n)break;n=s}return null}function Br(t){let e=Z(t),n=Ct(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>Ye(ge(e,o))))return e;if(e===n)break;let s=me(e);if(s===e)break;e=s}return Z(t)}function Vr(t){let e;try{e=JSON.parse(_r(t,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${t}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${t}`);let n=e;if(typeof n.id!="string"||!n.id.trim())throw new Error(`ToolNet project manifest is missing id: ${t}`);if(typeof n.name!="string"||!n.name.trim())throw new Error(`ToolNet project manifest is missing name: ${t}`);let r=new Date().toISOString();return{version:1,id:n.id,name:n.name,remote:typeof n.remote=="string"&&n.remote.trim()?n.remote:n.name,rootPath:typeof n.rootPath=="string"?n.rootPath:me(me(t)),createdAt:typeof n.createdAt=="string"?n.createdAt:r,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:r,graphVersion:typeof n.graphVersion=="number"?n.graphVersion:0,memoryVersion:typeof n.memoryVersion=="number"?n.memoryVersion:0,metadata:n.metadata&&typeof n.metadata=="object"?n.metadata:void 0}}function xt(t,e){let n=ge(t,It);Nr(n,{recursive:!0});let r=Xe(t),s=`${r}.tmp-${process.pid}`;Kr(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),$r(s,r)}function jt(t,e){return{id:t.id,name:t.name,remote:t.remote,rootPath:e,createdAt:t.createdAt,updatedAt:t.updatedAt,graphVersion:t.graphVersion,memoryVersion:t.memoryVersion,metadata:t.metadata}}var fe=class{detect(e=process.cwd()){let n=Z(e),r=Br(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>Ye(ge(r,p))),i=zr(n,o?r:void 0);if(i){let p=Xe(i),l=Vr(p);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),xt(i,l)),jt(l,i)}let a=new Date().toISOString(),c=Lr(r),u={version:1,id:Wr(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return xt(r,u),jt(u,r)}};var qr=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],ye=class{scan(e){let n=[];for(let r of qr){let s=new RegExp(r.regex.source,r.regex.flags);for(let o of e.matchAll(s))n.push({type:r.type,value:o[0]})}return n}hasSecrets(e){return this.scan(e).length>0}};var ee=class{scanner=new ye;sanitize(e){let n=e,r=this.scanner.scan(e),s=new Set;for(let o of r)s.add(o.type),n=n.split(o.value).join(`[REDACTED:${o.type}]`);return{text:n,redacted:r.length,secretTypes:[...s]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(n=>this.sanitizeValue(n));if(e&&typeof e=="object"){let n={};for(let[r,s]of Object.entries(e)){let o=r.toLowerCase();o.includes("password")||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")?n[r]="[REDACTED]":n[r]=this.sanitizeValue(s)}return n}return e}};import{homedir as fs}from"node:os";import{join as gs}from"node:path";import{DeleteObjectCommand as Jr,GetObjectCommand as Hr,HeadObjectCommand as Gr,ListObjectsV2Command as Ur,PutObjectCommand as Yr,S3Client as Xr}from"@aws-sdk/client-s3";import{getSignedUrl as Qr}from"@aws-sdk/s3-request-presigner";var he=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Xr({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new Yr({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await Qr(this.client,new Hr({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new Gr({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new Jr({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new Ur({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};import{access as At,mkdir as Zr,readFile as es,readdir as ts,rm as ns,stat as Et,writeFile as rs}from"node:fs/promises";import{dirname as ss,join as os,relative as Pt,resolve as is}from"node:path";var te=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return is(this.root,n)}async put(e,n){let r=this.path(e);await Zr(ss(r),{recursive:!0}),await rs(r,n)}async get(e){try{return await es(this.path(e))}catch(n){if(typeof n=="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return null;throw n}}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await At(this.path(e)),!0}catch{return!1}}async delete(e){await ns(this.path(e),{force:!0})}async list(e=""){let n=this.path(e),r=[];try{await At(n)}catch{return r}let s=async i=>{let a=await ts(i,{withFileTypes:!0});for(let c of a){let u=os(i,c.name);if(c.isDirectory()){await s(u);continue}let p=await Et(u);r.push({key:Pt(this.root,u),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await Et(n);return o.isDirectory()?await s(n):r.push({key:Pt(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as as,GetObjectCommand as cs,HeadObjectCommand as us,ListObjectsV2Command as ls,PutObjectCommand as ds,S3Client as ps}from"@aws-sdk/client-s3";import{getSignedUrl as ms}from"@aws-sdk/s3-request-presigner";var ne=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ps({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new ds({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await ms(this.client,new cs({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new us({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new as({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new ls({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};function Qe(t,e){return console.warn(e),new te(t)}function Mt(t){let e=t.localRoot??gs(fs(),".toolnet-memory","storage");if(t.provider==="r2"){let n=t.r2;return n?.accountId&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new ne({name:"r2",endpoint:`https://${n.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:n.bucket,forcePathStyle:!0,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Qe(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(t.provider==="s3"){let n=t.s3;return n?.bucket&&n.accessKeyId&&n.secretAccessKey?new ne({name:"s3",endpoint:n.endpoint,region:n.region??"us-east-1",bucket:n.bucket,forcePathStyle:n.forcePathStyle??!1,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Qe(e,"[storage] S3 credentials missing. Using local fallback.")}if(t.provider==="huggingface"){let n=t.huggingface;return n?.namespace&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new he({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Qe(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new te(e)}function ys(t){return new Promise(e=>setTimeout(e,t))}async function Tt(t,e={}){let n=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let i=1;i<=n;i++)try{return await t()}catch(a){if(o=a,i>=n)break;let c=Math.min(s,r*2**(i-1)),u=Math.floor(Math.random()*Math.max(1,c*.2));await ys(c+u)}throw o}var hs=new Set(["put","get","getText","delete","list"]);function Ot(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:hs.has(r)?(...o)=>Tt(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Rt(t){let e=t.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Nt(t){let e=t.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let n=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var Se=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=Rt(s??r),this.sourcePrefix=`projects/${n}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,n=new Date().toISOString(),r=n,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:n};await this.provider.put(e,JSON.stringify(o,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Nt(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,n,r){return await this.ensureRegistered(),this.provider.put(this.key(e),n,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{existsSync as ka}from"node:fs";import{execFileSync as ba}from"node:child_process";import{homedir as xa}from"node:os";import{isAbsolute as ja,join as ar,relative as Ca,resolve as cr}from"node:path";import{DatabaseSync as Ia}from"node:sqlite";import{join as js}from"node:path";import{createHash as Ss}from"node:crypto";import{dirname as ws}from"node:path";import{mkdirSync as vs,readFileSync as ks,renameSync as bs,writeFileSync as xs}from"node:fs";function w(t){return Ss("sha256").update(t).digest("hex")}function Ze(t){if(Array.isArray(t))return t.map(Ze);if(t&&typeof t=="object"){let e=t,n={};for(let r of Object.keys(e).sort())n[r]=Ze(e[r]);return n}return t}function _t(t){return JSON.stringify(Ze(t))}function $t(t){try{return JSON.parse(ks(t,"utf8"))}catch{return null}}function E(t,e){vs(ws(t),{recursive:!0});let n=`${t}.${process.pid}.tmp`;xs(n,JSON.stringify(e,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),bs(n,t)}function Kt(t,e){let n=t.trim(),r=n.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=w(n).slice(0,12);if(!r||r==="."||r==="..")return`${e}--${s}`;let o=r.slice(0,100);return o===n&&n.length<=100?o:`${o.slice(0,85)}--${s}`}function Lt(t,e,n){let r=e.trim(),s=n.trim();if(!r)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let o=Kt(r.toLowerCase(),"agent"),i=Kt(s,"session");return{projectId:t.id,projectName:t.name,projectRoot:t.rootPath,agent:r,nativeSessionId:s,sessionKey:`${r}:${s}`,remotePrefix:["projects",t.id,"sessions",o,i].join("/"),localDirectory:js(t.rootPath,".toolnet","sessions",o,i)}}function Dt(t){return String(t).padStart(12,"0")}var we=class{constructor(e,n=100,r=512*1024){this.storage=e;this.maxEventsPerChunk=n;this.maxChunkBytes=r;if(n<1)throw new Error("maxEventsPerChunk must be positive");if(r<1024)throw new Error("maxChunkBytes is too small")}storage;maxEventsPerChunk;maxChunkBytes;async getJson(e){let n=await this.storage.getText(e);return n?JSON.parse(n):null}async putJson(e,n){await this.storage.put(e,JSON.stringify(n,null,2)+`
|
|
6
|
+
`,"application/json")}async scan(e){let n=`${e.remotePrefix}/events/`,r=await this.storage.list(n),s=[],o=0;for(let i of r){let a=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!a)continue;let c=Number(a[1]),u=Number(a[2]);!Number.isFinite(c)||!Number.isFinite(u)||(s.push({key:i.key,start:c,end:u}),o=Math.max(o,u))}return s.sort((i,a)=>i.start-a.start),{chunks:s,maxSequence:o}}split(e){let n=[],r=[],s=0;for(let o of e){let i=Buffer.byteLength(JSON.stringify(o)+`
|
|
7
|
+
`,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),a=n.filter(y=>y.sequence>i.maxSequence),c=0;for(let y of this.split(a)){let g=y[0],v=y[y.length-1],A=y.map(_=>JSON.stringify(_)).join(`
|
|
8
8
|
`)+`
|
|
9
|
-
`,
|
|
9
|
+
`,O=w(A).slice(0,16),C=[e.remotePrefix,"events",`${Dt(g.sequence)}-${Dt(v.sequence)}-${O}.jsonl`].join("/");await this.storage.exists(C)||await this.storage.put(C,A,"application/x-ndjson"),c+=y.length}let u=await this.scan(e),p=n[n.length-1],l=o?.status??"active";p?.type==="session_end"||p?.type==="session_idle"?l="idle":p?.type==="error"?l="error":n.length>0&&(l="active");let m=new Date().toISOString(),d=n[0],f={version:1,projectId:e.projectId,projectName:e.projectName,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,status:l,createdAt:o?.createdAt??d?.timestamp??m,updatedAt:p?.timestamp??m,firstEventAt:o?.firstEventAt??d?.timestamp,lastEventAt:p?.timestamp??o?.lastEventAt,eventCount:u.maxSequence,chunkCount:u.chunks.length,metadata:{...o?.metadata,...s.metadata}};(s.title??o?.title)&&(f.title=s.title??o?.title);let h={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,lastLocalSequence:n.length>0?n[n.length-1].sequence:u.maxSequence,lastRemoteSequence:u.maxSequence,sourceCursors:r,updatedAt:m};return await this.putJson(`${e.remotePrefix}/cursor.json`,h),await this.putJson(`${e.remotePrefix}/session.json`,f),{uploadedEvents:c,lastRemoteSequence:u.maxSequence,eventCount:f.eventCount,chunkCount:f.chunkCount,status:l}}};import{closeSync as et,existsSync as Cs,fsyncSync as Is,mkdirSync as As,openSync as tt,readSync as Es,rmSync as Wt,statSync as Ft,writeSync as Ps}from"node:fs";import{join as nt}from"node:path";var Ms=12e4,Ts=80,Os=2e3;function Rs(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}var ve=class{constructor(e){this.identity=e;As(e.localDirectory,{recursive:!0}),this.eventsFile=nt(e.localDirectory,"events.jsonl"),this.stateFile=nt(e.localDirectory,"state.json"),this.lockFile=nt(e.localDirectory,"journal.lock")}identity;eventsFile;stateFile;lockFile;initialState(){let e=new Date().toISOString();return{version:1,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,status:"idle",createdAt:e,updatedAt:e,lastSequence:0,lastRemoteSequence:0,remoteByteOffset:0,sourceCursors:{},recentEventIds:[]}}loadStateUnsafe(){return $t(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(e){E(this.stateFile,e)}acquireLock(){for(let e=0;e<Ts;e+=1)try{return tt(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-Ft(this.lockFile).mtimeMs>Ms){Wt(this.lockFile,{force:!0});continue}}catch{}Rs(25)}throw new Error(`Session journal is locked: ${this.lockFile}`)}withLock(e){let n=this.acquireLock();try{return e()}finally{et(n),Wt(this.lockFile,{force:!0})}}append(e){return e.length===0?[]:this.withLock(()=>{let n=this.loadStateUnsafe(),r=new Set(n.recentEventIds),s=n.lastSequence,o=[];for(let l of e){let m=l.timestamp??new Date().toISOString(),d=l.data??{},f=l.provenance?.rawDigest??w(_t(d)),h=l.sourceEventId?[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,l.sourceEventId].join("|"):[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,s+1,l.type,m,f].join("|"),y=w(h).slice(0,32);if(r.has(y))continue;s+=1;let g={version:1,id:y,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,type:l.type,timestamp:m,data:d,provenance:{...l.provenance,rawDigest:f}};l.role!==void 0&&(g.role=l.role),l.sourceEventId!==void 0&&(g.sourceEventId=l.sourceEventId),l.sourceSequence!==void 0&&(g.sourceSequence=l.sourceSequence),o.push(g),r.add(y)}if(o.length===0)return[];let i=o.map(l=>JSON.stringify(l)).join(`
|
|
10
10
|
`)+`
|
|
11
|
-
`,
|
|
12
|
-
`).filter(Boolean).map(
|
|
13
|
-
`)
|
|
14
|
-
`).
|
|
11
|
+
`,a=tt(this.eventsFile,"a",384);try{Ps(a,i,null,"utf8"),Is(a)}finally{et(a)}let c=o[o.length-1],u="active";c.type==="session_end"||c.type==="session_idle"?u="idle":c.type==="error"&&(u="error");let p=Array.from(r).slice(-Os);return this.saveStateUnsafe({...n,status:u,updatedAt:c.timestamp,lastSequence:c.sequence,recentEventIds:p}),o})}readPending(){return this.withLock(()=>{let e=this.loadStateUnsafe();if(!Cs(this.eventsFile))return{events:[],startOffset:e.remoteByteOffset,endOffset:e.remoteByteOffset};let n=Ft(this.eventsFile).size,r=Math.min(e.remoteByteOffset,n);if(n<=r)return{events:[],startOffset:r,endOffset:n};let s=n-r,o=Buffer.alloc(s),i=tt(this.eventsFile,"r");try{Es(i,o,0,s,r)}finally{et(i)}return{events:o.toString("utf8").split(`
|
|
12
|
+
`).filter(Boolean).map(u=>JSON.parse(u)),startOffset:r,endOffset:n}})}markRemote(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,lastRemoteSequence:Math.max(r.lastRemoteSequence,e),remoteByteOffset:Math.max(r.remoteByteOffset,n),updatedAt:new Date().toISOString()})})}setSourceCursor(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,sourceCursors:{...r.sourceCursors,[e]:String(n)},updatedAt:new Date().toISOString()})})}};import{closeSync as ji,existsSync as Ci,openSync as Ii,readSync as Ai,statSync as Ei}from"node:fs";function zt(t,e){let n=e.toLowerCase();return n.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||n.includes("tuy\u1EC7t \u0111\u1ED1i")||n.includes("must not")||n.includes("never ")?"critical":t==="rule"||t==="decision"?"high":t==="todo"||n.includes("error")||n.includes("failed")||n.includes("exception")?"normal":"temporary"}var Jt=[/không được/iu,/tuyệt đối/iu,/bắt buộc/iu,/đừng\s+/iu,/must not/iu,/do not/iu,/don't/iu,/\bnever\b/iu],Ns=[/từ giờ/iu,/về sau/iu,/mỗi lần/iu,/luôn luôn/iu,/\bluôn\b/iu,/quy tắc/iu,/workflow/iu,/\balways\b/iu,/\brequired\b/iu,/\bmust\b/iu,/from now on/iu],_s=[/\bchốt\b/iu,/quyết định/iu,/sẽ dùng/iu,/chọn .+ thay/iu,/đổi sang/iu,/chuyển sang/iu,/\bdecided\b/iu,/\bchosen\b/iu,/we will use/iu,/use .+ instead/iu,/switch(?:ed)? to/iu],$s=[/\btodo\b/iu,/cần làm/iu,/cần thêm/iu,/cần sửa/iu,/cần kiểm tra/iu,/tiếp theo/iu,/bước tiếp theo/iu,/còn phải/iu,/còn cần/iu,/next step/iu,/\bneed to\b/iu,/\bremaining\b/iu,/follow[- ]?up/iu],Ks=[/đã sửa/iu,/đã fix/iu,/đã khắc phục/iu,/đã xử lý/iu,/hoàn tất/iu,/hoàn thành/iu,/\bfixed\b/iu,/\bresolved\b/iu,/\bimplemented\b/iu,/\bcompleted\b/iu,/\bpasses?\b/iu],Bt=[/kiến trúc/iu,/pipeline/iu,/adapter/iu,/schema/iu,/runtime/iu,/namespace/iu,/storage/iu,/lưu trữ/iu,/workflow/iu,/session core/iu,/memory engine/iu,/retrieval/iu],Ls=[/\bdùng\b/iu,/\btách\b/iu,/\bthay\b/iu,/\bchuyển\b/iu,/\blưu\b/iu,/\bmap\b/iu,/\buse\b/iu,/\bsplit\b/iu,/\bstore\b/iu,/\breplace\b/iu,/\bmove\b/iu],Ds=[/đường dẫn/iu,/\bpath\b/iu,/\bport\b/iu,/\bendpoint\b/iu,/\bdomain\b/iu,/\bbucket\b/iu,/\brepository\b/iu,/\brepo\b/iu,/\bbranch\b/iu,/\/[A-Za-z0-9._/-]{4,}/u],Ws=[/\blà\b/iu,/\bở\b/iu,/\bdùng\b/iu,/\bnằm\b/iu,/\bis\b/iu,/\buse\b/iu,/located/iu,/runs on/iu],Vt=new Set(["content","text","message","prompt","summary","description","reason","title","last_assistant_message","lastAssistantMessage","input_messages","inputMessages"]),Fs=new Set(["payload","data","content","message","messages","parts","summary"]);function P(t,e){return e.some(n=>n.test(t))}function Ht(t){return t.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function zs(t){return Ht(t).toLowerCase().replace(/[^\p{L}\p{N}:/._-]+/gu," ").replace(/\s+/g," ").trim()}function Bs(t){return!(t.length<12||t.length>1e3||(t.match(new RegExp("\\p{L}","gu"))??[]).length<6||/^(?:https?:\/\/\S+|[A-Za-z0-9+/=]{80,})$/u.test(t))}function rt(t,e,n,r=0){if(!(r>6)){if(typeof t=="string"){(!e||Vt.has(e))&&n.push(t);return}if(Array.isArray(t)){for(let s of t.slice(0,50))rt(s,e,n,r+1);return}if(!(!t||typeof t!="object"))for(let[s,o]of Object.entries(t))(Vt.has(s)||Fs.has(s))&&rt(o,s,n,r+1)}}function Vs(t){let e=[];rt(t.data,void 0,e);let n=[],r=new Set;for(let s of e)for(let o of s.split(/\n+|(?<=[.!?])\s+/u)){let i=Ht(o);if(Bs(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function qt(t){return(t.role??(typeof t.data.role=="string"?t.data.role:"")).toLowerCase()}function qs(t,e,n){if(n.type==="decision")return{kind:"decision",confidence:1};if(n.type==="todo")return{kind:"todo",confidence:1};let r=e==="user"||n.type==="user_prompt",s=e==="assistant"||n.type==="assistant_message";return r&&P(t,Jt)?{kind:"rule",confidence:.98}:r&&P(t,Ns)?{kind:"rule",confidence:.92}:P(t,_s)?{kind:P(t,Bt)?"architecture":"decision",confidence:r?.93:.86}:r&&P(t,$s)?{kind:"todo",confidence:.87}:P(t,Bt)&&P(t,Ls)?{kind:"architecture",confidence:r?.88:.82}:s&&P(t,Ks)?{kind:"fix",confidence:.8}:r&&P(t,Ds)&&P(t,Ws)?{kind:"context",confidence:.79}:null}function Js(t){switch(t){case"rule":return"rule";case"decision":case"architecture":return"decision";case"todo":return"todo";case"fix":case"context":return"code"}}function Hs(t,e,n){return t==="rule"&&P(n,Jt)?"critical":t==="architecture"||t==="decision"||t==="rule"?"high":t==="fix"||t==="context"?"normal":zt(e,n)}function Gt(t,e){let n=[],r=new Set,s=new Map;for(let o of e){let i=typeof o.data.messageId=="string"?o.data.messageId:void 0,a=qt(o);i&&a&&s.set(i,a)}for(let o of e){let i=qt(o),a=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&a&&(i=s.get(a)??"");for(let c of Vs(o)){let u=qs(c,i,o);if(!u||u.confidence<.75)continue;let p=Js(u.kind),l=zs(c),m=w([t.projectId,u.kind,l].join("|"));if(r.has(m))continue;r.add(m);let d=o.provenance.sourcePath?[o.provenance.sourcePath]:[],f=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:m,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,kind:u.kind,type:p,content:c,confidence:u.confidence,importance:Hs(u.kind,p,c),tags:[p],provenance:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventIds:[o.id],sourceEventIds:f,sourcePaths:d,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}import{createHash as Gs}from"node:crypto";var Us=["project-knowledge","implementation","continuation","session-context"],Ys={"project-knowledge":"Project knowledge",implementation:"Implementation state",continuation:"Work continuation","session-context":"Session context"};function st(t){return Gs("sha256").update(t).digest("hex")}function ke(t,e){return`${t}:${st(e).slice(0,24)}`}function Xs(t){try{return st(JSON.stringify(t))}catch{return st(String(t))}}function W(t){let e=new Set,n=[];for(let r of t){let s=r?.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function Yt(t,e=420){let n=t.replace(/\s+/gu," ").trim();return n.length<=e?n:`${n.slice(0,Math.max(0,e-1)).trimEnd()}\u2026`}function Qs(t){return t==="rule"||t==="architecture"?"project-knowledge":t==="decision"||t==="fix"?"implementation":t==="todo"?"continuation":"session-context"}function Ut(t){return t.length===0?0:t.reduce((e,n)=>e+n,0)/t.length}function Zs(t){return t.slice().sort((e,n)=>n.importanceScore-e.importanceScore||n.confidence-e.confidence||e.id.localeCompare(n.id)).slice(0,5).map(e=>Yt(e.content)).join(" | ")}function eo(t){return t.slice().sort((e,n)=>n.importanceScore-e.importanceScore||n.confidence-e.confidence||e.id.localeCompare(n.id)).slice(0,6).map(e=>Yt(e.content)).join(`
|
|
13
|
+
`)}function Xt(t,e){let n=t.slice().sort((m,d)=>m.sequence-d.sequence||m.timestamp.localeCompare(d.timestamp)||m.id.localeCompare(d.id)),r=n.map(m=>({id:ke("raw",[m.projectId,m.agent,m.nativeSessionId,m.id,String(m.sequence)].join("|")),level:"raw",eventId:m.id,sourceEventId:m.sourceEventId,sequence:m.sequence,type:m.type,role:m.role,timestamp:m.timestamp,sourcePath:m.provenance.sourcePath,payloadDigest:Xs(m.data)})),s=new Map,o=new Map;n.forEach((m,d)=>{let f=r[d];f&&(s.set(m.id,f.id),m.sourceEventId&&o.set(m.sourceEventId,f.id))});let i=e.map(m=>{let d=W([...m.provenance.eventIds.map(f=>s.get(f)),...m.provenance.sourceEventIds.map(f=>o.get(f))]);return{id:ke("fact",m.fingerprint),level:"fact",fingerprint:m.fingerprint,kind:m.kind,type:m.type,content:m.content,knowledgeClass:m.knowledgeClass,importanceScore:m.importanceScore,confidence:m.confidence,tags:W([...m.tags,"level:fact",`class:${m.knowledgeClass}`,`kind:${m.kind}`]),rawIds:d,sourcePaths:W(m.provenance.sourcePaths)}}),a=new Map;for(let m of i){let d=Qs(m.kind),f=a.get(d)??[];f.push(m),a.set(d,f)}let c=[];for(let m of Us){let d=a.get(m);if(!d?.length)continue;let f=d.slice().sort((y,g)=>g.importanceScore-y.importanceScore||g.confidence-y.confidence||y.id.localeCompare(g.id)),h=f.map(y=>y.id);c.push({id:ke("scene",`${m}|${h.join("|")}`),level:"scene",kind:m,title:Ys[m],summary:Zs(f),factIds:h,importanceScore:Math.max(...f.map(y=>y.importanceScore)),confidence:Ut(f.map(y=>y.confidence)),tags:W(["level:scene",`scene:${m}`,...f.flatMap(y=>y.tags)]),sourcePaths:W(f.flatMap(y=>y.sourcePaths))})}let u=new Map(i.map(m=>[m.id,m])),p=[];for(let m of c){let f=m.factIds.map(g=>u.get(g)).filter(g=>!!g).filter(g=>(g.knowledgeClass==="permanent"||g.knowledgeClass==="task")&&g.importanceScore>=.55);if(f.length===0)continue;let h=f.some(g=>g.knowledgeClass==="permanent")?"permanent":"task",y=eo(f);p.push({id:ke("knowledge",`${m.id}|${h}|${f.map(g=>g.id).join("|")}`),level:"knowledge",knowledgeClass:h,title:m.title,content:y,sceneIds:[m.id],factIds:f.map(g=>g.id),importanceScore:Math.max(...f.map(g=>g.importanceScore)),confidence:Ut(f.map(g=>g.confidence)),tags:W(["level:knowledge",`class:${h}`,`scene:${m.kind}`,...f.flatMap(g=>g.tags)]),sourcePaths:W(f.flatMap(g=>g.sourcePaths))})}let l=[];for(let m of i)for(let d of m.rawIds)l.push({from:d,to:m.id,type:"supports"});for(let m of c)for(let d of m.factIds)l.push({from:d,to:m.id,type:"belongs_to"});for(let m of p)for(let d of m.sceneIds)l.push({from:d,to:m.id,type:"promotes_to"});return{schema:"toolnet.memory-hierarchy.v1",version:1,raw:r,facts:i,scenes:c,knowledge:p,links:l,stats:{raw:r.length,facts:i.length,scenes:c.length,knowledge:p.length,links:l.length}}}function be(t){return t?Math.ceil(t.length/3.5):0}function xe(t,e){if(!t)return"";if(be(t)<=e)return t;let r=Math.floor(e*3.5),s=t.slice(0,r),o=s.lastIndexOf("."),i=s.lastIndexOf(`
|
|
14
|
+
`),a=Math.max(o,i);return a>r*.7?s.slice(0,a+1):s}function F(){let t=pe(),e=process.env.TOOLNET_SESSION_SAVE||"summary",n=process.env.TOOLNET_RAW_TRANSCRIPT==="on"||e==="archive"||e==="full",r=process.env.TOOLNET_MEMORY_PROMOTION||"conservative",s=parseFloat(process.env.TOOLNET_PROMOTE_MIN_SCORE||"0.65"),o=parseInt(process.env.TOOLNET_SESSION_SUMMARY_MAX_TOKENS||"700",10),i=parseInt(process.env.TOOLNET_DURABLE_MEMORY_MAX_ITEMS_PER_SESSION||"10",10),a=n,c=process.env.TOOLNET_RAW_TRANSCRIPT_REMOTE==="on"||e==="full";return{sessionSave:e,rawTranscript:n,memoryPromotion:r,promoteMinScore:s,sessionSummaryMaxTokens:o,durableMemoryMaxItemsPerSession:i,archiveLocal:a,archiveRemote:c}}function Qt(t){return(t||F()).rawTranscript}function Zt(t){return(t||F()).durableMemoryMaxItemsPerSession}function en(t){return(t||F()).sessionSummaryMaxTokens}function tn(t){return(t||F()).archiveRemote}function to(t){return t.replace(/\b[A-Za-z0-9_-]{20,}\b/g,"[REDACTED]").replace(/api[_-]?key[:\s=]+[^\s]+/gi,"api_key=[REDACTED]").replace(/token[:\s=]+[^\s]+/gi,"token=[REDACTED]").replace(/secret[:\s=]+[^\s]+/gi,"secret=[REDACTED]").replace(/password[:\s=]+[^\s]+/gi,"password=[REDACTED]")}function no(t,e){let n=t.toLowerCase(),r=.5,s=["nh\u1EDB","remember","quy t\u1EAFc","rule","t\u1EEB gi\u1EDD","from now","kh\xF4ng \u0111\u01B0\u1EE3c","must not","lu\xF4n lu\xF4n","always","never","critical","important","blocker","deploy","production","architecture"];for(let i of s)n.includes(i)&&(r+=.15);e==="rule"||e==="architecture"||e==="blocker"?r+=.2:e==="decision"||e==="deploy"?r+=.15:(e==="fix"||e==="next_action")&&(r+=.1),t.length<20?r-=.3:t.length>500&&(r-=.1);let o=[/npm (notice|warn|ERR)/i,/\d+ packages? in \d+/i,/found \d+ vulnerabilities/i,/up to date/i,/added \d+ packages/i,/^(ok|done|success|error|warning)$/i];for(let i of o)i.test(t)&&(r-=.4);return Math.max(0,Math.min(1,r))}function ro(t,e){let n=[],r=new Set;for(let i of t){let a=i.split(`
|
|
15
|
+
`).filter(c=>c.trim());for(let c of a){let u=c.trim();if(u.length<15)continue;let p=u.toLowerCase().replace(/\s+/g," ");if(r.has(p))continue;r.add(p);let l="decision";/\b(rule|quy tắc|policy|standard|convention)\b/i.test(u)||/\b(always|never|must|should|từ giờ|không được)\b/i.test(u)?l="rule":/\b(fix|fixed|bug|issue|error|lỗi)\b/i.test(u)?l="fix":/\b(blocker|blocked|stuck|cannot|không thể)\b/i.test(u)?l="blocker":/\b(next|todo|action|task|cần làm)\b/i.test(u)?l="next_action":/\b(deploy|release|publish|ship)\b/i.test(u)?l="deploy":/\b(architecture|design|structure|pattern)\b/i.test(u)?l="architecture":/\.(ts|js|py|go|rs|java|cpp|c|h)\b/i.test(u)&&(l="file");let m=no(u,l);if(m<.3)continue;let d=to(u);n.push({category:l,text:d,importance:m,sourceSessionId:e})}}let s=F(),o=Zt(s);return n.sort((i,a)=>a.importance-i.importance).slice(0,o)}function so(t){let e=F(),n=en(e),o=t.join(`
|
|
15
16
|
|
|
16
17
|
`).split(`
|
|
17
|
-
`).filter(i=>{let
|
|
18
|
-
`);return
|
|
19
|
-
|
|
20
|
-
`).filter(d=>d.trim())).map(d=>typeof d=="string"?d:JSON.stringify(d)).filter(d=>d.trim()),s=
|
|
21
|
-
|
|
22
|
-
`);if(c<0)return{events:[],nextOffset:r};let a=u.slice(0,c+1);return{events:a.split(`
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
`)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
`)
|
|
31
|
-
|
|
18
|
+
`).filter(i=>{let a=i.trim();return a.length>20&&!a.startsWith("npm")&&!a.startsWith("\u2713")&&!a.startsWith("Error:")}).slice(0,20).join(`
|
|
19
|
+
`);return xe(o,n)}function je(t,e){let r=(Array.isArray(t)?t:t.split(`
|
|
20
|
+
|
|
21
|
+
`).filter(d=>d.trim())).map(d=>typeof d=="string"?d:JSON.stringify(d)).filter(d=>d.trim()),s=ro(r,e),o=s.filter(d=>d.category==="decision").map(d=>d.text),i=s.filter(d=>d.category==="rule").map(d=>d.text),a=s.filter(d=>d.category==="file").map(d=>d.text),c=s.filter(d=>d.category==="fix").map(d=>d.text),u=s.filter(d=>d.category==="blocker").map(d=>d.text),p=s.filter(d=>d.category==="next_action").map(d=>d.text),l=s.filter(d=>d.category==="deploy").map(d=>d.text);return{summary:so(r),decisions:o,projectRules:i,filesChanged:a,bugsFixed:c,commands:l,blockers:u,nextActions:p,durableFacts:s}}function K(t){let e=new Set,n=[];for(let r of t){let s=r?.replace(/\s+/g," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function oo(t){let e=new Map;for(let n of t){if(!n||!n.id||!Number.isFinite(n.sequence))continue;let r=n.sourceEventId?`${n.agent}:${n.sourceEventId}`:n.id,s=e.get(r);(!s||n.sequence>s.sequence)&&e.set(r,n)}return[...e.values()].sort((n,r)=>n.sequence-r.sequence||n.timestamp.localeCompare(r.timestamp))}function io(t){switch(t){case"critical":return 1;case"high":return .85;case"normal":return .6;case"temporary":return .25}}function ao(t){let e=io(t.importance);return Math.max(0,Math.min(1,e*.75+t.confidence*.25))}function co(t){return t.importance==="temporary"||t.confidence<.78?"transient":t.kind==="rule"||t.kind==="architecture"?"permanent":t.kind==="decision"||t.kind==="todo"||t.kind==="fix"?"task":"session"}function uo(t){let e=t.normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}_./:-]+/gu)??[],n=new Set;for(let r of e)if(!(r.length<2||/^\d+$/u.test(r))&&(n.add(r),n.size>=40))break;return[...n]}function lo(t){let e=co(t),n=ao(t),r=uo(t.content);return{...t,knowledgeClass:e,importanceScore:n,retrievalTerms:r,tags:K([...t.tags,"level:fact",`class:${e}`,`kind:${t.kind}`])}}function po(t){return t.map(e=>{try{return JSON.stringify({type:e.type,role:e.role,data:e.data,provenance:{sourcePath:e.provenance.sourcePath,files:e.provenance.files}})}catch{return""}}).filter(Boolean)}function mo(t,e,n){let r=je(po(e),t.nativeSessionId),s=n.filter(u=>u.kind==="todo").map(u=>u.content),o=n.flatMap(u=>u.provenance.sourcePaths),i=n.filter(u=>u.kind==="architecture").map(u=>u.content),a=K([...s,...r.nextActions]),c=K([...r.nextActions,...s]);return{summary:r.summary,state:{task:c[0]??a[0],decisions:K(r.decisions),files:K([...r.filesChanged,...o]),todos:a,completed:K(r.bugsFixed),blockers:K(r.blockers),nextActions:c,architecture:K(i)}}}function nn(t,e){let n=oo(e),r=Gt(t,n).map(lo),s=r.filter(p=>p.knowledgeClass!=="transient").sort((p,l)=>l.importanceScore-p.importanceScore),{summary:o,state:i}=mo(t,n,s),a=s.map(p=>({fingerprint:p.fingerprint,kind:p.kind,knowledgeClass:p.knowledgeClass,importanceScore:p.importanceScore,content:p.content,terms:p.retrievalTerms})),c=Xt(n,s),u=p=>r.filter(l=>l.knowledgeClass===p).length;return{version:2,normalizedEvents:n,summary:o,state:i,candidates:s,retrievalIndex:a,hierarchy:c,stats:{inputEvents:e.length,normalizedEvents:n.length,extractedCandidates:r.length,persistedCandidates:s.length,permanent:u("permanent"),task:u("task"),session:u("session"),transient:u("transient")}}}import{createHash as fo}from"node:crypto";import{chmodSync as rn,existsSync as go,mkdirSync as yo,readFileSync as ho,renameSync as So,writeFileSync as sn}from"node:fs";import{dirname as on,join as Ce}from"node:path";var at="toolnet.context-offload.v1",wo="toolnet.context-offload-asset.v1",vo=256,ko=new Set(["tool_call","tool_result","file_read","file_write","file_edit","command","test","artifact"]);function an(t){return Ce(t,".toolnet","offload")}function bo(t){return Ce(an(t),"assets")}function cn(t){return Ce(an(t),"graph.json")}function un(t){yo(t,{recursive:!0,mode:448});try{rn(t,448)}catch{}}function xo(t,e){un(on(t));let n=`${t}.${process.pid}.${Date.now()}.tmp`;sn(n,e,{encoding:"utf8",mode:384}),So(n,t);try{rn(t,384)}catch{}}function it(t){return Array.isArray(t)?t.map(it):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).sort(([e],[n])=>e.localeCompare(n)).map(([e,n])=>[e,it(n)])):t}function jo(t){return fo("sha256").update(JSON.stringify(it(t)),"utf8").digest("hex")}function ot(){return{schema:at,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function Co(t){let e=cn(t);if(!go(e))return ot();try{let n=JSON.parse(ho(e,"utf8"));return n.schema!==at||n.version!==1||!Array.isArray(n.nodes)?ot():n}catch{return ot()}}function Io(t,e){xo(cn(t),JSON.stringify(e,null,2)+`
|
|
22
|
+
`)}function Ao(t,e=260){if(typeof t!="string")return null;let n=t.replace(/\s+/gu," ").trim();return n?n.slice(0,e):null}function Eo(t){let e=[...t.provenance.files??[],t.provenance.sourcePath],n=[];for(let r of e){let s=Ao(r);if(!(!s||n.includes(s))&&(n.push(s),n.length===3))break}return n}function Po(t){return`${t.agent}:${t.sourceEventId??t.id}`.replace(/\s+/gu," ").trim().slice(0,120)}function Mo(t,e){un(on(t));try{return sn(t,e,{encoding:"utf8",flag:"wx",mode:384}),!0}catch(n){if(n.code==="EEXIST")return!1;throw n}}function To(t,e){let n=t.nodes.find(s=>s.id===e.id),r=n?{...n,kind:e.kind,bytes:e.bytes,sourceRefs:Array.from(new Set([...n.sourceRefs,...e.sourceRefs])).slice(-8),files:Array.from(new Set([...n.files,...e.files])).slice(0,6)}:e;return{schema:at,version:1,updatedAt:new Date().toISOString(),nodes:[...t.nodes.filter(s=>s.id!==e.id),r].slice(-vo)}}function ln(t,e){let n=Co(t),r=0,s=0,o=0,i=[];for(let a of e){if(!ko.has(a.type))continue;r+=1;let c=jo({type:a.type,data:a.data}),u={schema:wo,version:1,assetId:c,event:{type:a.type,agent:a.agent,nativeSessionId:a.nativeSessionId,timestamp:a.timestamp,sourceEventId:a.sourceEventId,provenance:a.provenance,data:a.data}},p=JSON.stringify(u,null,2)+`
|
|
23
|
+
`;Mo(Ce(bo(t),`${c}.json`),p)?s+=1:o+=1,i.push(c),n=To(n,{id:c,kind:a.type,bytes:Buffer.byteLength(p,"utf8"),createdAt:a.timestamp,sourceRefs:[Po(a)],files:Eo(a)})}return r>0&&Io(t,n),{eligible:r,written:s,deduped:o,graphNodes:n.nodes.length,assetIds:i}}import{createHash as Do}from"node:crypto";import{existsSync as Wo,readdirSync as Fo,readFileSync as zo}from"node:fs";import{basename as Bo,join as An}from"node:path";import{randomUUID as mn}from"node:crypto";var x=class extends Error{constructor(n,r){super(n);this.statusCode=r}statusCode};function re(t){let e=new Set,n=[];for(let r of t){let s=r.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function B(t){let e=t.normalize("NFKD").replace(/[\u0300-\u036f]/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,120);if(!e)throw new x("Invalid Wiki slug",400);return e}function dn(t){let e=[];for(let n of t.matchAll(/\[\[([^\[\]]+)\]\]/gu)){let r=n[1]?.trim();r&&e.push(B(r))}return re(e)}function Oo(t){return t.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_-]+/u).map(e=>e.trim()).filter(e=>e.length>=2)}function pn(t){return{id:`revision-${mn()}`,pageId:t.id,slug:t.slug,revision:t.revision,title:t.title,...t.summary?{summary:t.summary}:{},content:t.content,tags:[...t.tags],links:[...t.links],createdAt:t.updatedAt}}function z(t){return structuredClone(t)}var Ie=class{constructor(e){this.store=e}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}async mutate(e){let n,r=this.queue.then(async()=>{let s=await this.ensureState();n=e(s),s.updatedAt=new Date().toISOString(),await this.store.save(s)});return this.queue=r.then(()=>{},()=>{}),await r,n}async summary(){let e=await this.ensureState(),n=new Set(e.pages.flatMap(r=>r.links));return{schema:"toolnet.wiki-summary.v1",projectId:e.projectId,pages:e.pages.length,revisions:e.revisions.length,tags:re(e.pages.flatMap(r=>r.tags)).sort((r,s)=>r.localeCompare(s)),links:e.pages.reduce((r,s)=>r+s.links.length,0),orphanPages:e.pages.filter(r=>r.links.length===0&&!n.has(r.slug)).length,automatedPages:e.pages.filter(r=>r.tags.some(s=>s.startsWith("toolnet-auto-"))).length,updatedAt:e.updatedAt}}async listPages(){let e=await this.ensureState();return z([...e.pages].sort((n,r)=>n.title.localeCompare(r.title)))}async getPage(e){let n=await this.ensureState(),r=B(e),s=n.pages.find(o=>o.slug===r||o.id===e);if(!s)throw new x(`Wiki page not found: ${e}`,404);return z(s)}async createPage(e){return this.mutate(n=>{let r=e.title.trim(),s=e.content.trim();if(!r)throw new x("Wiki title is required",400);let o=B(e.slug??r);if(n.pages.some(c=>c.slug===o))throw new x(`Wiki page already exists: ${o}`,409);let i=new Date().toISOString(),a={id:`wiki-${mn()}`,slug:o,title:r,...e.summary?.trim()?{summary:e.summary.trim()}:{},content:s,tags:re(e.tags??[]),links:dn(s),revision:1,createdAt:i,updatedAt:i};return n.pages.push(a),n.revisions.push(pn(a)),z(a)})}async updatePage(e,n){return this.mutate(r=>{let s=B(e),o=r.pages.find(i=>i.slug===s||i.id===e);if(!o)throw new x(`Wiki page not found: ${e}`,404);if(n.title!==void 0){let i=n.title.trim();if(!i)throw new x("Wiki title is required",400);o.title=i}if(n.summary!==void 0){let i=n.summary.trim();i?o.summary=i:delete o.summary}return n.content!==void 0&&(o.content=n.content.trim(),o.links=dn(o.content)),n.tags!==void 0&&(o.tags=re(n.tags)),o.revision+=1,o.updatedAt=new Date().toISOString(),r.revisions.push(pn(o)),z(o)})}async history(e){let n=await this.getPage(e),r=await this.ensureState();return z(r.revisions.filter(s=>s.pageId===n.id).sort((s,o)=>o.revision-s.revision))}async backlinks(e){let n=await this.getPage(e),r=await this.ensureState();return z(r.pages.filter(s=>s.links.includes(n.slug)).sort((s,o)=>s.title.localeCompare(o.title)))}async search(e,n=10){let r=await this.ensureState(),s=re(Oo(e));if(s.length===0)return[];let o=Math.max(1,Math.min(20,Math.floor(n))),i=[];for(let a of r.pages){let c=a.title.toLowerCase(),u=a.slug.toLowerCase(),p=a.summary?.toLowerCase()??"",l=a.content.toLowerCase(),m=a.tags.map(f=>f.toLowerCase()),d=0;for(let f of s)u===f&&(d+=12),c===f&&(d+=10),c.includes(f)&&(d+=6),u.includes(f)&&(d+=5),m.some(h=>h===f)?d+=5:m.some(h=>h.includes(f))&&(d+=3),p.includes(f)&&(d+=2),l.includes(f)&&(d+=1);d>0&&i.push({page:z(a),score:d})}return i.sort((a,c)=>c.score-a.score||c.page.updatedAt.localeCompare(a.page.updatedAt)).slice(0,o)}};var fn="wiki/state.v1.json";function Ro(t){let e=new Date().toISOString();return{schema:"toolnet.wiki.v1",version:1,projectId:t.id,pages:[],revisions:[],createdAt:e,updatedAt:e}}function No(t,e){let n=JSON.parse(t);if(n.schema!=="toolnet.wiki.v1"||n.version!==1||n.projectId!==e.id||!Array.isArray(n.pages)||!Array.isArray(n.revisions))throw new Error("Invalid ToolNet Wiki state");return n}var Ae=class{constructor(e,n){this.storage=e;this.project=n}storage;project;async load(){let e=await this.storage.getText(fn);if(!e){let n=Ro(this.project);return await this.save(n),n}return No(e,this.project)}async save(e){await this.storage.put(fn,JSON.stringify(e,null,2),"application/json")}};import{createHash as _o,randomUUID as gn}from"node:crypto";var yn="wiki/governance.v1.json",vn="toolnet.knowledge-governance.v1",hn=500,se={autoApproveThreshold:.86,criticalApproveThreshold:.94,staleAfterDays:90};function $o(t,e=0,n=1){return Math.max(e,Math.min(n,t))}function ct(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/gu," ").trim()}function Sn(t){return _o("sha256").update(t.normalize("NFKC").replace(/\s+/gu," ").trim()).digest("hex")}function Ko(t){let e=[t.title,t.summary??"",t.content.slice(0,2e3),...t.tags].join(" ").toLowerCase();return/\b(?:architecture|security|authentication|authorization|auth|database|production|deploy|deployment|payment|billing|permission|permissions|acl|credential|secret|migration)\b/u.test(e)}function Lo(t){let e=t.sourceType==="skill"?.96:t.sourceType==="memory"?.94:.88,n=t.tags.map(r=>r.toLowerCase());return(n.includes("permanent")||n.includes("task"))&&(e+=.03),t.content.length>=200&&(e+=.02),t.content.length<80&&(e-=.05),t.title.length<4&&(e-=.05),$o(e)}function wn(t){let e=new Date().toISOString();return{schema:vn,version:1,projectId:t,policy:{...se},reviews:[],audit:[],createdAt:e,updatedAt:e}}function kn(t){let e=t.autoApproveThreshold??se.autoApproveThreshold,n=t.criticalApproveThreshold??se.criticalApproveThreshold,r=t.staleAfterDays??se.staleAfterDays;if(!Number.isFinite(e)||e<.5||e>1)throw new x("Invalid autoApproveThreshold",400);if(!Number.isFinite(n)||n<.5||n>1)throw new x("Invalid criticalApproveThreshold",400);if(!Number.isInteger(r)||r<1||r>3650)throw new x("Invalid staleAfterDays",400);return{autoApproveThreshold:e,criticalApproveThreshold:n,staleAfterDays:r}}var Ee=class{constructor(e,n){this.storage=e;this.project=n}storage;project;async load(){let e=await this.storage.getText(yn);if(!e){let n=wn(this.project.id);return await this.save(n),n}try{let n=JSON.parse(e);if(n.schema!==vn||n.version!==1||n.projectId!==this.project.id||!Array.isArray(n.reviews)||!Array.isArray(n.audit))throw new Error("invalid");return{...n,policy:kn(n.policy??se)}}catch{let n=wn(this.project.id);return await this.save(n),n}}async save(e){await this.storage.put(yn,JSON.stringify(e,null,2),"application/json")}},Pe=class{constructor(e){this.store=e}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}audit(e,n,r,s={}){e.audit.push({id:gn(),action:n,principal:r,...s.reviewId?{reviewId:s.reviewId}:{},...s.sourceKey?{sourceKey:s.sourceKey}:{},timestamp:new Date().toISOString(),...s.metadata?{metadata:s.metadata}:{}}),e.audit.length>hn&&(e.audit=e.audit.slice(-hn))}async mutate(e){let n,r=this.queue.then(async()=>{let s=await this.ensureState();n=await e(s),s.updatedAt=new Date().toISOString(),await this.store.save(s)});return this.queue=r.then(()=>{},()=>{}),await r,n}async policy(){return{...(await this.ensureState()).policy}}async setPolicy(e,n){return this.mutate(r=>(r.policy=kn({...r.policy,...e}),this.audit(r,"policy:update",n,{metadata:{...r.policy}}),{...r.policy}))}async summary(){let e=await this.ensureState(),n=r=>e.reviews.filter(s=>s.status===r).length;return{schema:"toolnet.knowledge-governance-summary.v1",projectId:e.projectId,pending:n("pending"),approved:n("approved"),rejected:n("rejected"),superseded:n("superseded"),criticalPending:e.reviews.filter(r=>r.status==="pending"&&r.risk==="critical").length,conflictPending:e.reviews.filter(r=>r.status==="pending"&&r.risk==="conflict").length,auditEvents:e.audit.length,policy:{...e.policy},updatedAt:e.updatedAt}}async listReviews(e){let n=await this.ensureState();return structuredClone(n.reviews.filter(r=>!e||r.status===e).sort((r,s)=>s.updatedAt.localeCompare(r.updatedAt)))}async auditLog(e=100){let n=await this.ensureState(),r=Math.max(1,Math.min(500,Math.floor(e)));return structuredClone(n.audit.slice(-r).reverse())}async assess(e,n){let r=await this.ensureState(),s=Lo(e),o=ct(e.title),i=n.filter(p=>p.slug!==e.slug&&ct(p.title)===o&&Sn(p.content)!==Sn(e.content)).map(p=>p.slug),a=Ko(e),c=[];s<r.policy.autoApproveThreshold&&c.push(`confidence:${s.toFixed(2)}`),a&&s<r.policy.criticalApproveThreshold&&c.push("critical-knowledge"),i.length>0&&c.push("conflicting-knowledge");let u=i.length>0?"conflict":a?"critical":"normal";return{confidence:s,risk:u,requiresReview:i.length>0||s<r.policy.autoApproveThreshold||a&&s<r.policy.criticalApproveThreshold,reasons:c,conflicts:i}}async gate(e,n){let r=await this.assess(e,n);return this.mutate(s=>{let o=s.reviews.find(c=>c.sourceKey===e.sourceKey&&c.digest===e.digest);if(o?.status==="approved")return{allowed:!0,mode:"review-approved",assessment:r,review:structuredClone(o)};if(o?.status==="rejected")return{allowed:!1,mode:"rejected",assessment:r,review:structuredClone(o)};if(!r.requiresReview)return this.audit(s,"knowledge:auto-approved","system",{sourceKey:e.sourceKey,metadata:{confidence:r.confidence,risk:r.risk}}),{allowed:!0,mode:"auto-approved",assessment:r};if(o?.status==="pending")return{allowed:!1,mode:"pending-review",assessment:r,review:structuredClone(o)};let i=new Date().toISOString(),a={id:gn(),sourceKey:e.sourceKey,sourceType:e.sourceType,slug:e.slug,marker:e.marker,digest:e.digest,title:e.title,...e.summary?{summary:e.summary}:{},content:e.content,tags:[...new Set([...e.tags,e.marker])],confidence:r.confidence,risk:r.risk,reasons:[...r.reasons],conflicts:[...r.conflicts],status:"pending",createdAt:i,updatedAt:i};return s.reviews.push(a),this.audit(s,"knowledge:review-requested","system",{reviewId:a.id,sourceKey:a.sourceKey,metadata:{confidence:a.confidence,risk:a.risk}}),{allowed:!1,mode:"pending-review",assessment:r,review:structuredClone(a)}})}async markApplied(e,n){await this.mutate(r=>{let s=r.reviews.find(o=>o.sourceKey===e&&o.digest===n&&o.status==="approved");s&&(s.appliedAt=new Date().toISOString(),s.updatedAt=s.appliedAt,this.audit(r,"knowledge:applied",s.reviewedBy??"system",{reviewId:s.id,sourceKey:e}))})}async decide(e,n,r){return this.mutate(async s=>{let o=s.reviews.find(u=>u.id===e);if(!o)throw new x(`Governance review not found: ${e}`,404);if(o.status!=="pending")throw new x("Governance review is already resolved",409);let i=new Date().toISOString();if(o.reviewedAt=i,o.reviewedBy=n.principal,o.updatedAt=i,n.note?.trim()&&(o.reviewNote=n.note.trim()),n.action==="reject")return o.status="rejected",this.audit(s,"knowledge:rejected",n.principal,{reviewId:e,sourceKey:o.sourceKey}),structuredClone(o);if(n.action==="supersede")return o.status="superseded",n.targetReviewId&&(o.supersededBy=n.targetReviewId),this.audit(s,"knowledge:superseded",n.principal,{reviewId:e,sourceKey:o.sourceKey,metadata:{targetReviewId:n.targetReviewId}}),structuredClone(o);if(n.action==="merge"){if(!n.targetReviewId)throw new x("targetReviewId is required for merge",400);let u=s.reviews.find(p=>p.id===n.targetReviewId);if(!u)throw new x("Merge target review not found",404);return o.status="superseded",o.mergedInto=u.id,this.audit(s,"knowledge:merged",n.principal,{reviewId:e,sourceKey:o.sourceKey,metadata:{targetReviewId:u.id}}),structuredClone(o)}o.status="approved";let c=(await r.listPages()).find(u=>u.slug===o.slug);if(c&&!c.tags.includes(o.marker))throw new x(`Wiki page '${o.slug}' is manually managed`,409);return c?await r.updatePage(o.slug,{title:o.title,summary:o.summary??"",content:o.content,tags:o.tags}):await r.createPage({slug:o.slug,title:o.title,...o.summary?{summary:o.summary}:{},content:o.content,tags:o.tags}),o.appliedAt=i,this.audit(s,"knowledge:approved",n.principal,{reviewId:e,sourceKey:o.sourceKey}),structuredClone(o)})}async quality(e){let n=await this.ensureState(),r=await e.listPages(),s=Date.now(),o=n.policy.staleAfterDays*864e5,i=r.map(p=>{let l=s-Date.parse(p.updatedAt);return{slug:p.slug,title:p.title,updatedAt:p.updatedAt,ageDays:Math.max(0,Math.floor(l/864e5)),stale:Number.isFinite(l)&&l>o}}).filter(p=>p.stale).map(({stale:p,...l})=>l),a=new Map;for(let p of r){let l=ct(p.title),m=a.get(l)??[];m.push(p),a.set(l,m)}let c=[...a.entries()].filter(([,p])=>p.length>1).map(([p,l])=>({title:p,pages:l.map(m=>m.slug)})),u=n.reviews.filter(p=>p.status==="pending");return{schema:"toolnet.knowledge-quality.v1",totalPages:r.length,automatedPages:r.filter(p=>p.tags.some(l=>l.startsWith("toolnet-auto-"))).length,manualPages:r.filter(p=>!p.tags.some(l=>l.startsWith("toolnet-auto-"))).length,stalePages:i,duplicateTitles:c,pendingReviews:u.length,lowConfidenceReviews:u.filter(p=>p.confidence<n.policy.autoApproveThreshold).length,conflicts:u.filter(p=>p.risk==="conflict").length,generatedAt:new Date().toISOString()}}};var En="wiki/automation.v1.json",Pn="toolnet.wiki-automation.v1",dt=8e3,bn=new Set(["raw","rawtext","raw_text","rawtranscript","raw_transcript","transcript","messages","message","payload","prompt","response","assistantmessage","assistant_message","userprompt","user_prompt"]);function ie(t){return Do("sha256").update(JSON.stringify(t)).digest("hex")}function oe(t){if(!(!t||typeof t!="object"||Array.isArray(t)))return t}function xn(t){return Array.isArray(t)?t:[]}function Mn(t){return typeof t!="string"?void 0:t.replace(/\s+/gu," ").trim()||void 0}function ut(t){return Array.isArray(t)?t.map(Mn).filter(e=>!!e):[]}function R(t,e){for(let n of e){let r=Mn(t[n]);if(r)return r}}function ae(t){let e=new Set,n=[];for(let r of t){let s=r.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();e.has(o)||(e.add(o),n.push(s))}return n}function Me(t,e=0,n=""){if(e>3)return[];let r=n.replace(/[^a-z0-9]/giu,"").toLowerCase();if(bn.has(r))return[];if(typeof t=="string"){let i=t.replace(/\s+/gu," ").trim();return i.length<8?[]:[i]}if(Array.isArray(t))return t.flatMap(i=>Me(i,e+1,n));let s=oe(t);if(!s)return[];let o=[];for(let[i,a]of Object.entries(s)){let c=i.replace(/[^a-z0-9]/giu,"").toLowerCase();bn.has(c)||o.push(...Me(a,e+1,i))}return o}function jn(t){let n=ae(["content","summary","text","value","statement","description","decision","task","knowledge","context","outcome","reason","rationale"].flatMap(s=>Me(t[s],0,s)));return(n.length>0?n:ae(Me(t))).join(`
|
|
24
|
+
|
|
25
|
+
`).slice(0,dt)}function Cn(t,e){return R(t,["id","key","fingerprint","knowledgeId","sceneId"])??e}function In(t,e){return R(t,["title","name","topic","label","task","kind","type"])??e}function Vo(t){return(R(t,["knowledgeClass","class","classification","scope"])??"").toLowerCase()}function qo(t){return(R(t,["kind","sceneKind","type"])??"").toLowerCase()}function Jo(t){let e=oe(t);if(!e)return[];let n=[],r=xn(e.knowledge);for(let[o,i]of r.entries()){let a=oe(i);if(!a)continue;let c=Vo(a);if(c==="session"||c==="transient")continue;let u=jn(a);if(u.length<20)continue;let p=Cn(a,ie(a).slice(0,16)),l=In(a,`Durable Memory ${o+1}`);n.push({sourceKey:`memory:${p}`,sourceType:"memory",title:l,summary:R(a,["summary","description"]),content:u,tags:ae(["toolnet","auto","memory",...c?[c]:[]])})}let s=xn(e.scenes);for(let[o,i]of s.entries()){let a=oe(i);if(!a)continue;let c=qo(a);if(c==="session-context")continue;let u=jn(a);if(u.length<20)continue;let p=Cn(a,ie(a).slice(0,16)),l=In(a,`Knowledge Scene ${o+1}`);n.push({sourceKey:`scene:${p}`,sourceType:"scene",title:l,summary:R(a,["summary","description"]),content:u,tags:ae(["toolnet","auto","scene",...c?[c]:[]])})}return n}function Ho(t){return An(t,".toolnet","memory","skills")}function Go(t){let e=Ho(t);if(!Wo(e))return{candidates:[],failed:0};let n=[],r=0,s=Fo(e).filter(o=>o.endsWith(".json")).sort();for(let o of s)try{let i=JSON.parse(zo(An(e,o),"utf8")),a=oe(i);if(!a||a.schema!=="toolnet.skill-memory.v1")continue;let c=R(a,["id","fingerprint"])??Bo(o,".json"),u=R(a,["task"])??"",p=R(a,["title"])||u||`Reusable Skill ${c.slice(0,8)}`,l=R(a,["summary"])??void 0,m=ut(a.steps),d=ut(a.verification),f=ut(a.files),h=[];u&&h.push(`## Task
|
|
26
|
+
${u}`),l&&h.push(`## Summary
|
|
27
|
+
${l}`),m.length>0&&h.push(`## Procedure
|
|
28
|
+
${m.map((g,v)=>`${v+1}. ${g}`).join(`
|
|
29
|
+
`)}`),d.length>0&&h.push(`## Verification
|
|
30
|
+
${d.map(g=>`- ${g}`).join(`
|
|
31
|
+
`)}`),f.length>0&&h.push(`## Relevant Files
|
|
32
|
+
${f.map(g=>`- \`${g}\``).join(`
|
|
33
|
+
`)}`);let y=h.join(`
|
|
34
|
+
|
|
35
|
+
`).slice(0,dt);if(y.length<20)continue;n.push({sourceKey:`skill:${c}`,sourceType:"skill",title:p,summary:l,content:y,tags:["toolnet","auto","skill","sop"]})}catch{r+=1}return{candidates:n,failed:r}}function lt(t){let e=new Date().toISOString();return{schema:Pn,version:1,projectId:t,entries:[],createdAt:e,updatedAt:e}}async function Uo(t,e){let n=await t.getText(En);if(!n)return lt(e);try{let r=JSON.parse(n);return r.schema!==Pn||r.version!==1||r.projectId!==e||!Array.isArray(r.entries)?lt(e):r}catch{return lt(e)}}async function Yo(t,e){await t.put(En,JSON.stringify(e,null,2),"application/json")}function Xo(t){return`toolnet-auto-${ie(t).slice(0,12)}`}function Qo(t){let e=B(t.title).slice(0,72),n=ie(t.sourceKey).slice(0,10);return B(`auto-${t.sourceType}-${e}-${n}`)}function Zo(t){return[`> Auto-generated by ToolNet Knowledge Automation from ${t.sourceType==="skill"?"reusable Skill Memory":t.sourceType==="scene"?"semantic memory scene":"durable memory"}.`,"",t.content].join(`
|
|
36
|
+
`).slice(0,dt)}function ei(t){return ie({sourceType:t.sourceType,title:t.title,summary:t.summary,content:t.content,tags:t.tags})}function ti(t,e){return t.tags.includes(e)}async function Tn(t){let e=Jo(t.hierarchy),n=Go(t.project.rootPath),r=new Map;for(let d of[...e,...n.candidates])r.set(d.sourceKey,d);let s=[...r.values()].sort((d,f)=>d.sourceKey.localeCompare(f.sourceKey)),o={schema:"toolnet.wiki-automation-result.v1",scanned:e.length+n.candidates.length,eligible:s.length,created:0,updated:0,unchanged:0,skipped:0,failed:n.failed,reviewPending:0,autoApproved:0,reviewApproved:0,pages:[]},i=new Ie(new Ae(t.storage,t.project));await i.initialize();let a=new Pe(new Ee(t.storage,t.project));await a.initialize();let c=await Uo(t.storage,t.project.id),u=await i.listPages(),p=new Map(u.map(d=>[d.slug,d])),l=new Map(c.entries.map(d=>[d.sourceKey,d]));for(let d of s)try{let f=Xo(d.sourceKey),h=ei(d),y=l.get(d.sourceKey),g=y?.slug??Qo(d),v=p.get(g);if(v&&!ti(v,f)){o.skipped+=1;continue}let A=ae([...d.tags,f]),O=Zo(d),C=await a.gate({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:g,marker:f,digest:h,title:d.title,...d.summary?{summary:d.summary}:{},content:O,tags:A},[...p.values()]);if(!C.allowed){C.mode==="pending-review"?o.reviewPending+=1:o.skipped+=1;continue}C.mode==="auto-approved"?o.autoApproved+=1:C.mode==="review-approved"&&(o.reviewApproved+=1),v?y?.digest!==h?(v=await i.updatePage(g,{title:d.title,summary:d.summary??"",content:O,tags:A}),p.set(v.slug,v),o.updated+=1,o.pages.push({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:v.slug,action:"updated"})):(o.unchanged+=1,o.pages.push({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:g,action:"unchanged"})):(v=await i.createPage({slug:g,title:d.title,summary:d.summary,content:O,tags:A}),p.set(v.slug,v),o.created+=1,o.pages.push({sourceKey:d.sourceKey,sourceType:d.sourceType,slug:v.slug,action:"created"}));let _=new Date().toISOString(),S={sourceKey:d.sourceKey,sourceType:d.sourceType,slug:g,digest:h,marker:f,updatedAt:_},j=c.entries.findIndex(de=>de.sourceKey===d.sourceKey);j>=0?c.entries[j]=S:c.entries.push(S),l.set(d.sourceKey,S),await a.markApplied(d.sourceKey,h)}catch(f){if(f instanceof x&&f.statusCode===409){o.skipped+=1;continue}o.failed+=1}let m=new Date().toISOString();return c.updatedAt=m,c.lastRunAt=m,c.entries.sort((d,f)=>d.sourceKey.localeCompare(f.sourceKey)),await Yo(t.storage,c),o}import{createHash as ni}from"node:crypto";import{chmodSync as Rn,existsSync as ri,mkdirSync as si,readFileSync as Dl,readdirSync as Wl,renameSync as oi,statSync as Fl,writeFileSync as ii}from"node:fs";import{join as Nn}from"node:path";var ai="toolnet.skill-memory.v1",On=5,ci=16,ui=24,li=32;function di(t){return ni("sha256").update(t).digest("hex")}function ue(t,e=Number.MAX_SAFE_INTEGER){let n=new Set,r=[];for(let s of t){let o=s.replace(/\s+/gu," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();if(!n.has(i)&&(n.add(i),r.push(o),r.length>=e))break}return r}function pt(t,e=360){let n=t.replace(/\s+/gu," ").trim();return n.length<=e?n:n.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function pi(t){return t.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/giu,"Bearer [REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{8,}\b/gu,"[REDACTED]").replace(/\b(api[_-]?key|token|password|passwd|secret)\b(\s*[:=]\s*)(["']?)[^\s"'`]+/giu,"$1$2[REDACTED]")}function $(t,e=360){return t&&pt(pi(t),e)||void 0}function le(t,e){for(let n of e){let r=t[n];if(typeof r=="string"&&r.trim())return r}}function _n(t,e){for(let n of e){let r=t[n];if(typeof r=="number"&&Number.isFinite(r))return r;if(typeof r=="string"&&r.trim()&&Number.isFinite(Number(r)))return Number(r)}}function $n(t,e){for(let n of e){let r=t[n];if(typeof r=="boolean")return r;if(typeof r=="string"){let s=r.trim().toLowerCase();if(["true","yes","pass","passed","success","succeeded","ok"].includes(s))return!0;if(["false","no","fail","failed","error"].includes(s))return!1}}}function Kn(t){let e=t.data??{};if($n(e,["passed","pass","success","succeeded","ok"])===!1)return!0;let r=_n(e,["exitCode","exit_code","code","statusCode"]);if(r!==void 0&&r!==0)return!0;let s=le(e,["status","result","outcome"]);return!!(s&&/\b(fail(?:ed)?|error|broken|cancelled)\b/iu.test(s))}function ce(t){let e=t.data??{};if(Kn(t))return!1;if($n(e,["passed","pass","success","succeeded","ok"])===!0||_n(e,["exitCode","exit_code","code","statusCode"])===0)return!0;let s=le(e,["status","result","outcome"]);return s&&/\b(pass(?:ed)?|success(?:ful)?|succeeded|ok|green|complete(?:d)?)\b/iu.test(s)?!0:t.type==="commit"||t.type==="deploy"}function Ln(t){let e=t.data??{},n=le(e,["path","file","filePath","filename","target"]);if(n)return $(n,260);let r=t.provenance?.files;return $(r?.[0],260)}function mt(t){return $(le(t.data??{},["command","cmd","script"]),420)}function q(t){return $(le(t.data??{},["name","test","suite","title","message","text","result","status"]),300)}function mi(t){let e=[];for(let n of[...t].sort((r,s)=>r.sequence-s.sequence))if(ce(n)){if(n.type==="test"){let r=q(n)??mt(n)??"Tests passed";e.push(`Test passed: ${r}`);continue}if(n.type==="commit"){let r=q(n);e.push(r?`Commit: ${r}`:"Commit completed");continue}if(n.type==="deploy"){let r=q(n);e.push(r?`Deploy: ${r}`:"Deployment completed")}}return ue(e,10)}function fi(t,e){let n=[];for(let r of[...t].sort((s,o)=>s.sequence-o.sequence))switch(r.type){case"file_write":case"file_edit":{let s=Ln(r);s&&n.push(`Update ${s}`);break}case"command":{if(Kn(r))break;let s=mt(r);s&&n.push(`Run: ${s}`);break}case"test":{if(!ce(r))break;let s=q(r)??mt(r)??"project tests";n.push(`Verify: ${s}`);break}case"commit":{if(!ce(r))break;let s=q(r);n.push(s?`Commit: ${s}`:"Commit verified changes");break}case"deploy":{if(!ce(r))break;let s=q(r);n.push(s?`Deploy: ${s}`:"Deploy verified build");break}default:break}if(n.length===0)for(let r of e.files.slice(0,8)){let s=$(r,260);s&&n.push(`Update ${s}`)}return ue(n,ci)}function gi(t,e){let n=[...e.files];for(let r of t){let s=Ln(r);s&&n.push(s);for(let o of r.provenance?.files??[]){let i=$(o,260);i&&n.push(i)}}return ue(n,ui)}function yi(t){return ue(t.filter(e=>["file_write","file_edit","command","test","commit","deploy"].includes(e.type)).map(e=>e.id),li)}function hi(t){return t.map(n=>n.timestamp).filter(Boolean).sort().at(-1)??new Date(0).toISOString()}function Dn(t,e,n){if(e.length===0)return[];let r=mi(e),s=ue(n.completed.map(f=>$(f,280)??""),On);if(!(s.length>0||e.some(f=>["test","commit","deploy"].includes(f.type)&&ce(f))))return[];let i=$(n.task,280)??$(n.nextActions[0],280),a=s.length>0?s:i?[i]:[];if(a.length===0)return[];let c=fi(e,n);if(c.length===0)return[];let u=gi(e,n),p=yi(e),l=Math.min(...e.map(f=>f.sequence)),m=Math.max(...e.map(f=>f.sequence)),d=hi(e);return a.slice(0,On).map(f=>{let h=[`Reusable procedure learned from successful task: ${f}.`,u.length>0?`Files: ${u.slice(0,6).join(", ")}.`:"",r.length>0?`Verification: ${r.slice(0,4).join("; ")}.`:""].filter(Boolean),y=JSON.stringify({projectId:t.projectId,task:f,steps:c,verification:r,files:u}),g=di(y);return{schema:ai,version:1,id:`skill-${g.slice(0,24)}`,fingerprint:g,projectId:t.projectId,title:pt(`SOP: ${f}`,180),task:f,summary:pt(h.join(" "),900),steps:c,verification:r,files:u,source:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,firstSequence:l,lastSequence:m,eventIds:p},createdAt:d}})}function Si(t){return Nn(t.rootPath,".toolnet","memory","skills")}function wi(t){let e=Si(t);return si(e,{recursive:!0,mode:448}),Rn(e,448),e}function Wn(t,e){if(e.length===0)return{written:0,deduped:0,files:[]};let n=wi(t),r=0,s=0,o=[];for(let i of e){if(i.projectId!==t.id)throw new Error(`Skill project mismatch: ${i.projectId} != ${t.id}`);let a=Nn(n,`${i.id}.json`);if(o.push(a),ri(a)){s+=1;continue}let c=`${a}.${process.pid}.${Date.now()}.tmp`;ii(c,JSON.stringify(i,null,2)+`
|
|
37
|
+
`,{encoding:"utf8",mode:384}),oi(c,a),Rn(a,384),r+=1}return{written:r,deduped:s,files:o}}function Fn(t){return String(t).padStart(12,"0")}function vi(t){return t.remotePrefix.replace("/sessions/","/memory/learned/")}var Te=class{constructor(e){this.storage=e}storage;async write(e,n,r){if(r.length===0||n.length===0)return null;let s=Math.min(...n.map(p=>p.sequence)),o=Math.max(...n.map(p=>p.sequence)),i={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,candidateCount:r.length,candidates:r},a=JSON.stringify(i,null,2)+`
|
|
38
|
+
`,c=w(r.map(p=>p.fingerprint).sort().join("|")).slice(0,16),u=[vi(e),"batches",`${Fn(s)}-${Fn(o)}-${c}.json`].join("/");return await this.storage.exists(u)||await this.storage.put(u,a,"application/json"),u}};import{createHash as ki}from"node:crypto";function zn(t){return String(t).padStart(12,"0")}function bi(t){return ki("sha256").update(t).digest("hex")}function xi(t){return t.remotePrefix.replace("/sessions/","/memory/hierarchy/")}var Oe=class{constructor(e){this.storage=e}storage;async write(e,n,r){if(n.length===0||r.facts.length===0)return null;let s=Math.min(...n.map(u=>u.sequence)),o=Math.max(...n.map(u=>u.sequence)),i={schema:"toolnet.memory-hierarchy-batch.v1",version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,hierarchy:r},a=bi([...r.facts.map(u=>u.id),...r.knowledge.map(u=>u.id)].sort().join("|")).slice(0,16),c=[xi(e),"batches",`${zn(s)}-${zn(o)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,`${JSON.stringify(i,null,2)}
|
|
39
|
+
`,"application/json"),c}};function Pi(t,e){if(!Ci(t))return{events:[],nextOffset:e};let n=Ei(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=Ii(t,"r");try{Ai(i,o,0,s,r)}finally{ji(i)}let a=o.toString("utf8"),c=a.lastIndexOf(`
|
|
40
|
+
`);if(c<0)return{events:[],nextOffset:r};let u=a.slice(0,c+1);return{events:u.split(`
|
|
41
|
+
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(u,"utf8")}}var Re=class{constructor(e){this.options=e;this.journal=new Te(e.storage),this.hierarchyJournal=new Oe(e.storage)}options;journal;hierarchyJournal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["memory.learner.offset"]??0),r=Number.isFinite(n)?n:0,s=Pi(this.options.wal.eventsFile,r);if(s.events.length===0)return{scannedEvents:0,candidates:0,journalWritten:!1,nextOffset:s.nextOffset};let o=nn(this.options.identity,s.events),i=o.candidates,a=!1;i.length>0&&(a=!!await this.journal.write(this.options.identity,s.events,i));let c=!1;o.hierarchy.facts.length>0&&(c=!!await this.hierarchyJournal.write(this.options.identity,s.events,o.hierarchy));let u=Dn(this.options.identity,s.events,o.state),p=Wn(this.options.project,u);this.options.wal.setSourceCursor("memory.pipeline.version",2),this.options.wal.setSourceCursor("memory.pipeline.normalized_events",o.stats.normalizedEvents),this.options.wal.setSourceCursor("memory.pipeline.persisted",o.stats.persistedCandidates),this.options.wal.setSourceCursor("memory.pipeline.permanent",o.stats.permanent),this.options.wal.setSourceCursor("memory.pipeline.task",o.stats.task),this.options.wal.setSourceCursor("memory.pipeline.session",o.stats.session),this.options.wal.setSourceCursor("memory.pipeline.transient",o.stats.transient),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.version",o.hierarchy.version),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.raw",o.hierarchy.stats.raw),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.facts",o.hierarchy.stats.facts),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.scenes",o.hierarchy.stats.scenes),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.knowledge",o.hierarchy.stats.knowledge),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.journal_written",c?1:0),this.options.wal.setSourceCursor("memory.skill.assets",u.length),this.options.wal.setSourceCursor("memory.skill.written",p.written),this.options.wal.setSourceCursor("memory.skill.deduped",p.deduped);try{let l=ln(this.options.project.rootPath,s.events);this.options.wal.setSourceCursor("memory.context_offload.eligible",l.eligible),this.options.wal.setSourceCursor("memory.context_offload.written",l.written),this.options.wal.setSourceCursor("memory.context_offload.deduped",l.deduped),this.options.wal.setSourceCursor("memory.context_offload.graph_nodes",l.graphNodes),this.options.wal.setSourceCursor("memory.context_offload.failed",0)}catch{this.options.wal.setSourceCursor("memory.context_offload.failed",1)}try{let l=await Tn({project:this.options.project,storage:this.options.storage,hierarchy:o.hierarchy});this.options.wal.setSourceCursor("memory.wiki_automation.scanned",l.scanned),this.options.wal.setSourceCursor("memory.wiki_automation.eligible",l.eligible),this.options.wal.setSourceCursor("memory.wiki_automation.created",l.created),this.options.wal.setSourceCursor("memory.wiki_automation.updated",l.updated),this.options.wal.setSourceCursor("memory.wiki_automation.unchanged",l.unchanged),this.options.wal.setSourceCursor("memory.wiki_automation.skipped",l.skipped),this.options.wal.setSourceCursor("memory.wiki_automation.failed",l.failed),this.options.wal.setSourceCursor("memory.wiki_automation.review_pending",l.reviewPending),this.options.wal.setSourceCursor("memory.wiki_automation.auto_approved",l.autoApproved),this.options.wal.setSourceCursor("memory.wiki_automation.review_approved",l.reviewApproved)}catch{this.options.wal.setSourceCursor("memory.wiki_automation.failed",1)}return this.options.wal.setSourceCursor("memory.learner.offset",s.nextOffset),{scannedEvents:s.events.length,candidates:i.length,journalWritten:a,nextOffset:s.nextOffset}}};import{closeSync as $i,existsSync as Ki,openSync as Li,readSync as Di,statSync as Wi}from"node:fs";var Mi=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function H(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function Vn(t){return H(t).toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function J(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))J(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Mi.has(r)||["data","payload","parts","messages"].includes(r))&&J(s,e,n+1)}}function Ne(t){return/\b(cancelled|canceled)\b|đã hủy|bỏ qua/iu.test(t)?"cancelled":/\b(blocked|blocker)\b|đang vướng|bị vướng|đang kẹt|chưa thể/iu.test(t)?"blocked":/\b(completed|complete|done|finished|passed)\b|hoàn thành|hoàn tất|đã xong|đã làm xong|\bxong\b/iu.test(t)?"completed":/\bin[\s_-]*progress\b|working on|đang làm|đang thực hiện|đang xử lý|đang triển khai/iu.test(t)?"in_progress":"pending"}function Bn(t){let e=H(t);return/^(?:đang\s+làm|đang\s+thực\s+hiện|đang\s+xử\s+lý|đang\s+triển\s+khai|hoàn\s+thành|hoàn\s+tất|đã\s+xong|đã\s+làm\s+xong|xong|pending|in[\s_-]*progress|completed|complete|done|finished|blocked|cancelled|canceled)[.!]*$/iu.test(e)}function I(t,e,n,r,s={}){let o=H(r),i=s.key??Vn(o);return{version:1,id:w([t.projectId,n,i,e.id,o,s.status??"",s.order??""].join("|")).slice(0,32),projectId:t.projectId,kind:n,key:i,text:o,status:s.status,order:s.order,confidence:s.confidence??.85,occurredAt:e.timestamp,sequence:e.sequence,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId}}function Ti(t,e,n){let r=H(n);if(r.length<5||r.length>1200)return[];let s=[],o=/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r),i=r.match(/^(?:mục tiêu|goal|objective)\s*(?::|-)\s*(.+)$/iu);i?.[1]&&s.push(I(t,e,"goal",i[1],{confidence:.97}));let a=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);a?.[1]&&s.push(I(t,e,"plan",a[1],{confidence:.95}));let c=/\b(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?([^.;\n]{0,220})/giu,u;for(;!o&&(u=c.exec(r));){let m=Number(u[1]),d=H(u[2]??""),f=d&&!Bn(d)?`Phase ${m} - ${d}`:`Phase ${m}`;s.push(I(t,e,"phase",f,{key:`phase:${m}`,order:m,status:Ne(r),confidence:.93}))}let p=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);p?.[2]&&s.push(I(t,e,"task",p[2],{status:p[1].trim()?"completed":Ne(p[2]),confidence:.96}));let l=r.match(/^(?:todo|task|việc)\s*(\d+)?(?:\s*[:.\-–—]\s*|\s+)(.+)$/iu);if(l?.[2]){let m=l[1]?Number(l[1]):void 0,d=H(l[2]),f=Bn(d);s.push(I(t,e,"task",f&&m!==void 0?`TODO ${m}`:d,{key:m!==void 0?`task:${m}`:Vn(d),order:m,status:Ne(r),confidence:.93}))}if(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r)){let m=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");m&&s.push(I(t,e,"next_action",m,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(I(t,e,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(I(t,e,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(I(t,e,"decision",r,{confidence:.9})),s}function qn(t,e){if(e.length===0)return[];let n=[],r=new Set;function s(i){r.has(i.id)||(r.add(i.id),n.push(i))}for(let i of e){if(i.type==="decision"){let c=[];J(i.data,c);for(let u of c)s(I(t,i,"decision",u,{confidence:1}))}if(i.type==="todo"){let c=[];J(i.data,c);for(let u of c)s(I(t,i,"task",u,{status:Ne(u),confidence:1}))}if(["file_write","file_edit"].includes(i.type))for(let c of["filePath","path","file"]){let u=i.data[c];typeof u=="string"&&u&&s(I(t,i,"file",u,{confidence:1}))}if(i.type==="test"){let c=[];J(i.data,c);for(let u of c)s(I(t,i,"test",u,{confidence:1}))}let a=[];J(i.data,a);for(let c of a)for(let u of c.split(/\n+/u))for(let p of Ti(t,i,u))s(p)}let o=e[e.length-1];return s(I(t,o,"session",`${t.agent}:${t.nativeSessionId}`,{key:t.sessionKey,confidence:1})),n}function Jn(t){return String(t).padStart(12,"0")}var _e=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(u=>u.sequence)),s=Math.max(...n.map(u=>u.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:r,lastSequence:s,observations:n},i=JSON.stringify(o,null,2)+`
|
|
42
|
+
`,a=w(n.map(u=>u.id).sort().join("|")).slice(0,16),c=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${Jn(r)}-${Jn(s)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,i,"application/json"),c}};import{join as Hn}from"node:path";import{mkdirSync as Oi}from"node:fs";function Ri(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function G(t,e=20){let n=[],r=new Set;for(let s of t.slice().reverse()){let o=Ri(s);if(!(!o||r.has(o))&&(r.add(o),n.push(s),n.length>=e))break}return n.reverse()}function Ni(t){return t.kind==="phase"?/^Phase\s+\d+$/iu.test(t.text):t.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(t.text):!1}function Gn(t,e){let n=e.status??t?.status??"pending",r=n;t&&(t.status==="completed"&&n!=="completed"?r="completed":n==="pending"&&(t.status==="in_progress"||t.status==="blocked")&&(r=t.status));let s=t&&Ni(e)?t.title:e.text;return{id:t?.id??w(e.key).slice(0,24),title:s,status:r,order:e.order??t?.order,confidence:Math.max(e.confidence,t?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function _i(t,e){let n=`projects/${t.id}/work/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await e.getText(o.key);if(i)try{let a=JSON.parse(i);a.version===1&&Array.isArray(a.observations)&&s.push(a)}catch{}}return s}async function $e(t,e){let r=(await _i(t,e)).flatMap(S=>S.observations).sort((S,j)=>{let de=S.occurredAt.localeCompare(j.occurredAt);if(de!==0)return de;let bt=S.sequence-j.sequence;return bt!==0?bt:S.id.localeCompare(j.id)}),s=new Map,o=new Map,i,a,c,u=[],p=[],l=[],m=[],d=[],f=[];for(let S of r)switch(S.kind){case"goal":i=S.text;break;case"plan":a=S.text;break;case"phase":s.set(S.key,Gn(s.get(S.key),S));break;case"task":o.set(S.key,Gn(o.get(S.key),S));break;case"decision":u.push(S.text);break;case"blocker":p.push(S.text);break;case"warning":l.push(S.text);break;case"next_action":m.push(S.text);break;case"file":d.push(S.text);break;case"test":f.push(S.text);break;case"session":c={agent:S.agent,nativeSessionId:S.nativeSessionId,sessionKey:S.sessionKey,updatedAt:S.occurredAt};break}let h=Array.from(s.values()).sort((S,j)=>(S.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),y=Array.from(o.values()).sort((S,j)=>(S.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),g=h.find(S=>S.status==="in_progress")??h.find(S=>S.status==="blocked")??h.find(S=>S.status==="pending"),v=y.find(S=>S.status==="in_progress")??y.find(S=>S.status==="blocked")??y.find(S=>S.status==="pending"),A=G([...m,...v?[v.title]:[],...!v&&g?[g.title]:[],...y.filter(S=>S.status==="pending").slice(0,5).map(S=>S.title)],8),O=G([...p,...h.filter(S=>S.status==="blocked").map(S=>S.title),...y.filter(S=>S.status==="blocked").map(S=>S.title)],20),C={version:1,projectId:t.id,projectName:t.name,goal:i,plan:a,phases:h,tasks:y,decisions:G(u,20),blockers:O,warnings:G(l,20),nextActions:A,filesTouched:G(d,30),tests:G(f,20),currentPhase:g,currentTask:v,progress:{phasesTotal:h.length,phasesCompleted:h.filter(S=>S.status==="completed").length,tasksTotal:y.length,tasksCompleted:y.filter(S=>S.status==="completed").length,blocked:h.filter(S=>S.status==="blocked").length+y.filter(S=>S.status==="blocked").length},lastSession:c,updatedAt:r.length?r[r.length-1].occurredAt:new Date().toISOString()},_=Hn(t.rootPath,".toolnet","work");return Oi(_,{recursive:!0}),E(Hn(_,"current.json"),C),await e.put(`projects/${t.id}/work/current.json`,JSON.stringify(C,null,2)+`
|
|
43
|
+
`,"application/json"),C}async function Ke(t,e){let n=await e.getText(`projects/${t.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function Fi(t,e){if(!Ki(t))return{events:[],nextOffset:e};let n=Wi(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=Li(t,"r");try{Di(i,o,0,s,r)}finally{$i(i)}let a=o.toString("utf8"),c=a.lastIndexOf(`
|
|
44
|
+
`);if(c<0)return{events:[],nextOffset:r};let u=a.slice(0,c+1);return{events:u.split(`
|
|
45
|
+
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(u,"utf8")}}var Le=class{constructor(e){this.options=e;this.journal=new _e(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.continuity.offset"]??0),r=Fi(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=qn(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await $e(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.continuity.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{closeSync as Yi,existsSync as Xi,openSync as Qi,readSync as Zi,statSync as ea}from"node:fs";var zi=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function U(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function ft(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))ft(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(zi.has(r)||["data","payload","parts","messages"].includes(r))&&ft(s,e,n+1)}}function M(t,e,n,r,s,o=.95){let i=U(r);return{version:1,id:w([t.projectId,n,s.type,s.key??"",i.toLowerCase(),e.id].join("|")).slice(0,32),projectId:t.projectId,kind:n,value:i,scope:s.type,scopeKey:s.key,scopeOrder:s.order,confidence:o,evidence:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId,sequence:e.sequence,occurredAt:e.timestamp}}}function N(t,e){let n=t.toLowerCase();for(let r of e){let s=r.toLowerCase();if(n.startsWith(`${s}:`)||n.startsWith(`${s} -`)||n.startsWith(`${s} \u2014`))return U(t.slice(r.length+1))}return null}function Bi(t){let e=t.trimStart();return e.startsWith("- ")||e.startsWith("* ")||/^\d+[.)]\s+/u.test(e)}function Vi(t){return U(t.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function Un(t,e){let n=[],r=new Set;function s(o){!o.value||o.value.length<3||r.has(o.id)||(r.add(o.id),n.push(o))}for(let o of e){let i=[];ft(o.data,i);for(let a of i){let c={type:"project"},u=null;for(let p of a.split(/\r?\n/u)){let l=U(p);if(!l){u=null;continue}let m=l.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(m){let j=Number(m[1]);c={type:"phase",key:`phase:${j}`,order:j,title:U(m[2]??"")},u=null;continue}let d=l.match(/^(?:todo|task|việc)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(d){let j=Number(d[1]);c={type:"task",key:`task:${j}`,order:j,title:U(d[2]??"")},u=null;continue}let f=N(l,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(f){s(M(t,o,"mission",f,{type:"project"},.99)),u=null;continue}let h=N(l,["current objective","active objective","m\u1EE5c ti\xEAu hi\u1EC7n t\u1EA1i","objective","m\u1EE5c ti\xEAu","m\u1EE5c \u0111\xEDch"]);if(h){s(M(t,o,c.type==="phase"?"phase_objective":"objective",h,c,.98)),u=null;continue}let y=N(l,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(y){s(M(t,o,c.type==="phase"?"phase_why":"why",y,c,.98)),u=null;continue}let g=N(l,["desired outcome","final outcome","k\u1EBFt qu\u1EA3 cu\u1ED1i","k\u1EBFt qu\u1EA3 mong mu\u1ED1n","m\u1EE5c ti\xEAu cu\u1ED1i"]);if(g){s(M(t,o,"desired_outcome",g,{type:"project"},.98)),u=null;continue}let v=N(l,["plan rationale","approach rationale","why this approach","t\u1EA1i sao ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn ki\u1EBFn tr\xFAc"]);if(v){s(M(t,o,"plan_rationale",v,{type:"project"},.98)),u=null;continue}let A=N(l,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(A){s(M(t,o,"phase_deliverable",A,c,.97)),u=null;continue}let O=N(l,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if(O){s(M(t,o,"acceptance_criterion",O,c,.98)),u="acceptance_criterion";continue}let C=N(l,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(C){s(M(t,o,"dependency",C,c,.97)),u="dependency";continue}let _=N(l,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(_){s(M(t,o,"open_question",_,c,.95)),u="open_question";continue}let S=N(l,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(S){s(M(t,o,"constraint",S,c,.97)),u="constraint";continue}if(/^(?:acceptance criteria|definition of done|done khi|tiêu chí hoàn thành)\s*:?\s*$/iu.test(l)){u="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(l)){u="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(l)){u="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(l)){u="constraint";continue}if(u&&Bi(p)){s(M(t,o,u,Vi(p),c,.96));continue}u=null}}}return n}function Yn(t){return String(t).padStart(12,"0")}var De=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(c=>c.evidence.sequence)),s=Math.max(...n.map(c=>c.evidence.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,firstSequence:r,lastSequence:s,createdAt:new Date().toISOString(),observations:n},i=w(n.map(c=>c.id).sort().join("|")).slice(0,16),a=[`projects/${e.projectId}`,"work","semantic","observations",e.agent,e.nativeSessionId,`${Yn(r)}-${Yn(s)}-${i}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,JSON.stringify(o,null,2)+`
|
|
46
|
+
`,"application/json"),a}};import{mkdirSync as qi}from"node:fs";import{join as Xn}from"node:path";function Ji(t){return{value:t.value,confidence:t.confidence,evidence:t.evidence}}function Hi(t,e){if(!e)return!0;let n=t.evidence.occurredAt.localeCompare(e.evidence.occurredAt);return n!==0?n>0:t.evidence.sessionKey===e.evidence.sessionKey?t.evidence.sequence>=e.evidence.sequence:t.confidence>=e.confidence}function L(t,e){return Hi(e,t)?e:t}function D(t,e=30){let n=new Set,r=[];for(let s of t){let o=s.value.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim();!o||n.has(o)||(n.add(o),r.push(s))}return r.slice(-e)}async function Gi(t,e){let n=`projects/${t.id}/work/semantic/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await e.getText(o.key);if(i)try{let a=JSON.parse(i);a.version===1&&Array.isArray(a.observations)&&s.push(a)}catch{}}return s}function Ui(t){return{key:t.scopeKey??`phase:${t.scopeOrder??0}`,order:t.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function Qn(t,e){let r=(await Gi(t,e)).flatMap(h=>h.observations).sort((h,y)=>{let g=h.evidence.occurredAt.localeCompare(y.evidence.occurredAt);return g!==0?g:h.evidence.sessionKey===y.evidence.sessionKey?h.evidence.sequence-y.evidence.sequence:h.id.localeCompare(y.id)}),s,o,i,a,c,u=new Map,p=[],l=[],m=[];for(let h of r){let y=Ji(h);if(h.scope==="phase"&&h.scopeKey){let g=u.get(h.scopeKey)??Ui(h);switch(h.kind){case"phase_objective":g.objective=L(g.objective,y);break;case"phase_why":g.why=L(g.why,y);break;case"phase_deliverable":g.deliverable=L(g.deliverable,y);break;case"acceptance_criterion":g.acceptanceCriteria.push(y);break;case"dependency":g.dependencies.push(y);break;case"open_question":g.openQuestions.push(y);break;case"constraint":g.constraints.push(y);break;case"note":g.notes.push(y);break}u.set(g.key,g);continue}switch(h.kind){case"mission":s=L(s,y);break;case"objective":o=L(o,y);break;case"why":i=L(i,y);break;case"desired_outcome":a=L(a,y);break;case"plan_rationale":c=L(c,y);break;case"open_question":p.push(y);break;case"constraint":l.push(y);break;case"note":m.push(y);break}}for(let h of u.values())h.acceptanceCriteria=D(h.acceptanceCriteria,20),h.dependencies=D(h.dependencies,15),h.openQuestions=D(h.openQuestions,15),h.constraints=D(h.constraints,15),h.notes=D(h.notes,20);let d={version:1,projectId:t.id,projectName:t.name,mission:s,activeObjective:o,why:i,desiredOutcome:a,planRationale:c,phases:Array.from(u.values()).sort((h,y)=>h.order-y.order),openQuestions:D(p,20),constraints:D(l,20),notes:D(m,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},f=Xn(t.rootPath,".toolnet","work");return qi(f,{recursive:!0}),E(Xn(f,"semantic-current.json"),d),await e.put(`projects/${t.id}/work/semantic/current.json`,JSON.stringify(d,null,2)+`
|
|
47
|
+
`,"application/json"),d}async function Zn(t,e){let n=await e.getText(`projects/${t.id}/work/semantic/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function ta(t,e){if(!Xi(t))return{events:[],nextOffset:e};let n=ea(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=Buffer.alloc(n-r),o=Qi(t,"r");try{Zi(o,s,0,s.length,r)}finally{Yi(o)}let i=s.toString("utf8"),a=i.lastIndexOf(`
|
|
48
|
+
`);if(a<0)return{events:[],nextOffset:r};let c=i.slice(0,a+1);return{events:c.split(`
|
|
49
|
+
`).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var We=class{constructor(e){this.options=e;this.journal=new De(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.semantic.offset"]??0),r=ta(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=Un(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await Qn(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.semantic.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{mkdirSync as ma}from"node:fs";import{join as gt}from"node:path";import{existsSync as nr,mkdirSync as na,readFileSync as ra,statSync as er,writeFileSync as sa}from"node:fs";import{dirname as oa,join as ia}from"node:path";var tr=64*1024,aa=`# ToolNet Project Operating Manual
|
|
32
50
|
|
|
33
51
|
This file contains persistent instructions for AI agents working on this project.
|
|
34
52
|
|
|
@@ -71,30 +89,30 @@ Things an AI agent should always remember.
|
|
|
71
89
|
<!--
|
|
72
90
|
- [advisory] Prefer small focused files.
|
|
73
91
|
-->
|
|
74
|
-
`;function
|
|
75
|
-
`).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(e)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(e)?"passing":"unknown"}function
|
|
92
|
+
`;function Fe(t){return ia(t.rootPath,".toolnet","PROJECT.md")}function ca(t){return t.normalize("NFKC").replace(/\s+/g," ").trim()}function ua(t){let e=[],n=new Set,r=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=r.exec(t);){let o=s[1].toLowerCase(),i=ca(s[2]);if(!i)continue;let a=`${o}:${i.toLowerCase()}`;n.has(a)||(n.add(a),e.push({id:w(a).slice(0,24),mode:o,text:i,source:"manual"}))}return e}function la(t){let e=Fe(t);return nr(e)||(na(oa(e),{recursive:!0}),sa(e,aa,{encoding:"utf8",mode:384})),e}function ze(t,e=!1){let n=e?la(t):Fe(t);if(!nr(n))return null;if(er(n).size>tr)throw new Error(`PROJECT.md exceeds ${tr} bytes`);let s=ra(n,"utf8");return{path:n,content:s,digest:w(s),rules:ua(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(er(n).mtimeMs).toISOString()}}function T(t,e){let n=new Set,r=[];for(let s of t){let o=s.replace(/\s+/g," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();if(!n.has(i)&&(n.add(i),r.push(o),r.length>=e))break}return r}function rr(t){if(t)return{id:t.id,title:t.title,status:t.status}}function da(t){let e=t.slice(-10).join(`
|
|
93
|
+
`).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(e)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(e)?"passing":"unknown"}function pa(t){return w(JSON.stringify(t))}function sr(t){let{project:e,identity:n,state:r}=t,s=r.filesTouched.at(-1),o=r.phases.filter(g=>g.status==="completed").map(g=>g.title),i=r.tasks.filter(g=>g.status==="completed").map(g=>g.title),a=r.phases.filter(g=>g.status!=="completed"&&g.status!=="cancelled").map(g=>g.title),c=r.tasks.filter(g=>g.status!=="completed"&&g.status!=="cancelled").map(g=>g.title),u=T(r.nextActions,10),p=T([...c,...u],15),l=T(r.tests.slice().reverse(),10),m=T(r.filesTouched.slice().reverse(),20),d={schema:"toolnet.handoff.v2",version:2,project:{id:e.id,name:e.name},source:{agent:n.agent,nativeSessionId:n.nativeSessionId,sessionKey:n.sessionKey,sequence:t.sequence,reason:t.reason},capturedAt:t.capturedAt??new Date().toISOString(),goal:r.goal,current:{phase:rr(r.currentPhase),task:rr(r.currentTask),file:s},completed:{phases:T(o,20),tasks:T(i,30)},remaining:{phases:T(a,20),tasks:T(c,30),todos:p},nextAction:u[0],blockers:T(r.blockers.slice().reverse(),10),decisions:T(r.decisions.slice().reverse(),10),files:{current:s,recent:m},tests:{status:da(r.tests),recent:l},attention:T(t.attention??[],20),progress:r.progress},{capturedAt:f,source:h,...y}=d;return{...d,stateDigest:pa(y)}}function fa(t){return t.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.nextActions.length>0||t.blockers.length>0}var Be=class{constructor(e){this.options=e}options;async capture(e,n){let r=await Ke(this.options.project,this.options.storage);if(r||(r=await $e(this.options.project,this.options.storage)),!fa(r))return null;let s=ze(this.options.project,!1),i=[...s?s.rules.filter(f=>f.mode==="enforce").map(f=>f.text):[],...r.warnings].slice(0,20),a=sr({project:this.options.project,identity:this.options.identity,state:r,reason:e,sequence:n,attention:i}),c=a.stateDigest,u=w([this.options.project.id,this.options.identity.sessionKey,c].join("|")).slice(0,24),p=new Date().toISOString(),l={version:1,id:u,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:p,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:n},goal:r.goal,plan:r.plan,progress:r.progress,currentPhase:r.currentPhase,currentTask:r.currentTask,incompletePhases:r.phases.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),incompleteTasks:r.tasks.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),nextActions:r.nextActions.slice(0,10),blockers:r.blockers.slice(0,10),decisions:r.decisions.slice(-10),warnings:r.warnings.slice(-10),attention:i,filesTouched:r.filesTouched.slice(-20),tests:r.tests.slice(-15),stateDigest:c,continuity:a},m=`projects/${this.options.project.id}/work/handoffs/${u}.json`;await this.options.storage.exists(m)||await this.options.storage.put(m,JSON.stringify(l,null,2)+`
|
|
76
94
|
`,"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=
|
|
95
|
+
`,"application/json");let d=gt(this.options.project.rootPath,".toolnet","work","handoffs");return ma(d,{recursive:!0}),E(gt(d,`${u}.json`),l),E(gt(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),l),l}};async function or(t,e){let n=await e.getText(`projects/${t.id}/work/handoff-latest.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}var Ve=class{identity;wal;remote;sanitizer=new ee;learner;continuity;semantic;handoff;title;metadata;constructor(e){this.identity=Lt(e.project,e.agent,e.nativeSessionId),this.title=e.title,this.metadata=this.sanitizer.sanitizeValue(e.metadata??{}),this.wal=new ve(this.identity),this.remote=new we(e.storage,e.maxEventsPerChunk??100,e.maxChunkBytes??512*1024),this.learner=new Re({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.continuity=new Le({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.semantic=new We({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.handoff=new Be({project:e.project,storage:e.storage,identity:this.identity})}sanitizeEvent(e){let n=e.provenance?{...e.provenance,metadata:this.sanitizer.sanitizeValue(e.provenance.metadata)}:void 0;return{...e,data:this.sanitizer.sanitizeValue(e.data??{}),provenance:n}}start(e={}){let n=this.wal.loadState();return this.record({type:n.lastSequence===0?"session_start":"session_resume",data:e,provenance:{source:this.identity.agent}})}record(e){return this.wal.append([this.sanitizeEvent(e)])[0]}recordMany(e){return this.wal.append(e.map(n=>this.sanitizeEvent(n)))}setSourceCursor(e,n){this.wal.setSourceCursor(e,n)}async flush(){let e=this.wal.readPending(),n=this.wal.loadState(),r=await this.remote.append(this.identity,e.events,n.sourceCursors,{title:this.title,metadata:this.metadata});if(e.events.length>0){let s=e.events[e.events.length-1];this.wal.markRemote(s.sequence,e.endOffset)}if(process.env.TOOLNET_SESSION_LEARNING!=="0")try{await this.learner.learnNew()}catch{}if(process.env.TOOLNET_WORK_CONTINUITY!=="0")try{await this.continuity.learnNew()}catch{}if(process.env.TOOLNET_SEMANTIC_CONTINUITY!=="0")try{await this.semantic.learnNew()}catch{}if(process.env.TOOLNET_SMART_HANDOFF!=="0"&&e.events.length>0)try{let s=e.events[e.events.length-1],o=["session_idle","session_end","session_compact"].includes(s.type)?s.type:"checkpoint";await this.handoff.capture(o,s.sequence)}catch{}return r}async idle(e={}){return this.record({type:"session_idle",data:e,provenance:{source:this.identity.agent}}),this.flush()}async end(e={}){return this.record({type:"session_end",data:e,provenance:{source:this.identity.agent}}),this.flush()}status(){return this.wal.loadState()}recoverRemote(){return this.remote.recover(this.identity)}};var ga=[/^<SYSTEM MESSAGE>/i,/^<EPHEMERAL MESSAGE>/i,/^<system>/i,/^<ephemeral>/i,/^ManageTask:/i,/^Task \d+ status:/i,/^Task \d+ killed/i,/^Task \d+ loading/i,/^Thought for \d+ tokens/i,/^Prioritizing Tool Usage/i,/^Tool call:/i,/^Tool response:/i,/^npm notice/i,/^npm WARN/i,/^added \d+ packages/i,/^removed \d+ packages/i,/^up to date/i,/^\d+ packages are looking for funding/i,/^run `npm fund` for details/i,/^[\d.]+%/,/^\[={10,}\]/,/^Loading\.\.\./i,/^Processing\.\.\./i,/^bash-\d+\.\d+\$/,/^\$ /,/^\s*$/],ya=[/api[_-]?key[:\s=]+[^\s]+/gi,/token[:\s=]+[^\s]+/gi,/secret[:\s=]+[^\s]+/gi,/password[:\s=]+[^\s]+/gi,/bearer\s+[^\s]+/gi,/authorization:\s*[^\s]+/gi],ha=["decision","decided","rule","convention","architecture","pattern","fixed","resolved","implemented","created","updated","deleted","deployed","blocker","blocked","issue","bug","error","next","todo","action","requirement","must","should","important"];function Sa(t){let e=t.toLowerCase();return ha.some(n=>e.includes(n))}function wa(t){if(!t.trim())return!0;for(let e of ga)if(e.test(t))return!0;return Sa(t),!1}function va(t){let e=t;for(let n of ya)e=e.replace(n,r=>{let s=r.split(/[:\s=]+/);return s.length>1?`${s[0]}: [REDACTED]`:"[REDACTED]"});return e}function yt(t){let e=t.trim();return e?wa(e)?{content:"",filtered:!0,reason:"noise"}:{content:va(e),filtered:!1}:{content:"",filtered:!0,reason:"empty"}}function qe(t){let e={};for(let[n,r]of Object.entries(t))if(typeof r=="string"){let s=yt(r);s.filtered||(e[n]=s.content)}else r&&typeof r=="object"&&!Array.isArray(r)?e[n]=qe(r):Array.isArray(r)?e[n]=r.map(s=>{if(typeof s=="string"){let o=yt(s);return o.filtered?null:o.content}return s&&typeof s=="object"?qe(s):s}).filter(s=>s!==null):e[n]=r;return e}function ir(t){let e=typeof t.type=="string"?t.type.toLowerCase():"";if(e.includes("system")||e.includes("ephemeral")||e==="tool_call"&&!t.result)return!0;if(t.data&&typeof t.data=="object"){let n=t.data,r=typeof n.content=="string"?n.content:"";if(r&&yt(r).filtered)return!0}return!1}function mr(){try{let e=ba("opencode",["db","path"],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:5e3}).trim();if(e)return e}catch{}if(process.env.OPENCODE_DB)return process.env.OPENCODE_DB;let t=process.env.XDG_DATA_HOME??ar(xa(),".local","share");return ar(t,"opencode","opencode.db")}function b(t){return typeof t=="string"?t:""}function V(t){if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="bigint")return Number(t);if(typeof t=="string"){let e=Number(t);if(Number.isFinite(e))return e}return 0}function ht(t){if(t&&typeof t=="object"&&!Buffer.isBuffer(t))return t;if(typeof t!="string")return{};try{let e=JSON.parse(t);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{}}function Y(t){let e=V(t);if(e<=0)return new Date().toISOString();e<1e11&&(e*=1e3);let n=new Date(e);return Number.isNaN(n.getTime())?new Date().toISOString():n.toISOString()}function Je(t,e){if(!e)return!1;let n=cr(t),r=cr(e);if(n===r)return!0;let s=Ca(n,r);return s!==""&&s!==".."&&!s.startsWith(`..${process.platform==="win32"?"\\":"/"}`)&&!ja(s)}function ur(t){if(!t)return{time:-1,id:""};try{let e=JSON.parse(t);return{time:typeof e.time=="number"?e.time:-1,id:typeof e.id=="string"?e.id:""}}catch{return{time:-1,id:""}}}function lr(t){return JSON.stringify(t)}function fr(t){if(!ka(t))throw new Error(`OpenCode database not found: ${t}`);let e=new Ia(t,{readOnly:!0});return e.exec("PRAGMA query_only = ON"),e.exec("PRAGMA busy_timeout = 3000"),e}function Aa(t,e){let n=t.prepare(`
|
|
78
96
|
SELECT *
|
|
79
97
|
FROM "session"
|
|
80
98
|
WHERE id = ?
|
|
81
99
|
LIMIT 1
|
|
82
|
-
`).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function
|
|
100
|
+
`).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function gr(t,e,n){let r=b(e.directory);if(r&&Je(n.rootPath,r))return!0;let s=b(e.project_id);if(s){try{let o=t.prepare(`
|
|
83
101
|
SELECT *
|
|
84
102
|
FROM "project"
|
|
85
103
|
WHERE id = ?
|
|
86
104
|
LIMIT 1
|
|
87
|
-
`).get(s);if(o)for(let i of["worktree","directory","path"]){let
|
|
105
|
+
`).get(s);if(o)for(let i of["worktree","directory","path"]){let a=b(o[i]);if(a&&Je(n.rootPath,a))return!0}}catch{}try{if(t.prepare(`
|
|
88
106
|
SELECT directory
|
|
89
107
|
FROM "project_directory"
|
|
90
108
|
WHERE project_id = ?
|
|
91
|
-
`).all(s).some(i=>
|
|
109
|
+
`).all(s).some(i=>Je(n.rootPath,b(i.directory))))return!0}catch{}}try{let o=t.prepare(`
|
|
92
110
|
SELECT data
|
|
93
111
|
FROM "message"
|
|
94
112
|
WHERE session_id = ?
|
|
95
113
|
ORDER BY time_created DESC
|
|
96
114
|
LIMIT 20
|
|
97
|
-
`).all(
|
|
115
|
+
`).all(b(e.id));for(let i of o){let a=ht(i.data),c=a.path&&typeof a.path=="object"?a.path:{};for(let u of[b(c.cwd),b(c.root)])if(u&&Je(n.rootPath,u))return!0}}catch{}return!1}function dr(t,e,n,r){let s=`
|
|
98
116
|
SELECT *,
|
|
99
117
|
COALESCE(
|
|
100
118
|
time_updated,
|
|
@@ -125,10 +143,10 @@ Things an AI agent should always remember.
|
|
|
125
143
|
0
|
|
126
144
|
) ASC,
|
|
127
145
|
id ASC
|
|
128
|
-
`;return t.prepare(s).all(n,r.time,r.time,r.id)}function
|
|
146
|
+
`;return t.prepare(s).all(n,r.time,r.time,r.id)}function pr(t,e){let n=t[t.length-1];return n?{time:V(n.__clock),id:b(n.id)}:e}function Ea(t,e){let n=ht(e.data),r=b(n.role),s=V(e.__clock),o=b(e.id),i="message";return r==="user"?i="user_prompt":r==="assistant"&&(i="assistant_message"),{clock:s,order:0,event:{type:i,timestamp:Y(s),role:r||void 0,sourceEventId:`message:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{messageId:o,...n},provenance:{source:"opencode",sourcePath:t,sourceTable:"message",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}function Pa(t){let e={...t},n=t.state&&typeof t.state=="object"&&!Array.isArray(t.state)?{...t.state}:void 0;if(n){let r=n.output;if(typeof r=="string"){let s=r.replace(/\r\n/g,`
|
|
129
147
|
`),o=500;n.outputSummary=s.length<=o?s:`${s.slice(0,350)}
|
|
130
148
|
...[ToolNet truncated ${s.length-o} chars]...
|
|
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
|
|
149
|
+
${s.slice(-150)}`,delete n.output}else r!==void 0&&(n.outputSummary="[non-text tool output omitted]",delete n.output);if(n.input&&typeof n.input=="object"&&!Array.isArray(n.input)){let s={...n.input};for(let[o,i]of Object.entries(s))typeof i=="string"&&i.length>1e3&&(s[o]=`${i.slice(0,1e3)}...[ToolNet truncated]`);n.input=s}e.state=n}return e}function Ma(t,e){let n=ht(e.data),r=b(n.type),s=V(e.__clock),o=b(e.id),i=b(e.message_id),a="message_part";return r==="tool"?a="tool_call":r==="snapshot"&&(a="artifact"),{clock:s,order:1,event:{type:a,timestamp:Y(s),sourceEventId:`part:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{partId:o,messageId:i,...r==="tool"?Pa(n):n},provenance:{source:"opencode",sourcePath:t,sourceTable:"part",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}async function St(t){let e=t.dbPath??mr(),n=fr(e);try{let r=Aa(n,t.nativeSessionId);if(!gr(n,r,t.project))throw new Error(["OpenCode session does not belong to current ToolNet project.",`Session: ${t.nativeSessionId}`,`Project: ${t.project.rootPath}`,`Session directory: ${b(r.directory)||"unknown"}`].join(" "));let s=new Ve({project:t.project,storage:t.storage,agent:"opencode",nativeSessionId:t.nativeSessionId,title:b(r.title)||void 0,metadata:{source:"opencode.db",openCodeProjectId:b(r.project_id)||void 0,directory:b(r.directory)||void 0}}),o=s.status(),i=ur(o.sourceCursors["opencode.message"]),a=ur(o.sourceCursors["opencode.part"]),c=dr(n,"message",t.nativeSessionId,i),u=dr(n,"part",t.nativeSessionId,a),p=[];if(o.lastSequence===0){let g=V(r.time_created);p.push({clock:g,order:-1,event:{type:"session_start",timestamp:Y(g),sourceEventId:`session:${t.nativeSessionId}:created:${g}`,data:{title:b(r.title)||void 0,directory:b(r.directory)||void 0,openCodeProjectId:b(r.project_id)||void 0},provenance:{source:"opencode",sourcePath:e,sourceTable:"session",sourceRowId:t.nativeSessionId}}})}p.push(...c.map(g=>Ea(e,g))),p.push(...u.map(g=>Ma(e,g)));let l=V(r.time_updated)||V(r.time_created);t.compacted&&p.push({clock:l,order:98,event:{type:"session_compact",timestamp:Y(l),sourceEventId:`session:${t.nativeSessionId}:compact:${l}`,data:{},provenance:{source:"opencode"}}}),t.error?p.push({clock:l,order:99,event:{type:"error",timestamp:Y(l),sourceEventId:`session:${t.nativeSessionId}:error:${l}`,data:{source:"session.error"},provenance:{source:"opencode"}}}):t.idle&&p.push({clock:l,order:100,event:{type:"session_idle",timestamp:Y(l),sourceEventId:`session:${t.nativeSessionId}:idle:${l}`,data:{},provenance:{source:"opencode"}}}),p.sort((g,v)=>g.clock-v.clock||g.order-v.order);let m=p.filter(g=>!ir(g.event.data)).map(g=>({...g,event:{...g.event,data:qe(g.event.data)}})),d=s.recordMany(m.map(g=>g.event)),f=pr(c,i),h=pr(u,a);if(s.setSourceCursor("opencode.message",lr(f)),s.setSourceCursor("opencode.part",lr(h)),t.idle&&m.length>0)try{let g=m.map(A=>JSON.stringify(A.event.data)),v=je(g,t.nativeSessionId);s.setSourceCursor("opencode.session.summary",v.summary),s.setSourceCursor("opencode.session.facts_count",v.durableFacts.length),Qt()&&!tn()&&s.setSourceCursor("opencode.raw_transcript.archived","local")}catch{}let y=await s.flush();return{nativeSessionId:t.nativeSessionId,importedMessages:c.length,importedParts:u.length,recordedEvents:d.length,eventCount:y.eventCount,chunkCount:y.chunkCount,status:y.status}}finally{n.close()}}async function yr(t){let e=t.dbPath??mr(),n=fr(e),r=[];try{let o=n.prepare(`
|
|
132
150
|
SELECT *
|
|
133
151
|
FROM "session"
|
|
134
152
|
ORDER BY
|
|
@@ -137,11 +155,11 @@ ${s.slice(-150)}`,delete n.output}else r!==void 0&&(n.outputSummary="[non-text t
|
|
|
137
155
|
time_created,
|
|
138
156
|
0
|
|
139
157
|
) DESC
|
|
140
|
-
`).all();for(let i of o){if(!
|
|
158
|
+
`).all();for(let i of o){if(!gr(n,i,t.project))continue;let a=b(i.id);if(a&&r.push(a),r.length>=(t.limit??100))break}}finally{n.close()}let s=[];for(let o of r)s.push(await St({project:t.project,storage:t.storage,nativeSessionId:o,dbPath:e}));return s}import{existsSync as Ra,mkdirSync as kr,readFileSync as Na,writeFileSync as br}from"node:fs";import{join as _a}from"node:path";import{homedir as Ta}from"node:os";import{join as He}from"node:path";function Ge(t={}){let e=t.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return e?He(e,"opencode"):He(t.home??Ta(),".config","opencode")}function hr(t={}){return He(Ge(t),"plugins")}function Sr(t={}){return He(Ge(t),"AGENTS.md")}var Oa="memory_agent_ask";function wr(){return`
|
|
141
159
|
[TOOLNET MEMORY AGENT]
|
|
142
160
|
|
|
143
161
|
Tool available:
|
|
144
|
-
- ${
|
|
162
|
+
- ${Oa}
|
|
145
163
|
|
|
146
164
|
Use it automatically BEFORE guessing when:
|
|
147
165
|
|
|
@@ -188,7 +206,7 @@ Rules:
|
|
|
188
206
|
- After receiving the ToolNet answer, continue the task
|
|
189
207
|
instead of asking the user to repeat known context.
|
|
190
208
|
- If ToolNet says information is not recorded, say so.
|
|
191
|
-
`.trim()}var
|
|
209
|
+
`.trim()}var vr="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",wt="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function $a(){let t=Sr();kr(Ge(),{recursive:!0});let e=`${vr}
|
|
192
210
|
## ToolNet Memory
|
|
193
211
|
|
|
194
212
|
ToolNet Memory is available for projects that already contain a valid \`.toolnet/project.json\`.
|
|
@@ -204,12 +222,12 @@ Rules:
|
|
|
204
222
|
7. Current repository evidence has priority over stale memory when they conflict.
|
|
205
223
|
|
|
206
224
|
|
|
207
|
-
${
|
|
225
|
+
${wr()}
|
|
208
226
|
|
|
209
|
-
${
|
|
227
|
+
${wt}`,n=Ra(t)?Na(t,"utf8"):"",r=n.indexOf(vr),s=n.indexOf(wt);return r>=0&&s>=r?n=n.slice(0,r)+e+n.slice(s+wt.length):(n=n.trimEnd(),n&&(n+=`
|
|
210
228
|
|
|
211
|
-
`),n+=e),
|
|
212
|
-
`,{encoding:"utf8",mode:384}),t}function
|
|
229
|
+
`),n+=e),br(t,n.trimEnd()+`
|
|
230
|
+
`,{encoding:"utf8",mode:384}),t}function xr(t={}){let e=t.directory??hr();kr(e,{recursive:!0}),$a();let n=_a(e,"toolnet-memory.js"),r=t.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`
|
|
213
231
|
// Generated by ToolNet Memory.
|
|
214
232
|
// OpenCode integration:
|
|
215
233
|
// - project gated
|
|
@@ -837,20 +855,20 @@ export const ToolNetMemoryPlugin =
|
|
|
837
855
|
},
|
|
838
856
|
}
|
|
839
857
|
}
|
|
840
|
-
`;return
|
|
841
|
-
`);if(
|
|
842
|
-
`)),i=Math.max(0,e-o);if(i>=16){let
|
|
843
|
-
`).trim()}async function
|
|
858
|
+
`;return br(n,s.trimStart(),{encoding:"utf8",mode:384}),n}import{existsSync as Mp,mkdirSync as Wa,readFileSync as Tp,writeFileSync as Fa}from"node:fs";import{dirname as za,join as Cr}from"node:path";function vt(t){if(!t)return 0;let e=Array.from(t).length,n=t.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,n*1.3))}function k(t,e){let n=t.replace(/\s+/g," ").trim();return n.length<=e?n:n.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function Ka(t){let e=[],n=!1;for(let r of t.split(/\r?\n/u)){let s=r.trim();if(s.includes("<!--")&&(n=!0),n){s.includes("-->")&&(n=!1);continue}let o=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||o.startsWith("- [enforce]")||o.startsWith("* [enforce]")||o.startsWith("- [advisory]")||o.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(k(s,280)),e.length>=16))break}return e}function La(t){let e=[],n=[];for(let r of t.split(/\\r?\\n/u)){let s=r.trim(),o=s.toLowerCase(),a=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(u=>o.startsWith(u));if(!a)continue;let c=s.slice(a.length).trim();c&&(a.includes("enforce")?e.push(c):n.push(c))}return{enforce:e,advisory:n}}function Da(t,e){let n=[];for(let r of t){let s=[...n,r].join(`
|
|
859
|
+
`);if(vt(s)<=e){n.push(r);continue}let o=vt(n.join(`
|
|
860
|
+
`)),i=Math.max(0,e-o);if(i>=16){let a=Math.floor(i*3.2),c=k(r,a);c&&n.push(c)}break}return n.join(`
|
|
861
|
+
`).trim()}async function jr(t){let e=Math.max(256,Math.min(2e3,t.maxTokens??1e3)),n=ze(t.project,!1),r=n?.content??"";r||(r=await t.storage.getText(`projects/${t.project.id}/project/manual.md`)??"");let s=La(r),o=n?n.rules.filter(d=>d.mode==="enforce").map(d=>d.text):s.enforce,i=n?n.rules.filter(d=>d.mode==="advisory").map(d=>d.text):s.advisory,a=r?Ka(r):[],c=await Ke(t.project,t.storage),u=await Zn(t.project,t.storage),p=await or(t.project,t.storage),l=[];if(l.push("[TOOLNET PROJECT CONTEXT]"),l.push(`Project: ${t.project.name}`),l.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),r&&l.push(`Full operating manual: ${Fe(t.project)}`),o.length){l.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let d of o.slice(0,24))l.push(`- [ENFORCE] ${k(d,240)}`)}if(i.length){l.push("","PROJECT PREFERENCES");for(let d of i.slice(0,10))l.push(`- ${k(d,220)}`)}if(u&&(u.mission&&l.push("","MISSION",k(u.mission.value,420)),u.activeObjective&&l.push("","CURRENT OBJECTIVE",k(u.activeObjective.value,420)),u.why&&l.push("","WHY THIS WORK MATTERS",k(u.why.value,420)),u.desiredOutcome&&l.push("","DESIRED OUTCOME",k(u.desiredOutcome.value,420)),u.planRationale&&l.push("","WHY THIS APPROACH",k(u.planRationale.value,420))),c){if(l.push("","ACTIVE WORK"),c.goal&&l.push(`Goal: ${k(c.goal,320)}`),c.plan&&l.push(`Plan: ${k(c.plan,320)}`),l.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&l.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&u){let d=u.phases.find(f=>f.order===c.currentPhase?.order);d&&(d.objective&&l.push(`Phase objective: ${k(d.objective.value,340)}`),d.why?l.push(`Why this phase: ${k(d.why.value,340)}`):l.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),d.deliverable&&l.push(`Deliverable: ${k(d.deliverable.value,340)}`),d.dependencies.length&&l.push(`Depends on: ${d.dependencies.slice(0,4).map(f=>k(f.value,180)).join("; ")}`),d.acceptanceCriteria.length&&(l.push("","DEFINITION OF DONE"),d.acceptanceCriteria.slice(0,6).forEach(f=>{l.push(`- ${k(f.value,260)}`)})),d.openQuestions.length&&(l.push("","OPEN QUESTIONS FOR CURRENT PHASE"),d.openQuestions.slice(0,4).forEach(f=>{l.push(`- ${k(f.value,260)}`)})))}c.currentTask&&l.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(l.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((d,f)=>{l.push(`${f+1}. ${k(d,260)}`)})),c.blockers.length&&(l.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(d=>{l.push(`- ${k(d,260)}`)})),c.warnings.length&&(l.push("","ATTENTION"),c.warnings.slice(-5).forEach(d=>{l.push(`- ${k(d,260)}`)})),c.decisions.length&&(l.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(d=>{l.push(`- ${k(d,260)}`)})),c.lastSession&&l.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(u&&u.openQuestions.length&&(l.push("","UNRESOLVED QUESTIONS"),u.openQuestions.slice(0,5).forEach(d=>{l.push(`- ${k(d.value,260)}`)})),p&&l.push(`Latest handoff: ${p.reason} / ${p.sourceSession.agent}`),a.length){l.push("","OPERATING NOTES");for(let d of a)l.push(`- ${d}`)}l.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let m=Da(l,e);return{version:1,projectId:t.project.id,projectName:t.project.name,text:m,estimatedTokens:vt(m),maxTokens:e,hasManual:!!r,hasWorkState:!!c,hasHandoff:!!p,generatedAt:new Date().toISOString()}}function Ba(t){return Cr(t.rootPath,".toolnet","context","startup.md")}function Va(t){return Cr(t.rootPath,".toolnet","context","startup.json")}function qa(t,e){let n=Ba(t);Wa(za(n),{recursive:!0}),Fa(n,e.text.endsWith(`
|
|
844
862
|
`)?e.text:e.text+`
|
|
845
|
-
`,{encoding:"utf8",mode:384}),
|
|
863
|
+
`,{encoding:"utf8",mode:384}),E(Va(t),e)}async function Ir(t,e,n=800){let s=(await jr({project:t,storage:e,maxTokens:n})).text;be(s)>n&&(s=xe(s,n),s+=`
|
|
846
864
|
|
|
847
865
|
[Context trimmed by ToolNet Memory token budget]
|
|
848
|
-
`);let i={version:1,projectId:t.id,projectName:t.name,text:s,digest:
|
|
866
|
+
`);let i={version:1,projectId:t.id,projectName:t.name,text:s,digest:w(s),estimatedTokens:be(s),generatedAt:new Date().toISOString()};return qa(t,i),await e.put(`projects/${t.id}/context/startup.md`,i.text+`
|
|
849
867
|
`,"text/markdown"),await e.put(`projects/${t.id}/context/startup.json`,JSON.stringify(i,null,2)+`
|
|
850
|
-
`,"application/json"),i}function
|
|
868
|
+
`,"application/json"),i}function Ue(t,e){let n=t.indexOf(e);if(!(n<0))return t[n+1]}function kt(t,e){return t.includes(e)}function Ja(t){let e=pe(),n=Ot(Mt({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new Se(n,t.id,t.name,t.remote??t.name)}async function Ha(){let[t="help",...e]=process.argv.slice(2);if(t==="install-plugin"){let i=xr({binary:Ue(e,"--bin")});console.log(`\u2705 OpenCode plugin installed: ${i}`),console.log("OpenCode will load it automatically on next start.");return}let n=Ue(e,"--project")??process.cwd(),r=new fe().detect(n),s=Ja(r),o=Ue(e,"--db");if(t==="sync"){let i=e.find(l=>!l.startsWith("--")&&l!==n&&l!==o);if(!i)throw new Error("Usage: session:opencode-sync <session-id>");let a=kt(e,"--idle"),c=kt(e,"--error"),u=kt(e,"--compacted"),p=await St({project:r,storage:s,nativeSessionId:i,dbPath:o,idle:a,error:c,compacted:u});if(a||u||c)try{await Ir(r,s,800)}catch{}console.log(JSON.stringify(p,null,2));return}if(t==="recover"){let i=Ue(e,"--limit"),a=i?Number(i):100,c=await yr({project:r,storage:s,dbPath:o,limit:Number.isFinite(a)?a:100});console.log(JSON.stringify({project:r.name,sessions:c.length,importedMessages:c.reduce((u,p)=>u+p.importedMessages,0),importedParts:c.reduce((u,p)=>u+p.importedParts,0)},null,2));return}console.log(`OpenCode Session Adapter
|
|
851
869
|
|
|
852
870
|
Commands:
|
|
853
871
|
sync <session-id> [--project PATH] [--idle]
|
|
854
872
|
recover [--project PATH] [--limit N]
|
|
855
873
|
install-plugin [--bin PATH]
|
|
856
|
-
`)}
|
|
874
|
+
`)}Ha().catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});
|