toolnet-memory 0.2.9 → 0.2.10
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 +30 -10
- package/LICENSE +21 -0
- package/README.md +146 -376
- package/bundle/agy-hook.js +25 -25
- package/bundle/agy.js +23 -23
- package/bundle/codex-context.js +12 -12
- package/bundle/codex.js +29 -29
- package/bundle/context-runtime.js +13 -13
- package/bundle/context.js +13 -13
- package/bundle/doctor.js +3 -3
- package/bundle/full-index.js +8 -8
- package/bundle/graph-index.js +4 -4
- package/bundle/impact.js +4 -4
- package/bundle/incremental.js +4 -4
- package/bundle/learner.js +5 -5
- package/bundle/mcp.js +7 -7
- package/bundle/opencode.js +34 -34
- package/bundle/project-manual.js +7 -7
- package/bundle/runtime.js +11 -11
- package/bundle/semantic.js +6 -6
- package/bundle/setup.js +57 -32
- package/bundle/snapshot.js +4 -4
- package/bundle/work-continuity.js +7 -7
- package/package.json +24 -1
package/bundle/opencode.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
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}),Ut(s,r)}function _e(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 U=class{detect(e=process.cwd()){let n=D(e),r=en(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>he(H(r,p))),i=Zt(n,o?r:void 0);if(i){let p=ye(i),u=tn(p);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),Ne(i,u)),_e(u,i)}let d=new Date().toISOString(),a=Yt(r),c={version:1,id:Qt(r),name:a,remote:a,rootPath:r,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return Ne(r,c),_e(c,r)}};var nn=[{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}],Y=class{scan(e){let n=[];for(let r of nn){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 K=class{scanner=new Y;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 vn}from"node:os";import{join as bn}from"node:path";import{DeleteObjectCommand as rn,GetObjectCommand as sn,HeadObjectCommand as on,ListObjectsV2Command as an,PutObjectCommand as cn,S3Client as un}from"@aws-sdk/client-s3";import{getSignedUrl as dn}from"@aws-sdk/s3-request-presigner";var G=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new un({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 cn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await dn(this.client,new sn({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new 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 rn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new an({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 We,mkdir as pn,readFile as ln,readdir as fn,rm as mn,stat as ze,writeFile as gn}from"node:fs/promises";import{dirname as hn,join as yn,relative as Be,resolve as Sn}from"node:path";var q=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return Sn(this.root,n)}async put(e,n){let r=this.path(e);await pn(hn(r),{recursive:!0}),await gn(r,n)}async get(e){try{return await ln(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 We(this.path(e)),!0}catch{return!1}}async delete(e){await mn(this.path(e),{force:!0})}async list(e=""){let n=this.path(e),r=[];try{await We(n)}catch{return r}let s=async i=>{let d=await fn(i,{withFileTypes:!0});for(let a of d){let c=yn(i,a.name);if(a.isDirectory()){await s(c);continue}let p=await ze(c);r.push({key:Be(this.root,c),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await ze(n);return o.isDirectory()?await s(n):r.push({key:Be(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};function Fe(t){let e=t.localRoot??bn(vn(),".toolnet-memory","storage");if(t.provider==="huggingface"){let n=t.huggingface;return n?.namespace&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new G({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new q(e))}return new q(e)}function jn(t){return new Promise(e=>setTimeout(e,t))}async function De(t,e={}){let n=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let i=1;i<=n;i++)try{return await t()}catch(d){if(o=d,i>=n)break;let a=Math.min(s,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,a*.2));await jn(a+c)}throw o}var wn=new Set(["put","get","getText","delete","list"]);function Ke(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:wn.has(r)?(...o)=>De(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function qe(t){let e=t.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Je(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 Q=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=qe(s??r),this.sourcePrefix=`projects/${n}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,n=new Date().toISOString(),r=n,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${d instanceof Error?d.message:String(d)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:n};await this.provider.put(e,JSON.stringify(o,null,2)+`
|
|
4
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=
|
|
5
|
-
`,{encoding:"utf8",mode:384})
|
|
1
|
+
import{existsSync as Bt,readFileSync as Dt}from"node:fs";import{homedir as zt}from"node:os";import{join as Ft}from"node:path";function qt(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 Jt(){let t=process.env.TOOLNET_GLOBAL_ENV??Ft(zt(),".config","toolnet-memory",".env");if(!Bt(t))return;let e=Dt(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]=qt(r.slice(s+1)))}}Jt();function D(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function z(t,e){if(!t)return e;let n=Number(t);return Number.isFinite(n)?n:e}function _e(){return{memory:{autoCapture:D(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:D(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:D(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:D(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:z(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:z(process.env.MEMORY_RERANK_TOP,10),finalContext:z(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:z(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:D(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:z(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Vt}from"node:crypto";import{existsSync as ye,mkdirSync as Ut,readFileSync as Ht,renameSync as Yt,writeFileSync as Gt}from"node:fs";import{basename as Qt,dirname as U,join as Y,parse as Ke,resolve as F}from"node:path";var We=".toolnet",Xt="project.json";function Zt(t){return Vt("sha256").update(t).digest("hex").slice(0,16)}function Se(t){return Y(t,We,Xt)}function en(t){return ye(Se(t))}function tn(t,e){let n=F(t),r=Ke(n).root;for(;;){if(en(n))return n;if(n===r||e&&n===F(e))break;let s=U(n);if(s===n)break;n=s}return null}function nn(t){let e=F(t),n=Ke(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>ye(Y(e,o))))return e;if(e===n)break;let s=U(e);if(s===e)break;e=s}return F(t)}function rn(t){let e;try{e=JSON.parse(Ht(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:U(U(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 $e(t,e){let n=Y(t,We);Ut(n,{recursive:!0});let r=Se(t),s=`${r}.tmp-${process.pid}`;Gt(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),Yt(s,r)}function Le(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 H=class{detect(e=process.cwd()){let n=F(e),r=nn(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>ye(Y(r,p))),i=tn(n,o?r:void 0);if(i){let p=Se(i),u=rn(p);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),$e(i,u)),Le(u,i)}let d=new Date().toISOString(),a=Qt(r),c={version:1,id:Zt(r),name:a,remote:a,rootPath:r,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return $e(r,c),Le(c,r)}};var sn=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],G=class{scan(e){let n=[];for(let r of sn){let s=new RegExp(r.regex.source,r.regex.flags);for(let o of e.matchAll(s))n.push({type:r.type,value:o[0]})}return n}hasSecrets(e){return this.scan(e).length>0}};var q=class{scanner=new G;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 En}from"node:os";import{join as Cn}from"node:path";import{DeleteObjectCommand as on,GetObjectCommand as an,HeadObjectCommand as cn,ListObjectsV2Command as un,PutObjectCommand as dn,S3Client as pn}from"@aws-sdk/client-s3";import{getSignedUrl as ln}from"@aws-sdk/s3-request-presigner";var Q=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new pn({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 dn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await ln(this.client,new an({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`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 cn({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 on({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new un({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 Be,mkdir as fn,readFile as mn,readdir as gn,rm as hn,stat as De,writeFile as yn}from"node:fs/promises";import{dirname as Sn,join as vn,relative as ze,resolve as bn}from"node:path";var J=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return bn(this.root,n)}async put(e,n){let r=this.path(e);await fn(Sn(r),{recursive:!0}),await yn(r,n)}async get(e){try{return await mn(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 Be(this.path(e)),!0}catch{return!1}}async delete(e){await hn(this.path(e),{force:!0})}async list(e=""){let n=this.path(e),r=[];try{await Be(n)}catch{return r}let s=async i=>{let d=await gn(i,{withFileTypes:!0});for(let a of d){let c=vn(i,a.name);if(a.isDirectory()){await s(c);continue}let p=await De(c);r.push({key:ze(this.root,c),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await De(n);return o.isDirectory()?await s(n):r.push({key:ze(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as wn,GetObjectCommand as jn,HeadObjectCommand as kn,ListObjectsV2Command as xn,PutObjectCommand as In,S3Client as On}from"@aws-sdk/client-s3";import{getSignedUrl as Pn}from"@aws-sdk/s3-request-presigner";var V=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new On({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 In({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await Pn(this.client,new jn({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 kn({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new wn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new xn({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 ve(t,e){return console.warn(e),new J(t)}function Fe(t){let e=t.localRoot??Cn(En(),".toolnet-memory","storage");if(t.provider==="r2"){let n=t.r2;return n?.accountId&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new V({name:"r2",endpoint:`https://${n.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:n.bucket,forcePathStyle:!0,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):ve(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 V({name:"s3",endpoint:n.endpoint,region:n.region??"us-east-1",bucket:n.bucket,forcePathStyle:n.forcePathStyle??!1,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):ve(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 Q({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):ve(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new J(e)}function Tn(t){return new Promise(e=>setTimeout(e,t))}async function qe(t,e={}){let n=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let i=1;i<=n;i++)try{return await t()}catch(d){if(o=d,i>=n)break;let a=Math.min(s,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,a*.2));await Tn(a+c)}throw o}var Rn=new Set(["put","get","getText","delete","list"]);function Je(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:Rn.has(r)?(...o)=>qe(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Ve(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 Ue(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 X=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=Ve(s??r),this.sourcePrefix=`projects/${n}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,n=new Date().toISOString(),r=n,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${d instanceof Error?d.message:String(d)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:n};await this.provider.put(e,JSON.stringify(o,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Ue(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 Zr}from"node:fs";import{homedir as es}from"node:os";import{isAbsolute as ts,join as ns,relative as rs,resolve as xt}from"node:path";import{DatabaseSync as ss}from"node:sqlite";import{join as Kn}from"node:path";import{createHash as An}from"node:crypto";import{dirname as Mn}from"node:path";import{mkdirSync as Nn,readFileSync as _n,renameSync as $n,writeFileSync as Ln}from"node:fs";function v(t){return An("sha256").update(t).digest("hex")}function be(t){if(Array.isArray(t))return t.map(be);if(t&&typeof t=="object"){let e=t,n={};for(let r of Object.keys(e).sort())n[r]=be(e[r]);return n}return t}function He(t){return JSON.stringify(be(t))}function Ye(t){try{return JSON.parse(_n(t,"utf8"))}catch{return null}}function x(t,e){Nn(Mn(t),{recursive:!0});let n=`${t}.${process.pid}.tmp`;Ln(n,JSON.stringify(e,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),$n(n,t)}function Ge(t,e){let n=t.trim(),r=n.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=v(n).slice(0,12);if(!r||r==="."||r==="..")return`${e}--${s}`;let o=r.slice(0,100);return o===n&&n.length<=100?o:`${o.slice(0,85)}--${s}`}function Qe(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=Ge(r.toLowerCase(),"agent"),i=Ge(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:Kn(t.rootPath,".toolnet","sessions",o,i)}}function Xe(t){return String(t).padStart(12,"0")}var Z=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
6
|
`,"application/json")}async scan(e){let n=`${e.remotePrefix}/events/`,r=await this.storage.list(n),s=[],o=0;for(let i of r){let d=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!d)continue;let a=Number(d[1]),c=Number(d[2]);!Number.isFinite(a)||!Number.isFinite(c)||(s.push({key:i.key,start:a,end:c}),o=Math.max(o,c))}return s.sort((i,d)=>i.start-d.start),{chunks:s,maxSequence:o}}split(e){let n=[],r=[],s=0;for(let o of e){let i=Buffer.byteLength(JSON.stringify(o)+`
|
|
7
|
-
`,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),d=n.filter(m=>m.sequence>i.maxSequence),a=0;for(let m of this.split(d)){let S=m[0],E=m[m.length-1],
|
|
7
|
+
`,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),d=n.filter(m=>m.sequence>i.maxSequence),a=0;for(let m of this.split(d)){let S=m[0],E=m[m.length-1],A=m.map(M=>JSON.stringify(M)).join(`
|
|
8
8
|
`)+`
|
|
9
|
-
`,_=v(
|
|
9
|
+
`,_=v(A).slice(0,16),C=[e.remotePrefix,"events",`${Xe(S.sequence)}-${Xe(E.sequence)}-${_}.jsonl`].join("/");await this.storage.exists(C)||await this.storage.put(C,A,"application/x-ndjson"),a+=m.length}let c=await this.scan(e),p=n[n.length-1],u=o?.status??"active";p?.type==="session_end"||p?.type==="session_idle"?u="idle":p?.type==="error"?u="error":n.length>0&&(u="active");let g=new Date().toISOString(),l=n[0],y={version:1,projectId:e.projectId,projectName:e.projectName,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,status:u,createdAt:o?.createdAt??l?.timestamp??g,updatedAt:p?.timestamp??g,firstEventAt:o?.firstEventAt??l?.timestamp,lastEventAt:p?.timestamp??o?.lastEventAt,eventCount:c.maxSequence,chunkCount:c.chunks.length,metadata:{...o?.metadata,...s.metadata}};(s.title??o?.title)&&(y.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:c.maxSequence,lastRemoteSequence:c.maxSequence,sourceCursors:r,updatedAt:g};return await this.putJson(`${e.remotePrefix}/cursor.json`,h),await this.putJson(`${e.remotePrefix}/session.json`,y),{uploadedEvents:a,lastRemoteSequence:c.maxSequence,eventCount:y.eventCount,chunkCount:y.chunkCount,status:u}}};import{closeSync as we,existsSync as Wn,fsyncSync as Bn,mkdirSync as Dn,openSync as je,readSync as zn,rmSync as Ze,statSync as et,writeSync as Fn}from"node:fs";import{join as ke}from"node:path";var qn=12e4,Jn=80,Vn=2e3;function Un(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}var ee=class{constructor(e){this.identity=e;Dn(e.localDirectory,{recursive:!0}),this.eventsFile=ke(e.localDirectory,"events.jsonl"),this.stateFile=ke(e.localDirectory,"state.json"),this.lockFile=ke(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 Ye(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(e){x(this.stateFile,e)}acquireLock(){for(let e=0;e<Jn;e+=1)try{return je(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-et(this.lockFile).mtimeMs>qn){Ze(this.lockFile,{force:!0});continue}}catch{}Un(25)}throw new Error(`Session journal is locked: ${this.lockFile}`)}withLock(e){let n=this.acquireLock();try{return e()}finally{we(n),Ze(this.lockFile,{force:!0})}}append(e){return e.length===0?[]:this.withLock(()=>{let n=this.loadStateUnsafe(),r=new Set(n.recentEventIds),s=n.lastSequence,o=[];for(let u of e){let g=u.timestamp??new Date().toISOString(),l=u.data??{},y=u.provenance?.rawDigest??v(He(l)),h=u.sourceEventId?[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,u.sourceEventId].join("|"):[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,s+1,u.type,g,y].join("|"),m=v(h).slice(0,32);if(r.has(m))continue;s+=1;let S={version:1,id:m,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,type:u.type,timestamp:g,data:l,provenance:{...u.provenance,rawDigest:y}};u.role!==void 0&&(S.role=u.role),u.sourceEventId!==void 0&&(S.sourceEventId=u.sourceEventId),u.sourceSequence!==void 0&&(S.sourceSequence=u.sourceSequence),o.push(S),r.add(m)}if(o.length===0)return[];let i=o.map(u=>JSON.stringify(u)).join(`
|
|
10
10
|
`)+`
|
|
11
|
-
`,d=
|
|
12
|
-
`).filter(Boolean).map(c=>JSON.parse(c)),startOffset:r,endOffset:n}})}markRemote(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,lastRemoteSequence:Math.max(r.lastRemoteSequence,e),remoteByteOffset:Math.max(r.remoteByteOffset,n),updatedAt:new Date().toISOString()})})}setSourceCursor(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,sourceCursors:{...r.sourceCursors,[e]:String(n)},updatedAt:new Date().toISOString()})})}};import{closeSync as
|
|
13
|
-
`,a=v(r.map(p=>p.fingerprint).sort().join("|")).slice(0,16),c=[
|
|
11
|
+
`,d=je(this.eventsFile,"a",384);try{Fn(d,i,null,"utf8"),Bn(d)}finally{we(d)}let a=o[o.length-1],c="active";a.type==="session_end"||a.type==="session_idle"?c="idle":a.type==="error"&&(c="error");let p=Array.from(r).slice(-Vn);return this.saveStateUnsafe({...n,status:c,updatedAt:a.timestamp,lastSequence:a.sequence,recentEventIds:p}),o})}readPending(){return this.withLock(()=>{let e=this.loadStateUnsafe();if(!Wn(this.eventsFile))return{events:[],startOffset:e.remoteByteOffset,endOffset:e.remoteByteOffset};let n=et(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=je(this.eventsFile,"r");try{zn(i,o,0,s,r)}finally{we(i)}return{events:o.toString("utf8").split(`
|
|
12
|
+
`).filter(Boolean).map(c=>JSON.parse(c)),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 ur,existsSync as dr,openSync as pr,readSync as lr,statSync as fr}from"node:fs";function tt(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 ot=[/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],Hn=[/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],Yn=[/\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],Gn=[/\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],Qn=[/đã 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],nt=[/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],Xn=[/\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],Zn=[/đườ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],er=[/\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],rt=new Set(["content","text","message","prompt","summary","description","reason","title","last_assistant_message","lastAssistantMessage","input_messages","inputMessages"]),tr=new Set(["payload","data","content","message","messages","parts","summary"]);function I(t,e){return e.some(n=>n.test(t))}function it(t){return t.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function nr(t){return it(t).toLowerCase().replace(/[^\p{L}\p{N}:/._-]+/gu," ").replace(/\s+/g," ").trim()}function rr(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 xe(t,e,n,r=0){if(!(r>6)){if(typeof t=="string"){(!e||rt.has(e))&&n.push(t);return}if(Array.isArray(t)){for(let s of t.slice(0,50))xe(s,e,n,r+1);return}if(!(!t||typeof t!="object"))for(let[s,o]of Object.entries(t))(rt.has(s)||tr.has(s))&&xe(o,s,n,r+1)}}function sr(t){let e=[];xe(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=it(o);if(rr(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function st(t){return(t.role??(typeof t.data.role=="string"?t.data.role:"")).toLowerCase()}function or(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&&I(t,ot)?{kind:"rule",confidence:.98}:r&&I(t,Hn)?{kind:"rule",confidence:.92}:I(t,Yn)?{kind:I(t,nt)?"architecture":"decision",confidence:r?.93:.86}:r&&I(t,Gn)?{kind:"todo",confidence:.87}:I(t,nt)&&I(t,Xn)?{kind:"architecture",confidence:r?.88:.82}:s&&I(t,Qn)?{kind:"fix",confidence:.8}:r&&I(t,Zn)&&I(t,er)?{kind:"context",confidence:.79}:null}function ir(t){switch(t){case"rule":return"rule";case"decision":case"architecture":return"decision";case"todo":return"todo";case"fix":case"context":return"code"}}function ar(t,e,n){return t==="rule"&&I(n,ot)?"critical":t==="architecture"||t==="decision"||t==="rule"?"high":t==="fix"||t==="context"?"normal":tt(e,n)}function at(t,e){let n=[],r=new Set,s=new Map;for(let o of e){let i=typeof o.data.messageId=="string"?o.data.messageId:void 0,d=st(o);i&&d&&s.set(i,d)}for(let o of e){let i=st(o),d=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&d&&(i=s.get(d)??"");for(let a of sr(o)){let c=or(a,i,o);if(!c||c.confidence<.75)continue;let p=ir(c.kind),u=nr(a),g=v([t.projectId,c.kind,u].join("|"));if(r.has(g))continue;r.add(g);let l=o.provenance.sourcePath?[o.provenance.sourcePath]:[],y=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:g,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,kind:c.kind,type:p,content:a,confidence:c.confidence,importance:ar(c.kind,p,a),tags:[p],provenance:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventIds:[o.id],sourceEventIds:y,sourcePaths:l,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}function ct(t){return String(t).padStart(12,"0")}function cr(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},d=JSON.stringify(i,null,2)+`
|
|
13
|
+
`,a=v(r.map(p=>p.fingerprint).sort().join("|")).slice(0,16),c=[cr(e),"batches",`${ct(s)}-${ct(o)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,d,"application/json"),c}};function mr(t,e){if(!dr(t))return{events:[],nextOffset:e};let n=fr(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=pr(t,"r");try{lr(i,o,0,s,r)}finally{ur(i)}let d=o.toString("utf8"),a=d.lastIndexOf(`
|
|
14
14
|
`);if(a<0)return{events:[],nextOffset:r};let c=d.slice(0,a+1);return{events:c.split(`
|
|
15
|
-
`).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var
|
|
16
|
-
`,d=v(n.map(c=>c.id).sort().join("|")).slice(0,16),a=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${
|
|
17
|
-
`,"application/json"),C}async function
|
|
15
|
+
`).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var ne=class{constructor(e){this.options=e;this.journal=new te(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["memory.learner.offset"]??0),r=Number.isFinite(n)?n:0,s=mr(this.options.wal.eventsFile,r);if(s.events.length===0)return{scannedEvents:0,candidates:0,journalWritten:!1,nextOffset:s.nextOffset};let o=at(this.options.identity,s.events),i=!1;return o.length>0&&(i=!!await this.journal.write(this.options.identity,s.events,o)),this.options.wal.setSourceCursor("memory.learner.offset",s.nextOffset),{scannedEvents:s.events.length,candidates:o.length,journalWritten:i,nextOffset:s.nextOffset}}};import{closeSync as wr,existsSync as jr,openSync as kr,readSync as xr,statSync as Ir}from"node:fs";var gr=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function L(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function dt(t){return L(t).toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function $(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))$(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(gr.has(r)||["data","payload","parts","messages"].includes(r))&&$(s,e,n+1)}}function re(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 ut(t){let e=L(t);return/^(?:đang\s+làm|đang\s+thực\s+hiện|đang\s+xử\s+lý|đang\s+triển\s+khai|hoàn\s+thành|hoàn\s+tất|đã\s+xong|đã\s+làm\s+xong|xong|pending|in[\s_-]*progress|completed|complete|done|finished|blocked|cancelled|canceled)[.!]*$/iu.test(e)}function j(t,e,n,r,s={}){let o=L(r),i=s.key??dt(o);return{version:1,id:v([t.projectId,n,i,e.id,o,s.status??"",s.order??""].join("|")).slice(0,32),projectId:t.projectId,kind:n,key:i,text:o,status:s.status,order:s.order,confidence:s.confidence??.85,occurredAt:e.timestamp,sequence:e.sequence,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId}}function hr(t,e,n){let r=L(n);if(r.length<5||r.length>1200)return[];let s=[],o=/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r),i=r.match(/^(?:mục tiêu|goal|objective)\s*(?::|-)\s*(.+)$/iu);i?.[1]&&s.push(j(t,e,"goal",i[1],{confidence:.97}));let d=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);d?.[1]&&s.push(j(t,e,"plan",d[1],{confidence:.95}));let a=/\b(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?([^.;\n]{0,220})/giu,c;for(;!o&&(c=a.exec(r));){let g=Number(c[1]),l=L(c[2]??""),y=l&&!ut(l)?`Phase ${g} - ${l}`:`Phase ${g}`;s.push(j(t,e,"phase",y,{key:`phase:${g}`,order:g,status:re(r),confidence:.93}))}let p=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);p?.[2]&&s.push(j(t,e,"task",p[2],{status:p[1].trim()?"completed":re(p[2]),confidence:.96}));let u=r.match(/^(?:todo|task|việc)\s*(\d+)?(?:\s*[:.\-–—]\s*|\s+)(.+)$/iu);if(u?.[2]){let g=u[1]?Number(u[1]):void 0,l=L(u[2]),y=ut(l);s.push(j(t,e,"task",y&&g!==void 0?`TODO ${g}`:l,{key:g!==void 0?`task:${g}`:dt(l),order:g,status:re(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 g=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");g&&s.push(j(t,e,"next_action",g,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(j(t,e,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(j(t,e,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(j(t,e,"decision",r,{confidence:.9})),s}function pt(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 a=[];$(i.data,a);for(let c of a)s(j(t,i,"decision",c,{confidence:1}))}if(i.type==="todo"){let a=[];$(i.data,a);for(let c of a)s(j(t,i,"task",c,{status:re(c),confidence:1}))}if(["file_write","file_edit"].includes(i.type))for(let a of["filePath","path","file"]){let c=i.data[a];typeof c=="string"&&c&&s(j(t,i,"file",c,{confidence:1}))}if(i.type==="test"){let a=[];$(i.data,a);for(let c of a)s(j(t,i,"test",c,{confidence:1}))}let d=[];$(i.data,d);for(let a of d)for(let c of a.split(/\n+/u))for(let p of hr(t,i,c))s(p)}let o=e[e.length-1];return s(j(t,o,"session",`${t.agent}:${t.nativeSessionId}`,{key:t.sessionKey,confidence:1})),n}function lt(t){return String(t).padStart(12,"0")}var se=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.sequence)),s=Math.max(...n.map(c=>c.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:r,lastSequence:s,observations:n},i=JSON.stringify(o,null,2)+`
|
|
16
|
+
`,d=v(n.map(c=>c.id).sort().join("|")).slice(0,16),a=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${lt(r)}-${lt(s)}-${d}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,i,"application/json"),a}};import{join as ft}from"node:path";import{mkdirSync as yr}from"node:fs";function Sr(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function K(t,e=20){let n=[],r=new Set;for(let s of t.slice().reverse()){let o=Sr(s);if(!(!o||r.has(o))&&(r.add(o),n.push(s),n.length>=e))break}return n.reverse()}function vr(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 mt(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&&vr(e)?t.title:e.text;return{id:t?.id??v(e.key).slice(0,24),title:s,status:r,order:e.order??t?.order,confidence:Math.max(e.confidence,t?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function br(t,e){let n=`projects/${t.id}/work/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,d)=>i.key.localeCompare(d.key))){let i=await e.getText(o.key);if(i)try{let d=JSON.parse(i);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}async function oe(t,e){let r=(await br(t,e)).flatMap(f=>f.observations).sort((f,k)=>{let Me=f.occurredAt.localeCompare(k.occurredAt);if(Me!==0)return Me;let Ne=f.sequence-k.sequence;return Ne!==0?Ne:f.id.localeCompare(k.id)}),s=new Map,o=new Map,i,d,a,c=[],p=[],u=[],g=[],l=[],y=[];for(let f of r)switch(f.kind){case"goal":i=f.text;break;case"plan":d=f.text;break;case"phase":s.set(f.key,mt(s.get(f.key),f));break;case"task":o.set(f.key,mt(o.get(f.key),f));break;case"decision":c.push(f.text);break;case"blocker":p.push(f.text);break;case"warning":u.push(f.text);break;case"next_action":g.push(f.text);break;case"file":l.push(f.text);break;case"test":y.push(f.text);break;case"session":a={agent:f.agent,nativeSessionId:f.nativeSessionId,sessionKey:f.sessionKey,updatedAt:f.occurredAt};break}let h=Array.from(s.values()).sort((f,k)=>(f.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),m=Array.from(o.values()).sort((f,k)=>(f.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),S=h.find(f=>f.status==="in_progress")??h.find(f=>f.status==="blocked")??h.find(f=>f.status==="pending"),E=m.find(f=>f.status==="in_progress")??m.find(f=>f.status==="blocked")??m.find(f=>f.status==="pending"),A=K([...g,...E?[E.title]:[],...!E&&S?[S.title]:[],...m.filter(f=>f.status==="pending").slice(0,5).map(f=>f.title)],8),_=K([...p,...h.filter(f=>f.status==="blocked").map(f=>f.title),...m.filter(f=>f.status==="blocked").map(f=>f.title)],20),C={version:1,projectId:t.id,projectName:t.name,goal:i,plan:d,phases:h,tasks:m,decisions:K(c,20),blockers:_,warnings:K(u,20),nextActions:A,filesTouched:K(l,30),tests:K(y,20),currentPhase:S,currentTask:E,progress:{phasesTotal:h.length,phasesCompleted:h.filter(f=>f.status==="completed").length,tasksTotal:m.length,tasksCompleted:m.filter(f=>f.status==="completed").length,blocked:h.filter(f=>f.status==="blocked").length+m.filter(f=>f.status==="blocked").length},lastSession:a,updatedAt:r.length?r[r.length-1].occurredAt:new Date().toISOString()},M=ft(t.rootPath,".toolnet","work");return yr(M,{recursive:!0}),x(ft(M,"current.json"),C),await e.put(`projects/${t.id}/work/current.json`,JSON.stringify(C,null,2)+`
|
|
17
|
+
`,"application/json"),C}async function ie(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 Or(t,e){if(!jr(t))return{events:[],nextOffset:e};let n=Ir(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=kr(t,"r");try{xr(i,o,0,s,r)}finally{wr(i)}let d=o.toString("utf8"),a=d.lastIndexOf(`
|
|
18
18
|
`);if(a<0)return{events:[],nextOffset:r};let c=d.slice(0,a+1);return{events:c.split(`
|
|
19
|
-
`).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var
|
|
20
|
-
`,"application/json"),d}};import{mkdirSync as
|
|
21
|
-
`,"application/json"),l}async function
|
|
19
|
+
`).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var ae=class{constructor(e){this.options=e;this.journal=new se(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.continuity.offset"]??0),r=Or(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=pt(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await oe(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 _r,existsSync as $r,openSync as Lr,readSync as Kr,statSync as Wr}from"node:fs";var Pr=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function W(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function Ie(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))Ie(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Pr.has(r)||["data","payload","parts","messages"].includes(r))&&Ie(s,e,n+1)}}function O(t,e,n,r,s,o=.95){let i=W(r);return{version:1,id:v([t.projectId,n,s.type,s.key??"",i.toLowerCase(),e.id].join("|")).slice(0,32),projectId:t.projectId,kind:n,value:i,scope:s.type,scopeKey:s.key,scopeOrder:s.order,confidence:o,evidence:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId,sequence:e.sequence,occurredAt:e.timestamp}}}function P(t,e){let n=t.toLowerCase();for(let r of e){let s=r.toLowerCase();if(n.startsWith(`${s}:`)||n.startsWith(`${s} -`)||n.startsWith(`${s} \u2014`))return W(t.slice(r.length+1))}return null}function Er(t){let e=t.trimStart();return e.startsWith("- ")||e.startsWith("* ")||/^\d+[.)]\s+/u.test(e)}function Cr(t){return W(t.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function gt(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=[];Ie(o.data,i);for(let d of i){let a={type:"project"},c=null;for(let p of d.split(/\r?\n/u)){let u=W(p);if(!u){c=null;continue}let g=u.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(g){let k=Number(g[1]);a={type:"phase",key:`phase:${k}`,order:k,title:W(g[2]??"")},c=null;continue}let l=u.match(/^(?:todo|task|việc)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(l){let k=Number(l[1]);a={type:"task",key:`task:${k}`,order:k,title:W(l[2]??"")},c=null;continue}let y=P(u,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(y){s(O(t,o,"mission",y,{type:"project"},.99)),c=null;continue}let h=P(u,["current objective","active objective","m\u1EE5c ti\xEAu hi\u1EC7n t\u1EA1i","objective","m\u1EE5c ti\xEAu","m\u1EE5c \u0111\xEDch"]);if(h){s(O(t,o,a.type==="phase"?"phase_objective":"objective",h,a,.98)),c=null;continue}let m=P(u,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(m){s(O(t,o,a.type==="phase"?"phase_why":"why",m,a,.98)),c=null;continue}let S=P(u,["desired outcome","final outcome","k\u1EBFt qu\u1EA3 cu\u1ED1i","k\u1EBFt qu\u1EA3 mong mu\u1ED1n","m\u1EE5c ti\xEAu cu\u1ED1i"]);if(S){s(O(t,o,"desired_outcome",S,{type:"project"},.98)),c=null;continue}let E=P(u,["plan rationale","approach rationale","why this approach","t\u1EA1i sao ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn ki\u1EBFn tr\xFAc"]);if(E){s(O(t,o,"plan_rationale",E,{type:"project"},.98)),c=null;continue}let A=P(u,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(A){s(O(t,o,"phase_deliverable",A,a,.97)),c=null;continue}let _=P(u,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if(_){s(O(t,o,"acceptance_criterion",_,a,.98)),c="acceptance_criterion";continue}let C=P(u,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(C){s(O(t,o,"dependency",C,a,.97)),c="dependency";continue}let M=P(u,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(M){s(O(t,o,"open_question",M,a,.95)),c="open_question";continue}let f=P(u,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(f){s(O(t,o,"constraint",f,a,.97)),c="constraint";continue}if(/^(?:acceptance criteria|definition of done|done khi|tiêu chí hoàn thành)\s*:?\s*$/iu.test(u)){c="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(u)){c="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(u)){c="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(u)){c="constraint";continue}if(c&&Er(p)){s(O(t,o,c,Cr(p),a,.96));continue}c=null}}}return n}function ht(t){return String(t).padStart(12,"0")}var ce=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(a=>a.evidence.sequence)),s=Math.max(...n.map(a=>a.evidence.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,firstSequence:r,lastSequence:s,createdAt:new Date().toISOString(),observations:n},i=v(n.map(a=>a.id).sort().join("|")).slice(0,16),d=[`projects/${e.projectId}`,"work","semantic","observations",e.agent,e.nativeSessionId,`${ht(r)}-${ht(s)}-${i}.json`].join("/");return await this.storage.exists(d)||await this.storage.put(d,JSON.stringify(o,null,2)+`
|
|
20
|
+
`,"application/json"),d}};import{mkdirSync as Tr}from"node:fs";import{join as yt}from"node:path";function Rr(t){return{value:t.value,confidence:t.confidence,evidence:t.evidence}}function Ar(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 T(t,e){return Ar(e,t)?e:t}function R(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 Mr(t,e){let n=`projects/${t.id}/work/semantic/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,d)=>i.key.localeCompare(d.key))){let i=await e.getText(o.key);if(i)try{let d=JSON.parse(i);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}function Nr(t){return{key:t.scopeKey??`phase:${t.scopeOrder??0}`,order:t.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function St(t,e){let r=(await Mr(t,e)).flatMap(h=>h.observations).sort((h,m)=>{let S=h.evidence.occurredAt.localeCompare(m.evidence.occurredAt);return S!==0?S:h.evidence.sessionKey===m.evidence.sessionKey?h.evidence.sequence-m.evidence.sequence:h.id.localeCompare(m.id)}),s,o,i,d,a,c=new Map,p=[],u=[],g=[];for(let h of r){let m=Rr(h);if(h.scope==="phase"&&h.scopeKey){let S=c.get(h.scopeKey)??Nr(h);switch(h.kind){case"phase_objective":S.objective=T(S.objective,m);break;case"phase_why":S.why=T(S.why,m);break;case"phase_deliverable":S.deliverable=T(S.deliverable,m);break;case"acceptance_criterion":S.acceptanceCriteria.push(m);break;case"dependency":S.dependencies.push(m);break;case"open_question":S.openQuestions.push(m);break;case"constraint":S.constraints.push(m);break;case"note":S.notes.push(m);break}c.set(S.key,S);continue}switch(h.kind){case"mission":s=T(s,m);break;case"objective":o=T(o,m);break;case"why":i=T(i,m);break;case"desired_outcome":d=T(d,m);break;case"plan_rationale":a=T(a,m);break;case"open_question":p.push(m);break;case"constraint":u.push(m);break;case"note":g.push(m);break}}for(let h of c.values())h.acceptanceCriteria=R(h.acceptanceCriteria,20),h.dependencies=R(h.dependencies,15),h.openQuestions=R(h.openQuestions,15),h.constraints=R(h.constraints,15),h.notes=R(h.notes,20);let l={version:1,projectId:t.id,projectName:t.name,mission:s,activeObjective:o,why:i,desiredOutcome:d,planRationale:a,phases:Array.from(c.values()).sort((h,m)=>h.order-m.order),openQuestions:R(p,20),constraints:R(u,20),notes:R(g,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},y=yt(t.rootPath,".toolnet","work");return Tr(y,{recursive:!0}),x(yt(y,"semantic-current.json"),l),await e.put(`projects/${t.id}/work/semantic/current.json`,JSON.stringify(l,null,2)+`
|
|
21
|
+
`,"application/json"),l}async function vt(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 Br(t,e){if(!$r(t))return{events:[],nextOffset:e};let n=Wr(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=Lr(t,"r");try{Kr(o,s,0,s.length,r)}finally{_r(o)}let i=s.toString("utf8"),d=i.lastIndexOf(`
|
|
22
22
|
`);if(d<0)return{events:[],nextOffset:r};let a=i.slice(0,d+1);return{events:a.split(`
|
|
23
|
-
`).filter(Boolean).flatMap(c=>{try{return[JSON.parse(c)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var
|
|
23
|
+
`).filter(Boolean).flatMap(c=>{try{return[JSON.parse(c)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var ue=class{constructor(e){this.options=e;this.journal=new ce(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.semantic.offset"]??0),r=Br(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=gt(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await St(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 Gr}from"node:fs";import{join as Oe}from"node:path";import{existsSync as jt,mkdirSync as Dr,readFileSync as zr,statSync as bt,writeFileSync as Fr}from"node:fs";import{dirname as qr,join as Jr}from"node:path";var wt=64*1024,Vr=`# ToolNet Project Operating Manual
|
|
24
24
|
|
|
25
25
|
This file contains persistent instructions for AI agents working on this project.
|
|
26
26
|
|
|
@@ -63,29 +63,29 @@ Things an AI agent should always remember.
|
|
|
63
63
|
<!--
|
|
64
64
|
- [advisory] Prefer small focused files.
|
|
65
65
|
-->
|
|
66
|
-
`;function
|
|
66
|
+
`;function de(t){return Jr(t.rootPath,".toolnet","PROJECT.md")}function Ur(t){return t.normalize("NFKC").replace(/\s+/g," ").trim()}function Hr(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=Ur(s[2]);if(!i)continue;let d=`${o}:${i.toLowerCase()}`;n.has(d)||(n.add(d),e.push({id:v(d).slice(0,24),mode:o,text:i,source:"manual"}))}return e}function Yr(t){let e=de(t);return jt(e)||(Dr(qr(e),{recursive:!0}),Fr(e,Vr,{encoding:"utf8",mode:384})),e}function pe(t,e=!1){let n=e?Yr(t):de(t);if(!jt(n))return null;if(bt(n).size>wt)throw new Error(`PROJECT.md exceeds ${wt} bytes`);let s=zr(n,"utf8");return{path:n,content:s,digest:v(s),rules:Hr(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(bt(n).mtimeMs).toISOString()}}function Qr(t){return{goal:t.goal,plan:t.plan,phases:t.phases.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),tasks:t.tasks.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),decisions:t.decisions,blockers:t.blockers,warnings:t.warnings,nextActions:t.nextActions,filesTouched:t.filesTouched,tests:t.tests}}function Xr(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 le=class{constructor(e){this.options=e}options;async capture(e,n){let r=await ie(this.options.project,this.options.storage);if(r||(r=await oe(this.options.project,this.options.storage)),!Xr(r))return null;let s=pe(this.options.project,!1),o=s?s.rules.filter(g=>g.mode==="enforce").map(g=>g.text):[],i=v(JSON.stringify(Qr(r))),d=v([this.options.project.id,this.options.identity.sessionKey,i].join("|")).slice(0,24),a=new Date().toISOString(),c={version:1,id:d,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:a,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(g=>g.status!=="completed"&&g.status!=="cancelled"),incompleteTasks:r.tasks.filter(g=>g.status!=="completed"&&g.status!=="cancelled"),nextActions:r.nextActions.slice(0,10),blockers:r.blockers.slice(0,10),decisions:r.decisions.slice(-10),warnings:r.warnings.slice(-10),attention:[...o,...r.warnings].slice(0,20),filesTouched:r.filesTouched.slice(-20),tests:r.tests.slice(-15),stateDigest:i},p=`projects/${this.options.project.id}/work/handoffs/${d}.json`;await this.options.storage.exists(p)||await this.options.storage.put(p,JSON.stringify(c,null,2)+`
|
|
67
67
|
`,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(c,null,2)+`
|
|
68
|
-
`,"application/json");let u=
|
|
68
|
+
`,"application/json");let u=Oe(this.options.project.rootPath,".toolnet","work","handoffs");return Gr(u,{recursive:!0}),x(Oe(u,`${d}.json`),c),x(Oe(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),c),c}};async function kt(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 fe=class{identity;wal;remote;sanitizer=new q;learner;continuity;semantic;handoff;title;metadata;constructor(e){this.identity=Qe(e.project,e.agent,e.nativeSessionId),this.title=e.title,this.metadata=this.sanitizer.sanitizeValue(e.metadata??{}),this.wal=new ee(this.identity),this.remote=new Z(e.storage,e.maxEventsPerChunk??100,e.maxChunkBytes??512*1024),this.learner=new ne({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.continuity=new ae({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.semantic=new ue({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.handoff=new le({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)}};function Ct(){return process.env.OPENCODE_DB_PATH??ns(es(),".local","share","opencode","opencode.db")}function w(t){return typeof t=="string"?t:""}function N(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 Pe(t){if(t&&typeof t=="object"&&!Buffer.isBuffer(t))return t;if(typeof t!="string")return{};try{let e=JSON.parse(t);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{}}function B(t){let e=N(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 me(t,e){if(!e)return!1;let n=xt(t),r=xt(e);if(n===r)return!0;let s=rs(n,r);return s!==""&&s!==".."&&!s.startsWith(`..${process.platform==="win32"?"\\":"/"}`)&&!ts(s)}function It(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 Ot(t){return JSON.stringify(t)}function Tt(t){if(!Zr(t))throw new Error(`OpenCode database not found: ${t}`);let e=new ss(t,{readOnly:!0});return e.exec("PRAGMA query_only = ON"),e.exec("PRAGMA busy_timeout = 3000"),e}function os(t,e){let n=t.prepare(`
|
|
69
69
|
SELECT *
|
|
70
70
|
FROM "session"
|
|
71
71
|
WHERE id = ?
|
|
72
72
|
LIMIT 1
|
|
73
|
-
`).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function
|
|
73
|
+
`).get(e);if(!n)throw new Error(`OpenCode session not found: ${e}`);return n}function Rt(t,e,n){let r=w(e.directory);if(r&&me(n.rootPath,r))return!0;let s=w(e.project_id);if(s){try{let o=t.prepare(`
|
|
74
74
|
SELECT *
|
|
75
75
|
FROM "project"
|
|
76
76
|
WHERE id = ?
|
|
77
77
|
LIMIT 1
|
|
78
|
-
`).get(s);if(o)for(let i of["worktree","directory","path"]){let d=
|
|
78
|
+
`).get(s);if(o)for(let i of["worktree","directory","path"]){let d=w(o[i]);if(d&&me(n.rootPath,d))return!0}}catch{}try{if(t.prepare(`
|
|
79
79
|
SELECT directory
|
|
80
80
|
FROM "project_directory"
|
|
81
81
|
WHERE project_id = ?
|
|
82
|
-
`).all(s).some(i=>
|
|
82
|
+
`).all(s).some(i=>me(n.rootPath,w(i.directory))))return!0}catch{}}try{let o=t.prepare(`
|
|
83
83
|
SELECT data
|
|
84
84
|
FROM "message"
|
|
85
85
|
WHERE session_id = ?
|
|
86
86
|
ORDER BY time_created DESC
|
|
87
87
|
LIMIT 20
|
|
88
|
-
`).all(
|
|
88
|
+
`).all(w(e.id));for(let i of o){let d=Pe(i.data),a=d.path&&typeof d.path=="object"?d.path:{};for(let c of[w(a.cwd),w(a.root)])if(c&&me(n.rootPath,c))return!0}}catch{}return!1}function Pt(t,e,n,r){let s=`
|
|
89
89
|
SELECT *,
|
|
90
90
|
COALESCE(
|
|
91
91
|
time_updated,
|
|
@@ -116,7 +116,7 @@ Things an AI agent should always remember.
|
|
|
116
116
|
0
|
|
117
117
|
) ASC,
|
|
118
118
|
id ASC
|
|
119
|
-
`;return t.prepare(s).all(n,r.time,r.time,r.id)}function
|
|
119
|
+
`;return t.prepare(s).all(n,r.time,r.time,r.id)}function Et(t,e){let n=t[t.length-1];return n?{time:N(n.__clock),id:w(n.id)}:e}function is(t,e){let n=Pe(e.data),r=w(n.role),s=N(e.__clock),o=w(e.id),i="message";return r==="user"?i="user_prompt":r==="assistant"&&(i="assistant_message"),{clock:s,order:0,event:{type:i,timestamp:B(s),role:r||void 0,sourceEventId:`message:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{messageId:o,...n},provenance:{source:"opencode",sourcePath:t,sourceTable:"message",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}function as(t,e){let n=Pe(e.data),r=w(n.type),s=N(e.__clock),o=w(e.id),i=w(e.message_id),d="message_part";return r==="tool"?d="tool_call":r==="snapshot"&&(d="artifact"),{clock:s,order:1,event:{type:d,timestamp:B(s),sourceEventId:`part:${o}:${s}`,sourceSequence:`${s}:${o}`,data:{partId:o,messageId:i,...n},provenance:{source:"opencode",sourcePath:t,sourceTable:"part",sourceRowId:o,sourceOffset:`${s}:${o}`}}}}async function Ee(t){let e=t.dbPath??Ct(),n=Tt(e);try{let r=os(n,t.nativeSessionId);if(!Rt(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: ${w(r.directory)||"unknown"}`].join(" "));let s=new fe({project:t.project,storage:t.storage,agent:"opencode",nativeSessionId:t.nativeSessionId,title:w(r.title)||void 0,metadata:{source:"opencode.db",openCodeProjectId:w(r.project_id)||void 0,directory:w(r.directory)||void 0}}),o=s.status(),i=It(o.sourceCursors["opencode.message"]),d=It(o.sourceCursors["opencode.part"]),a=Pt(n,"message",t.nativeSessionId,i),c=Pt(n,"part",t.nativeSessionId,d),p=[];if(o.lastSequence===0){let m=N(r.time_created);p.push({clock:m,order:-1,event:{type:"session_start",timestamp:B(m),sourceEventId:`session:${t.nativeSessionId}:created:${m}`,data:{title:w(r.title)||void 0,directory:w(r.directory)||void 0,openCodeProjectId:w(r.project_id)||void 0},provenance:{source:"opencode",sourcePath:e,sourceTable:"session",sourceRowId:t.nativeSessionId}}})}p.push(...a.map(m=>is(e,m))),p.push(...c.map(m=>as(e,m)));let u=N(r.time_updated)||N(r.time_created);t.compacted&&p.push({clock:u,order:98,event:{type:"session_compact",timestamp:B(u),sourceEventId:`session:${t.nativeSessionId}:compact:${u}`,data:{},provenance:{source:"opencode"}}}),t.error?p.push({clock:u,order:99,event:{type:"error",timestamp:B(u),sourceEventId:`session:${t.nativeSessionId}:error:${u}`,data:{source:"session.error"},provenance:{source:"opencode"}}}):t.idle&&p.push({clock:u,order:100,event:{type:"session_idle",timestamp:B(u),sourceEventId:`session:${t.nativeSessionId}:idle:${u}`,data:{},provenance:{source:"opencode"}}}),p.sort((m,S)=>m.clock-S.clock||m.order-S.order);let g=s.recordMany(p.map(m=>m.event)),l=Et(a,i),y=Et(c,d);s.setSourceCursor("opencode.message",Ot(l)),s.setSourceCursor("opencode.part",Ot(y));let h=await s.flush();return{nativeSessionId:t.nativeSessionId,importedMessages:a.length,importedParts:c.length,recordedEvents:g.length,eventCount:h.eventCount,chunkCount:h.chunkCount,status:h.status}}finally{n.close()}}async function At(t){let e=t.dbPath??Ct(),n=Tt(e),r=[];try{let o=n.prepare(`
|
|
120
120
|
SELECT *
|
|
121
121
|
FROM "session"
|
|
122
122
|
ORDER BY
|
|
@@ -125,7 +125,7 @@ Things an AI agent should always remember.
|
|
|
125
125
|
time_created,
|
|
126
126
|
0
|
|
127
127
|
) DESC
|
|
128
|
-
`).all();for(let i of o){if(!
|
|
128
|
+
`).all();for(let i of o){if(!Rt(n,i,t.project))continue;let d=w(i.id);if(d&&r.push(d),r.length>=(t.limit??100))break}}finally{n.close()}let s=[];for(let o of r)s.push(await Ee({project:t.project,storage:t.storage,nativeSessionId:o,dbPath:e}));return s}import{existsSync as cs,mkdirSync as Nt,readFileSync as us,writeFileSync as _t}from"node:fs";import{homedir as Te}from"node:os";import{join as ge}from"node:path";var Mt="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",Ce="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function ds(){let t=ge(Te(),".config","opencode","AGENTS.md");Nt(ge(Te(),".config","opencode"),{recursive:!0});let e=`${Mt}
|
|
129
129
|
## ToolNet Memory \u2014 Project Continuity
|
|
130
130
|
|
|
131
131
|
When the current workspace belongs to a ToolNet project, identified by a nearest ancestor containing \`.toolnet/project.json\`:
|
|
@@ -138,10 +138,10 @@ When the current workspace belongs to a ToolNet project, identified by a nearest
|
|
|
138
138
|
6. Never invent missing rationale. If ToolNet says a reason was not explicitly recorded, inspect the implementation or ask rather than guessing.
|
|
139
139
|
|
|
140
140
|
This applies automatically to every ToolNet-managed project.
|
|
141
|
-
${
|
|
141
|
+
${Ce}`,n=cs(t)?us(t,"utf8"):"",r=n.indexOf(Mt),s=n.indexOf(Ce);return r>=0&&s>=r?n=n.slice(0,r)+e+n.slice(s+Ce.length):(n=n.trimEnd(),n&&(n+=`
|
|
142
142
|
|
|
143
|
-
`),n+=e),
|
|
144
|
-
`,{encoding:"utf8",mode:384}),t}function
|
|
143
|
+
`),n+=e),_t(t,n.trimEnd()+`
|
|
144
|
+
`,{encoding:"utf8",mode:384}),t}function $t(t={}){let e=t.directory??ge(Te(),".config","opencode","plugins");Nt(e,{recursive:!0}),ds();let n=ge(e,"toolnet-memory.js"),r=t.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`// Generated by ToolNet Memory.
|
|
145
145
|
// OpenCode session capture + continuity bootstrap.
|
|
146
146
|
|
|
147
147
|
function getSessionId(event) {
|
|
@@ -298,17 +298,17 @@ export const ToolNetMemoryPlugin = async ({ directory }) => {
|
|
|
298
298
|
},
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
|
-
`;return
|
|
302
|
-
`);if(
|
|
301
|
+
`;return _t(n,s,{encoding:"utf8",mode:384}),n}import{existsSync as Ua,mkdirSync as ms,readFileSync as Ha,writeFileSync as gs}from"node:fs";import{dirname as hs,join as Kt}from"node:path";function Re(t){if(!t)return 0;let e=Array.from(t).length,n=t.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,n*1.3))}function b(t,e){let n=t.replace(/\s+/g," ").trim();return n.length<=e?n:n.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function ps(t){let e=[],n=!1;for(let r of t.split(/\r?\n/u)){let s=r.trim();if(s.includes("<!--")&&(n=!0),n){s.includes("-->")&&(n=!1);continue}let o=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||o.startsWith("- [enforce]")||o.startsWith("* [enforce]")||o.startsWith("- [advisory]")||o.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(b(s,280)),e.length>=16))break}return e}function ls(t){let e=[],n=[];for(let r of t.split(/\\r?\\n/u)){let s=r.trim(),o=s.toLowerCase(),d=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(c=>o.startsWith(c));if(!d)continue;let a=s.slice(d.length).trim();a&&(d.includes("enforce")?e.push(a):n.push(a))}return{enforce:e,advisory:n}}function fs(t,e){let n=[];for(let r of t){let s=[...n,r].join(`
|
|
302
|
+
`);if(Re(s)<=e){n.push(r);continue}let o=Re(n.join(`
|
|
303
303
|
`)),i=Math.max(0,e-o);if(i>=16){let d=Math.floor(i*3.2),a=b(r,d);a&&n.push(a)}break}return n.join(`
|
|
304
|
-
`).trim()}async function
|
|
304
|
+
`).trim()}async function Lt(t){let e=Math.max(256,Math.min(2e3,t.maxTokens??1e3)),n=pe(t.project,!1),r=n?.content??"";r||(r=await t.storage.getText(`projects/${t.project.id}/project/manual.md`)??"");let s=ls(r),o=n?n.rules.filter(l=>l.mode==="enforce").map(l=>l.text):s.enforce,i=n?n.rules.filter(l=>l.mode==="advisory").map(l=>l.text):s.advisory,d=r?ps(r):[],a=await ie(t.project,t.storage),c=await vt(t.project,t.storage),p=await kt(t.project,t.storage),u=[];if(u.push("[TOOLNET PROJECT CONTEXT]"),u.push(`Project: ${t.project.name}`),u.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),r&&u.push(`Full operating manual: ${de(t.project)}`),o.length){u.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let l of o.slice(0,24))u.push(`- [ENFORCE] ${b(l,240)}`)}if(i.length){u.push("","PROJECT PREFERENCES");for(let l of i.slice(0,10))u.push(`- ${b(l,220)}`)}if(c&&(c.mission&&u.push("","MISSION",b(c.mission.value,420)),c.activeObjective&&u.push("","CURRENT OBJECTIVE",b(c.activeObjective.value,420)),c.why&&u.push("","WHY THIS WORK MATTERS",b(c.why.value,420)),c.desiredOutcome&&u.push("","DESIRED OUTCOME",b(c.desiredOutcome.value,420)),c.planRationale&&u.push("","WHY THIS APPROACH",b(c.planRationale.value,420))),a){if(u.push("","ACTIVE WORK"),a.goal&&u.push(`Goal: ${b(a.goal,320)}`),a.plan&&u.push(`Plan: ${b(a.plan,320)}`),u.push(`Progress: phases ${a.progress.phasesCompleted}/${a.progress.phasesTotal}; tasks ${a.progress.tasksCompleted}/${a.progress.tasksTotal}; blocked ${a.progress.blocked}`),a.currentPhase&&u.push(`Current phase: ${a.currentPhase.title} [${a.currentPhase.status}]`),a.currentPhase&&c){let l=c.phases.find(y=>y.order===a.currentPhase?.order);l&&(l.objective&&u.push(`Phase objective: ${b(l.objective.value,340)}`),l.why?u.push(`Why this phase: ${b(l.why.value,340)}`):u.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),l.deliverable&&u.push(`Deliverable: ${b(l.deliverable.value,340)}`),l.dependencies.length&&u.push(`Depends on: ${l.dependencies.slice(0,4).map(y=>b(y.value,180)).join("; ")}`),l.acceptanceCriteria.length&&(u.push("","DEFINITION OF DONE"),l.acceptanceCriteria.slice(0,6).forEach(y=>{u.push(`- ${b(y.value,260)}`)})),l.openQuestions.length&&(u.push("","OPEN QUESTIONS FOR CURRENT PHASE"),l.openQuestions.slice(0,4).forEach(y=>{u.push(`- ${b(y.value,260)}`)})))}a.currentTask&&u.push(`Current task: ${a.currentTask.title} [${a.currentTask.status}]`),a.nextActions.length&&(u.push("","NEXT ACTIONS"),a.nextActions.slice(0,6).forEach((l,y)=>{u.push(`${y+1}. ${b(l,260)}`)})),a.blockers.length&&(u.push("","BLOCKERS"),a.blockers.slice(0,5).forEach(l=>{u.push(`- ${b(l,260)}`)})),a.warnings.length&&(u.push("","ATTENTION"),a.warnings.slice(-5).forEach(l=>{u.push(`- ${b(l,260)}`)})),a.decisions.length&&(u.push("","RECENT DECISIONS"),a.decisions.slice(-5).forEach(l=>{u.push(`- ${b(l,260)}`)})),a.lastSession&&u.push("",`Last work session: ${a.lastSession.agent} / ${a.lastSession.nativeSessionId}`)}if(c&&c.openQuestions.length&&(u.push("","UNRESOLVED QUESTIONS"),c.openQuestions.slice(0,5).forEach(l=>{u.push(`- ${b(l.value,260)}`)})),p&&u.push(`Latest handoff: ${p.reason} / ${p.sourceSession.agent}`),d.length){u.push("","OPERATING NOTES");for(let l of d)u.push(`- ${l}`)}u.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let g=fs(u,e);return{version:1,projectId:t.project.id,projectName:t.project.name,text:g,estimatedTokens:Re(g),maxTokens:e,hasManual:!!r,hasWorkState:!!a,hasHandoff:!!p,generatedAt:new Date().toISOString()}}function ys(t){return Kt(t.rootPath,".toolnet","context","startup.md")}function Ss(t){return Kt(t.rootPath,".toolnet","context","startup.json")}function vs(t,e){let n=ys(t);ms(hs(n),{recursive:!0}),gs(n,e.text.endsWith(`
|
|
305
305
|
`)?e.text:e.text+`
|
|
306
|
-
`,{encoding:"utf8",mode:384}),x(
|
|
306
|
+
`,{encoding:"utf8",mode:384}),x(Ss(t),e)}async function Wt(t,e,n=900){let r=await Lt({project:t,storage:e,maxTokens:n}),s={version:1,projectId:t.id,projectName:t.name,text:r.text,digest:v(r.text),estimatedTokens:r.estimatedTokens,generatedAt:new Date().toISOString()};return vs(t,s),await e.put(`projects/${t.id}/context/startup.md`,s.text+`
|
|
307
307
|
`,"text/markdown"),await e.put(`projects/${t.id}/context/startup.json`,JSON.stringify(s,null,2)+`
|
|
308
|
-
`,"application/json"),s}function
|
|
308
|
+
`,"application/json"),s}function he(t,e){let n=t.indexOf(e);if(!(n<0))return t[n+1]}function Ae(t,e){return t.includes(e)}function bs(t){let e=_e(),n=Je(Fe({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new X(n,t.id,t.name,t.remote??t.name)}async function ws(){let[t="help",...e]=process.argv.slice(2);if(t==="install-plugin"){let i=$t({binary:he(e,"--bin")});console.log(`\u2705 OpenCode plugin installed: ${i}`),console.log("OpenCode will load it automatically on next start.");return}let n=he(e,"--project")??process.cwd(),r=new H().detect(n),s=bs(r),o=he(e,"--db");if(t==="sync"){let i=e.find(u=>!u.startsWith("--")&&u!==n&&u!==o);if(!i)throw new Error("Usage: session:opencode-sync <session-id>");let d=Ae(e,"--idle"),a=Ae(e,"--error"),c=Ae(e,"--compacted"),p=await Ee({project:r,storage:s,nativeSessionId:i,dbPath:o,idle:d,error:a,compacted:c});if(d||c||a)try{await Wt(r,s,900)}catch{}console.log(JSON.stringify(p,null,2));return}if(t==="recover"){let i=he(e,"--limit"),d=i?Number(i):100,a=await At({project:r,storage:s,dbPath:o,limit:Number.isFinite(d)?d:100});console.log(JSON.stringify({project:r.name,sessions:a.length,importedMessages:a.reduce((c,p)=>c+p.importedMessages,0),importedParts:a.reduce((c,p)=>c+p.importedParts,0)},null,2));return}console.log(`OpenCode Session Adapter
|
|
309
309
|
|
|
310
310
|
Commands:
|
|
311
311
|
sync <session-id> [--project PATH] [--idle]
|
|
312
312
|
recover [--project PATH] [--limit N]
|
|
313
313
|
install-plugin [--bin PATH]
|
|
314
|
-
`)}
|
|
314
|
+
`)}ws().catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});
|