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/codex.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}),Ht(s,r)}function Ne(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 T=class{detect(e=process.cwd()){let n=z(e),r=en(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>ge(H(r,p))),i=Zt(n,o?r:void 0);if(i){let p=he(i),l=tn(p);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),Re(i,l)),Ne(l,i)}let u=new Date().toISOString(),a=Yt(r),c={version:1,id:Xt(r),name:a,remote:a,rootPath:r,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0};return Re(r,c),Ne(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}],U=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 B=class{scanner=new U;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 wn}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 ln}from"@aws-sdk/s3-request-presigner";var Y=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 ln(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 $e,mkdir as dn,readFile as pn,readdir as fn,rm as mn,stat as Le,writeFile as gn}from"node:fs/promises";import{dirname as hn,join as yn,relative as Fe,resolve as Sn}from"node:path";var K=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 dn(hn(r),{recursive:!0}),await gn(r,n)}async get(e){try{return await pn(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 $e(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 $e(n)}catch{return r}let s=async i=>{let u=await fn(i,{withFileTypes:!0});for(let a of u){let c=yn(i,a.name);if(a.isDirectory()){await s(c);continue}let p=await Le(c);r.push({key:Fe(this.root,c),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await Le(n);return o.isDirectory()?await s(n):r.push({key:Fe(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};function We(t){let e=t.localRoot??wn(vn(),".toolnet-memory","storage");if(t.provider==="huggingface"){let n=t.huggingface;return n?.namespace&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new Y({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new K(e))}return new K(e)}function jn(t){return new Promise(e=>setTimeout(e,t))}async function ze(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 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 xn=new Set(["put","get","getText","delete","list"]);function Be(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:xn.has(r)?(...o)=>ze(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Ke(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 De(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 G=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=Ke(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})
|
|
1
|
+
import{existsSync as _s,readFileSync as $s}from"node:fs";import{spawn as Ls}from"node:child_process";import{homedir as Ks}from"node:os";import{join as Fs}from"node:path";import{existsSync as Wt,readFileSync as zt}from"node:fs";import{homedir as Bt}from"node:os";import{join as Dt}from"node:path";function Jt(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 qt(){let t=process.env.TOOLNET_GLOBAL_ENV??Dt(Bt(),".config","toolnet-memory",".env");if(!Wt(t))return;let e=zt(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]=Jt(r.slice(s+1)))}}qt();function F(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function W(t,e){if(!t)return e;let n=Number(t);return Number.isFinite(n)?n:e}function Me(){return{memory:{autoCapture:F(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:F(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:F(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:F(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:W(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:W(process.env.MEMORY_RERANK_TOP,10),finalContext:W(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:W(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:F(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:W(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Vt}from"node:crypto";import{existsSync as he,mkdirSync as Ut,readFileSync as Ht,renameSync as Yt,writeFileSync as Gt}from"node:fs";import{basename as Qt,dirname as U,join as H,parse as $e,resolve as z}from"node:path";var Le=".toolnet",Xt="project.json";function Zt(t){return Vt("sha256").update(t).digest("hex").slice(0,16)}function ye(t){return H(t,Le,Xt)}function en(t){return he(ye(t))}function tn(t,e){let n=z(t),r=$e(n).root;for(;;){if(en(n))return n;if(n===r||e&&n===z(e))break;let s=U(n);if(s===n)break;n=s}return null}function nn(t){let e=z(t),n=$e(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>he(H(e,o))))return e;if(e===n)break;let s=U(e);if(s===e)break;e=s}return z(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 Ne(t,e){let n=H(t,Le);Ut(n,{recursive:!0});let r=ye(t),s=`${r}.tmp-${process.pid}`;Gt(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),Yt(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 N=class{detect(e=process.cwd()){let n=z(e),r=nn(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>he(H(r,p))),i=tn(n,o?r:void 0);if(i){let p=ye(i),l=rn(p);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),Ne(i,l)),_e(l,i)}let u=new Date().toISOString(),a=Qt(r),c={version:1,id:Zt(r),name:a,remote:a,rootPath:r,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0};return Ne(r,c),_e(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}],Y=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 B=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 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 ln,S3Client as dn}from"@aws-sdk/client-s3";import{getSignedUrl as pn}from"@aws-sdk/s3-request-presigner";var G=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new dn({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 ln({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await pn(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 Ke,mkdir as fn,readFile as mn,readdir as gn,rm as hn,stat as Fe,writeFile as yn}from"node:fs/promises";import{dirname as Sn,join as vn,relative as We,resolve as wn}from"node:path";var D=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return wn(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 Ke(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 Ke(n)}catch{return r}let s=async i=>{let u=await gn(i,{withFileTypes:!0});for(let a of u){let c=vn(i,a.name);if(a.isDirectory()){await s(c);continue}let p=await Fe(c);r.push({key:We(this.root,c),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await Fe(n);return o.isDirectory()?await s(n):r.push({key:We(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as bn,GetObjectCommand as jn,HeadObjectCommand as kn,ListObjectsV2Command as xn,PutObjectCommand as In,S3Client as Pn}from"@aws-sdk/client-s3";import{getSignedUrl as On}from"@aws-sdk/s3-request-presigner";var J=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Pn({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 On(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 bn({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 Se(t,e){return console.warn(e),new D(t)}function ze(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 J({name:"r2",endpoint:`https://${n.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:n.bucket,forcePathStyle:!0,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Se(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 J({name:"s3",endpoint:n.endpoint,region:n.region??"us-east-1",bucket:n.bucket,forcePathStyle:n.forcePathStyle??!1,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Se(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 G({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):Se(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new D(e)}function An(t){return new Promise(e=>setTimeout(e,t))}async function Be(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 a=Math.min(s,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,a*.2));await An(a+c)}throw o}var Rn=new Set(["put","get","getText","delete","list"]);function De(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)=>Be(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Je(t){let e=t.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function qe(t){let e=t.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let n=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var Q=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=Je(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=qe(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{join as Kn}from"node:path";import{createHash as Tn}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 Tn("sha256").update(t).digest("hex")}function ve(t){if(Array.isArray(t))return t.map(ve);if(t&&typeof t=="object"){let e=t,n={};for(let r of Object.keys(e).sort())n[r]=ve(e[r]);return n}return t}function Ve(t){return JSON.stringify(ve(t))}function Ue(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 He(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 Ye(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=He(r.toLowerCase(),"agent"),i=He(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 Ge(t){return String(t).padStart(12,"0")}var X=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 u=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!u)continue;let a=Number(u[1]),c=Number(u[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,u)=>i.start-u.start),{chunks:s,maxSequence:o}}split(e){let n=[],r=[],s=0;for(let o of e){let i=Buffer.byteLength(JSON.stringify(o)+`
|
|
7
|
-
`,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),u=n.filter(g=>g.sequence>i.maxSequence),a=0;for(let g of this.split(u)){let S=g[0],
|
|
7
|
+
`,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),u=n.filter(g=>g.sequence>i.maxSequence),a=0;for(let g of this.split(u)){let S=g[0],k=g[g.length-1],R=g.map(T=>JSON.stringify(T)).join(`
|
|
8
8
|
`)+`
|
|
9
|
-
`,
|
|
9
|
+
`,M=v(R).slice(0,16),E=[e.remotePrefix,"events",`${Ge(S.sequence)}-${Ge(k.sequence)}-${M}.jsonl`].join("/");await this.storage.exists(E)||await this.storage.put(E,R,"application/x-ndjson"),a+=g.length}let c=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 f=new Date().toISOString(),d=n[0],y={version:1,projectId:e.projectId,projectName:e.projectName,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,status:l,createdAt:o?.createdAt??d?.timestamp??f,updatedAt:p?.timestamp??f,firstEventAt:o?.firstEventAt??d?.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:f};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:l}}};import{closeSync as we,existsSync as Fn,fsyncSync as Wn,mkdirSync as zn,openSync as be,readSync as Bn,rmSync as Qe,statSync as Xe,writeSync as Dn}from"node:fs";import{join as je}from"node:path";var Jn=12e4,qn=80,Vn=2e3;function Un(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}var Z=class{constructor(e){this.identity=e;zn(e.localDirectory,{recursive:!0}),this.eventsFile=je(e.localDirectory,"events.jsonl"),this.stateFile=je(e.localDirectory,"state.json"),this.lockFile=je(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 Ue(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(e){x(this.stateFile,e)}acquireLock(){for(let e=0;e<qn;e+=1)try{return be(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-Xe(this.lockFile).mtimeMs>Jn){Qe(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),Qe(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 f=l.timestamp??new Date().toISOString(),d=l.data??{},y=l.provenance?.rawDigest??v(Ve(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,f,y].join("|"),g=v(h).slice(0,32);if(r.has(g))continue;s+=1;let S={version:1,id:g,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,type:l.type,timestamp:f,data:d,provenance:{...l.provenance,rawDigest:y}};l.role!==void 0&&(S.role=l.role),l.sourceEventId!==void 0&&(S.sourceEventId=l.sourceEventId),l.sourceSequence!==void 0&&(S.sourceSequence=l.sourceSequence),o.push(S),r.add(g)}if(o.length===0)return[];let i=o.map(l=>JSON.stringify(l)).join(`
|
|
10
10
|
`)+`
|
|
11
|
-
`,u=
|
|
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
|
+
`,u=be(this.eventsFile,"a",384);try{Dn(u,i,null,"utf8"),Wn(u)}finally{we(u)}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(!Fn(this.eventsFile))return{events:[],startOffset:e.remoteByteOffset,endOffset:e.remoteByteOffset};let n=Xe(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=be(this.eventsFile,"r");try{Bn(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 lr,openSync as dr,readSync as pr,statSync as fr}from"node:fs";function Ze(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 rt=[/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],et=[/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],tt=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 st(t){return t.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function nr(t){return st(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 ke(t,e,n,r=0){if(!(r>6)){if(typeof t=="string"){(!e||tt.has(e))&&n.push(t);return}if(Array.isArray(t)){for(let s of t.slice(0,50))ke(s,e,n,r+1);return}if(!(!t||typeof t!="object"))for(let[s,o]of Object.entries(t))(tt.has(s)||tr.has(s))&&ke(o,s,n,r+1)}}function sr(t){let e=[];ke(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=st(o);if(rr(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function nt(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,rt)?{kind:"rule",confidence:.98}:r&&I(t,Hn)?{kind:"rule",confidence:.92}:I(t,Yn)?{kind:I(t,et)?"architecture":"decision",confidence:r?.93:.86}:r&&I(t,Gn)?{kind:"todo",confidence:.87}:I(t,et)&&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,rt)?"critical":t==="architecture"||t==="decision"||t==="rule"?"high":t==="fix"||t==="context"?"normal":Ze(e,n)}function ot(t,e){let n=[],r=new Set,s=new Map;for(let o of e){let i=typeof o.data.messageId=="string"?o.data.messageId:void 0,u=nt(o);i&&u&&s.set(i,u)}for(let o of e){let i=nt(o),u=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&u&&(i=s.get(u)??"");for(let a of sr(o)){let c=or(a,i,o);if(!c||c.confidence<.75)continue;let p=ir(c.kind),l=nr(a),f=v([t.projectId,c.kind,l].join("|"));if(r.has(f))continue;r.add(f);let d=o.provenance.sourcePath?[o.provenance.sourcePath]:[],y=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:f,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:d,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}function it(t){return String(t).padStart(12,"0")}function cr(t){return t.remotePrefix.replace("/sessions/","/memory/learned/")}var ee=class{constructor(e){this.storage=e}storage;async write(e,n,r){if(r.length===0||n.length===0)return null;let s=Math.min(...n.map(p=>p.sequence)),o=Math.max(...n.map(p=>p.sequence)),i={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,candidateCount:r.length,candidates:r},u=JSON.stringify(i,null,2)+`
|
|
13
|
+
`,a=v(r.map(p=>p.fingerprint).sort().join("|")).slice(0,16),c=[cr(e),"batches",`${it(s)}-${it(o)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,u,"application/json"),c}};function mr(t,e){if(!lr(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=dr(t,"r");try{pr(i,o,0,s,r)}finally{ur(i)}let u=o.toString("utf8"),a=u.lastIndexOf(`
|
|
14
14
|
`);if(a<0)return{events:[],nextOffset:r};let c=u.slice(0,a+1);return{events:c.split(`
|
|
15
|
-
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var
|
|
16
|
-
`,u=v(n.map(c=>c.id).sort().join("|")).slice(0,16),a=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${
|
|
17
|
-
`,"application/json"),E}async function
|
|
15
|
+
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var te=class{constructor(e){this.options=e;this.journal=new ee(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=ot(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 br,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 $(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function ct(t){return $(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 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 at(t){let e=$(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 b(t,e,n,r,s={}){let o=$(r),i=s.key??ct(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=$(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(b(t,e,"goal",i[1],{confidence:.97}));let u=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);u?.[1]&&s.push(b(t,e,"plan",u[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 f=Number(c[1]),d=$(c[2]??""),y=d&&!at(d)?`Phase ${f} - ${d}`:`Phase ${f}`;s.push(b(t,e,"phase",y,{key:`phase:${f}`,order:f,status:ne(r),confidence:.93}))}let p=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);p?.[2]&&s.push(b(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 f=l[1]?Number(l[1]):void 0,d=$(l[2]),y=at(d);s.push(b(t,e,"task",y&&f!==void 0?`TODO ${f}`:d,{key:f!==void 0?`task:${f}`:ct(d),order:f,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 f=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");f&&s.push(b(t,e,"next_action",f,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(b(t,e,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(b(t,e,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(b(t,e,"decision",r,{confidence:.9})),s}function ut(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(b(t,i,"decision",c,{confidence:1}))}if(i.type==="todo"){let a=[];_(i.data,a);for(let c of a)s(b(t,i,"task",c,{status:ne(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(b(t,i,"file",c,{confidence:1}))}if(i.type==="test"){let a=[];_(i.data,a);for(let c of a)s(b(t,i,"test",c,{confidence:1}))}let u=[];_(i.data,u);for(let a of u)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(b(t,o,"session",`${t.agent}:${t.nativeSessionId}`,{key:t.sessionKey,confidence:1})),n}function lt(t){return String(t).padStart(12,"0")}var re=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
|
+
`,u=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)}-${u}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,i,"application/json"),a}};import{join as dt}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 L(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 pt(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 wr(t,e){let n=`projects/${t.id}/work/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,u)=>i.key.localeCompare(u.key))){let i=await e.getText(o.key);if(i)try{let u=JSON.parse(i);u.version===1&&Array.isArray(u.observations)&&s.push(u)}catch{}}return s}async function se(t,e){let r=(await wr(t,e)).flatMap(m=>m.observations).sort((m,j)=>{let Re=m.occurredAt.localeCompare(j.occurredAt);if(Re!==0)return Re;let Te=m.sequence-j.sequence;return Te!==0?Te:m.id.localeCompare(j.id)}),s=new Map,o=new Map,i,u,a,c=[],p=[],l=[],f=[],d=[],y=[];for(let m of r)switch(m.kind){case"goal":i=m.text;break;case"plan":u=m.text;break;case"phase":s.set(m.key,pt(s.get(m.key),m));break;case"task":o.set(m.key,pt(o.get(m.key),m));break;case"decision":c.push(m.text);break;case"blocker":p.push(m.text);break;case"warning":l.push(m.text);break;case"next_action":f.push(m.text);break;case"file":d.push(m.text);break;case"test":y.push(m.text);break;case"session":a={agent:m.agent,nativeSessionId:m.nativeSessionId,sessionKey:m.sessionKey,updatedAt:m.occurredAt};break}let h=Array.from(s.values()).sort((m,j)=>(m.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),g=Array.from(o.values()).sort((m,j)=>(m.order??Number.MAX_SAFE_INTEGER)-(j.order??Number.MAX_SAFE_INTEGER)),S=h.find(m=>m.status==="in_progress")??h.find(m=>m.status==="blocked")??h.find(m=>m.status==="pending"),k=g.find(m=>m.status==="in_progress")??g.find(m=>m.status==="blocked")??g.find(m=>m.status==="pending"),R=L([...f,...k?[k.title]:[],...!k&&S?[S.title]:[],...g.filter(m=>m.status==="pending").slice(0,5).map(m=>m.title)],8),M=L([...p,...h.filter(m=>m.status==="blocked").map(m=>m.title),...g.filter(m=>m.status==="blocked").map(m=>m.title)],20),E={version:1,projectId:t.id,projectName:t.name,goal:i,plan:u,phases:h,tasks:g,decisions:L(c,20),blockers:M,warnings:L(l,20),nextActions:R,filesTouched:L(d,30),tests:L(y,20),currentPhase:S,currentTask:k,progress:{phasesTotal:h.length,phasesCompleted:h.filter(m=>m.status==="completed").length,tasksTotal:g.length,tasksCompleted:g.filter(m=>m.status==="completed").length,blocked:h.filter(m=>m.status==="blocked").length+g.filter(m=>m.status==="blocked").length},lastSession:a,updatedAt:r.length?r[r.length-1].occurredAt:new Date().toISOString()},T=dt(t.rootPath,".toolnet","work");return yr(T,{recursive:!0}),x(dt(T,"current.json"),E),await e.put(`projects/${t.id}/work/current.json`,JSON.stringify(E,null,2)+`
|
|
17
|
+
`,"application/json"),E}async function oe(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 Pr(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{br(i)}let u=o.toString("utf8"),a=u.lastIndexOf(`
|
|
18
18
|
`);if(a<0)return{events:[],nextOffset:r};let c=u.slice(0,a+1);return{events:c.split(`
|
|
19
|
-
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var
|
|
20
|
-
`,"application/json"),u}};import{mkdirSync as
|
|
21
|
-
`,"application/json"),d}async function
|
|
19
|
+
`).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var ie=class{constructor(e){this.options=e;this.journal=new re(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.continuity.offset"]??0),r=Pr(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=ut(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await se(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 Fr}from"node:fs";var Or=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function K(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function xe(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))xe(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Or.has(r)||["data","payload","parts","messages"].includes(r))&&xe(s,e,n+1)}}function P(t,e,n,r,s,o=.95){let i=K(r);return{version:1,id:v([t.projectId,n,s.type,s.key??"",i.toLowerCase(),e.id].join("|")).slice(0,32),projectId:t.projectId,kind:n,value:i,scope:s.type,scopeKey:s.key,scopeOrder:s.order,confidence:o,evidence:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId,sequence:e.sequence,occurredAt:e.timestamp}}}function O(t,e){let n=t.toLowerCase();for(let r of e){let s=r.toLowerCase();if(n.startsWith(`${s}:`)||n.startsWith(`${s} -`)||n.startsWith(`${s} \u2014`))return K(t.slice(r.length+1))}return null}function Er(t){let e=t.trimStart();return e.startsWith("- ")||e.startsWith("* ")||/^\d+[.)]\s+/u.test(e)}function Cr(t){return K(t.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function ft(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=[];xe(o.data,i);for(let u of i){let a={type:"project"},c=null;for(let p of u.split(/\r?\n/u)){let l=K(p);if(!l){c=null;continue}let f=l.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(f){let j=Number(f[1]);a={type:"phase",key:`phase:${j}`,order:j,title:K(f[2]??"")},c=null;continue}let d=l.match(/^(?:todo|task|việc)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(d){let j=Number(d[1]);a={type:"task",key:`task:${j}`,order:j,title:K(d[2]??"")},c=null;continue}let y=O(l,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(y){s(P(t,o,"mission",y,{type:"project"},.99)),c=null;continue}let h=O(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(P(t,o,a.type==="phase"?"phase_objective":"objective",h,a,.98)),c=null;continue}let g=O(l,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(g){s(P(t,o,a.type==="phase"?"phase_why":"why",g,a,.98)),c=null;continue}let S=O(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(S){s(P(t,o,"desired_outcome",S,{type:"project"},.98)),c=null;continue}let k=O(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(k){s(P(t,o,"plan_rationale",k,{type:"project"},.98)),c=null;continue}let R=O(l,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(R){s(P(t,o,"phase_deliverable",R,a,.97)),c=null;continue}let M=O(l,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if(M){s(P(t,o,"acceptance_criterion",M,a,.98)),c="acceptance_criterion";continue}let E=O(l,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(E){s(P(t,o,"dependency",E,a,.97)),c="dependency";continue}let T=O(l,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(T){s(P(t,o,"open_question",T,a,.95)),c="open_question";continue}let m=O(l,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(m){s(P(t,o,"constraint",m,a,.97)),c="constraint";continue}if(/^(?:acceptance criteria|definition of done|done khi|tiêu chí hoàn thành)\s*:?\s*$/iu.test(l)){c="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(l)){c="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(l)){c="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(l)){c="constraint";continue}if(c&&Er(p)){s(P(t,o,c,Cr(p),a,.96));continue}c=null}}}return n}function mt(t){return String(t).padStart(12,"0")}var ae=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),u=[`projects/${e.projectId}`,"work","semantic","observations",e.agent,e.nativeSessionId,`${mt(r)}-${mt(s)}-${i}.json`].join("/");return await this.storage.exists(u)||await this.storage.put(u,JSON.stringify(o,null,2)+`
|
|
20
|
+
`,"application/json"),u}};import{mkdirSync as Ar}from"node:fs";import{join as gt}from"node:path";function Rr(t){return{value:t.value,confidence:t.confidence,evidence:t.evidence}}function Tr(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 C(t,e){return Tr(e,t)?e:t}function A(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,u)=>i.key.localeCompare(u.key))){let i=await e.getText(o.key);if(i)try{let u=JSON.parse(i);u.version===1&&Array.isArray(u.observations)&&s.push(u)}catch{}}return s}function Nr(t){return{key:t.scopeKey??`phase:${t.scopeOrder??0}`,order:t.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function ht(t,e){let r=(await Mr(t,e)).flatMap(h=>h.observations).sort((h,g)=>{let S=h.evidence.occurredAt.localeCompare(g.evidence.occurredAt);return S!==0?S:h.evidence.sessionKey===g.evidence.sessionKey?h.evidence.sequence-g.evidence.sequence:h.id.localeCompare(g.id)}),s,o,i,u,a,c=new Map,p=[],l=[],f=[];for(let h of r){let g=Rr(h);if(h.scope==="phase"&&h.scopeKey){let S=c.get(h.scopeKey)??Nr(h);switch(h.kind){case"phase_objective":S.objective=C(S.objective,g);break;case"phase_why":S.why=C(S.why,g);break;case"phase_deliverable":S.deliverable=C(S.deliverable,g);break;case"acceptance_criterion":S.acceptanceCriteria.push(g);break;case"dependency":S.dependencies.push(g);break;case"open_question":S.openQuestions.push(g);break;case"constraint":S.constraints.push(g);break;case"note":S.notes.push(g);break}c.set(S.key,S);continue}switch(h.kind){case"mission":s=C(s,g);break;case"objective":o=C(o,g);break;case"why":i=C(i,g);break;case"desired_outcome":u=C(u,g);break;case"plan_rationale":a=C(a,g);break;case"open_question":p.push(g);break;case"constraint":l.push(g);break;case"note":f.push(g);break}}for(let h of c.values())h.acceptanceCriteria=A(h.acceptanceCriteria,20),h.dependencies=A(h.dependencies,15),h.openQuestions=A(h.openQuestions,15),h.constraints=A(h.constraints,15),h.notes=A(h.notes,20);let d={version:1,projectId:t.id,projectName:t.name,mission:s,activeObjective:o,why:i,desiredOutcome:u,planRationale:a,phases:Array.from(c.values()).sort((h,g)=>h.order-g.order),openQuestions:A(p,20),constraints:A(l,20),notes:A(f,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},y=gt(t.rootPath,".toolnet","work");return Ar(y,{recursive:!0}),x(gt(y,"semantic-current.json"),d),await e.put(`projects/${t.id}/work/semantic/current.json`,JSON.stringify(d,null,2)+`
|
|
21
|
+
`,"application/json"),d}async function yt(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 Wr(t,e){if(!$r(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=Buffer.alloc(n-r),o=Lr(t,"r");try{Kr(o,s,0,s.length,r)}finally{_r(o)}let i=s.toString("utf8"),u=i.lastIndexOf(`
|
|
22
22
|
`);if(u<0)return{events:[],nextOffset:r};let a=i.slice(0,u+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 ce=class{constructor(e){this.options=e;this.journal=new ae(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.semantic.offset"]??0),r=Wr(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=ft(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await ht(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 Ie}from"node:path";import{existsSync as wt,mkdirSync as zr,readFileSync as Br,statSync as St,writeFileSync as Dr}from"node:fs";import{dirname as Jr,join as qr}from"node:path";var vt=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,30 +63,30 @@ Things an AI agent should always remember.
|
|
|
63
63
|
<!--
|
|
64
64
|
- [advisory] Prefer small focused files.
|
|
65
65
|
-->
|
|
66
|
-
`;function
|
|
66
|
+
`;function ue(t){return qr(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 u=`${o}:${i.toLowerCase()}`;n.has(u)||(n.add(u),e.push({id:v(u).slice(0,24),mode:o,text:i,source:"manual"}))}return e}function Yr(t){let e=ue(t);return wt(e)||(zr(Jr(e),{recursive:!0}),Dr(e,Vr,{encoding:"utf8",mode:384})),e}function le(t,e=!1){let n=e?Yr(t):ue(t);if(!wt(n))return null;if(St(n).size>vt)throw new Error(`PROJECT.md exceeds ${vt} bytes`);let s=Br(n,"utf8");return{path:n,content:s,digest:v(s),rules:Hr(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(St(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 de=class{constructor(e){this.options=e}options;async capture(e,n){let r=await oe(this.options.project,this.options.storage);if(r||(r=await se(this.options.project,this.options.storage)),!Xr(r))return null;let s=le(this.options.project,!1),o=s?s.rules.filter(f=>f.mode==="enforce").map(f=>f.text):[],i=v(JSON.stringify(Qr(r))),u=v([this.options.project.id,this.options.identity.sessionKey,i].join("|")).slice(0,24),a=new Date().toISOString(),c={version:1,id:u,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(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:[...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/${u}.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 l=
|
|
69
|
-
`))if(n)try{let r=xt(JSON.parse(n));if(r.type!=="session_meta")continue;let s=xt(r.payload),o=[s.id,s.thread_id,s.threadId,s.session_id,s.sessionId].find(u=>typeof u=="string"),i=typeof s.cwd=="string"?s.cwd:void 0;return{threadId:o,cwd:i,raw:s}}catch{}return{raw:{}}}function
|
|
68
|
+
`,"application/json");let l=Ie(this.options.project.rootPath,".toolnet","work","handoffs");return Gr(l,{recursive:!0}),x(Ie(l,`${u}.json`),c),x(Ie(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),c),c}};async function bt(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 pe=class{identity;wal;remote;sanitizer=new B;learner;continuity;semantic;handoff;title;metadata;constructor(e){this.identity=Ye(e.project,e.agent,e.nativeSessionId),this.title=e.title,this.metadata=this.sanitizer.sanitizeValue(e.metadata??{}),this.wal=new Z(this.identity),this.remote=new X(e.storage,e.maxEventsPerChunk??100,e.maxChunkBytes??512*1024),this.learner=new te({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.continuity=new ie({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.semantic=new ce({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.handoff=new de({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)}};import{existsSync as Zr,readFileSync as es,readdirSync as ts,statSync as jt}from"node:fs";import{homedir as ns}from"node:os";import{join as fe,resolve as kt}from"node:path";function xt(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function rs(){return process.env.CODEX_HOME??fe(ns(),".codex")}function q(t){let e="";try{e=es(t,"utf8").slice(0,128*1024)}catch{return{raw:{}}}for(let n of e.split(`
|
|
69
|
+
`))if(n)try{let r=xt(JSON.parse(n));if(r.type!=="session_meta")continue;let s=xt(r.payload),o=[s.id,s.thread_id,s.threadId,s.session_id,s.sessionId].find(u=>typeof u=="string"),i=typeof s.cwd=="string"?s.cwd:void 0;return{threadId:o,cwd:i,raw:s}}catch{}return{raw:{}}}function Pe(t,e){if(!Zr(t))return;let n;try{n=ts(t,{withFileTypes:!0})}catch{return}for(let r of n){let s=fe(t,r.name);if(r.isDirectory()){Pe(s,e);continue}r.isFile()&&r.name.endsWith(".jsonl")&&e.push(s)}}function Oe(){let t=rs(),e=[];return Pe(fe(t,"sessions"),e),Pe(fe(t,"archived_sessions"),e),e.sort((n,r)=>{try{return jt(r).mtimeMs-jt(n).mtimeMs}catch{return 0}})}function Ee(t){let e=Oe(),n=e.find(r=>r.includes(t));if(n)return n;for(let r of e)if(q(r).threadId===t)return r;return null}function me(t,e){let n=kt(t),r=kt(e);return r===n||r.startsWith(n+"/")||n.startsWith(r+"/")}import{closeSync as ss,existsSync as os,openSync as is,readSync as as,statSync as cs}from"node:fs";function It(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function us(t){let e=t.timestamp;if(typeof e=="string"){let n=new Date(e);if(!Number.isNaN(n.getTime()))return n.toISOString()}return new Date().toISOString()}function ls(t){let e=typeof t.type=="string"?t.type.toLowerCase():"",n=It(t.payload),r=typeof n.type=="string"?n.type.toLowerCase():"",s=typeof n.role=="string"?n.role.toLowerCase():void 0;return e==="session_meta"?{type:"custom"}:s==="user"||r==="user_message"?{type:"user_prompt",role:"user"}:s==="assistant"||r==="agent_message"||r==="assistant_message"?{type:"assistant_message",role:"assistant"}:r.includes("function_call")||r.includes("tool_call")||r.includes("exec_command_begin")||r.includes("exec_command_start")?{type:"tool_call"}:r.includes("function_call_output")||r.includes("tool_result")||r.includes("exec_command_end")||r.includes("exec_command_complete")?{type:"tool_result"}:r.includes("error")?{type:"error"}:e.includes("compacted")||r.includes("compacted")?{type:"session_compact"}:{type:"custom",role:s}}function Pt(t,e=0){if(!os(t))return{events:[],nextOffset:e,reset:!1};let n=cs(t).size,r=e>n,s=r?0:e;if(s>=n)return{events:[],nextOffset:n,reset:r};let o=n-s,i=Buffer.alloc(o),u=is(t,"r");try{as(u,i,0,o,s)}finally{ss(u)}let a=i.toString("utf8"),c=a.lastIndexOf(`
|
|
70
70
|
`);if(c<0)return{events:[],nextOffset:s,reset:r};let p=a.slice(0,c+1),l=0,f=[];for(let d of p.split(`
|
|
71
71
|
`)){if(!d)continue;let y=Buffer.byteLength(d+`
|
|
72
|
-
`,"utf8"),h=s+l;l+=y;let g;try{g=JSON.parse(d)}catch{continue}let S=
|
|
72
|
+
`,"utf8"),h=s+l;l+=y;let g;try{g=JSON.parse(d)}catch{continue}let S=It(g),k=ls(S);f.push({type:k.type,timestamp:us(S),role:k.role,sourceEventId:`rollout:${h}`,sourceSequence:h,data:S,provenance:{source:"codex-rollout",sourcePath:t,sourceOffset:h}})}return{events:f,nextOffset:s+Buffer.byteLength(p,"utf8"),reset:r}}async function V(t){let e=t.threadId.trim();if(!e)throw new Error("Codex thread ID is required");let n=q(t.rolloutPath),r=t.cwd??n.cwd;if(r&&!me(t.project.rootPath,r))throw new Error(`Codex thread does not belong to project: ${r}`);if(n.threadId&&n.threadId!==e)throw new Error(`Codex rollout thread mismatch: expected ${e}, got ${n.threadId}`);let s=new pe({project:t.project,storage:t.storage,agent:"codex",nativeSessionId:e,metadata:{source:"codex-rollout",rolloutPath:t.rolloutPath,cwd:r,client:t.client}}),o=s.status(),i=o.sourceCursors["codex.rollout.path"],u=Number(o.sourceCursors["codex.rollout.offset"]??0);i&&i!==t.rolloutPath&&(u=0),(!Number.isFinite(u)||u<0)&&(u=0);let a=Pt(t.rolloutPath,u),c=[];o.lastSequence===0&&c.push({type:"session_start",sourceEventId:`codex:${e}:start`,data:{threadId:e,cwd:r,rolloutPath:t.rolloutPath,sessionMeta:n.raw},provenance:{source:"codex-rollout",sourcePath:t.rolloutPath}}),i&&i!==t.rolloutPath&&c.push({type:"custom",sourceEventId:`codex:${e}:rollout-rotation:${t.rolloutPath}`,data:{event:"rollout_rotation",previousPath:i,rolloutPath:t.rolloutPath},provenance:{source:"codex-rollout"}}),a.reset&&c.push({type:"custom",sourceEventId:`codex:${e}:rollout-reset:${a.nextOffset}`,data:{event:"rollout_reset"},provenance:{source:"codex-rollout",sourcePath:t.rolloutPath}}),c.push(...a.events),t.idle&&t.turnId&&c.push({type:"session_idle",sourceEventId:`codex:${e}:turn:${t.turnId}:idle`,data:{turnId:t.turnId,client:t.client},provenance:{source:"codex-notify"}});let p=s.recordMany(c);s.setSourceCursor("codex.rollout.path",t.rolloutPath),s.setSourceCursor("codex.rollout.offset",a.nextOffset),t.turnId&&s.setSourceCursor("codex.last.turn",t.turnId);let l=await s.flush();return{threadId:e,imported:p.length,rolloutEvents:a.events.length,eventCount:l.eventCount,chunkCount:l.chunkCount,status:l.status,rolloutOffset:a.nextOffset,reset:a.reset}}import{existsSync as ds}from"node:fs";import{dirname as ps,join as fs,parse as ms,resolve as gs}from"node:path";function Ot(t){let e=gs(t),n=ms(e).root;for(;;){if(ds(fs(e,".toolnet","project.json")))return new N().detect(e);if(e===n)break;let r=ps(e);if(r===e)break;e=r}return null}async function Et(t,e,n=100){let r=[];for(let s of Oe()){let o=q(s);if(!(!o.threadId||!o.cwd)&&me(t.rootPath,o.cwd)&&(r.push(await V({project:t,storage:e,threadId:o.threadId,rolloutPath:s,cwd:o.cwd})),r.length>=n))break}return r}import{existsSync as hs,mkdirSync as Ct,readFileSync as ys,writeFileSync as At}from"node:fs";import{homedir as Rt}from"node:os";import{dirname as Tt,join as Ce}from"node:path";function Ss(t){let e=[],n=/"((?:\\.|[^"\\])*)"|'([^']*)'/g,r;for(;r=n.exec(t);){let s=r[1]??r[2]??"";try{e.push(r[1]!==void 0?JSON.parse(`"${s}"`):s)}catch{e.push(s)}}return e}function Mt(t={}){let e=t.configFile??Ce(process.env.CODEX_HOME??Ce(Rt(),".codex"),"config.toml"),n=t.previousFile??Ce(Rt(),".config","toolnet-memory","codex-notify-previous.json");Ct(Tt(e),{recursive:!0}),Ct(Tt(n),{recursive:!0});let r=hs(e)?ys(e,"utf8"):"",s=t.binary??"toolnet-memory",o=`notify = [${JSON.stringify(s)}, "session:codex-notify"]`,i=r.split(`
|
|
73
73
|
`),u=i.findIndex(f=>/^\s*\[/.test(f));u<0&&(u=i.length);let a=-1,c=-1;for(let f=0;f<u;f+=1)if(/^\s*notify\s*=/.test(i[f])){if(a=f,c=f,i[f].includes("[")&&!i[f].includes("]"))for(;c+1<u&&(c+=1,!i[c].includes("]")););break}let p=[];if(a>=0){let f=i.slice(a,c+1).join(`
|
|
74
|
-
`);p=
|
|
74
|
+
`);p=Ss(f),i.splice(a,c-a+1,o)}else u=i.findIndex(f=>/^\s*\[/.test(f)),u<0&&(u=i.length),i.splice(u,0,o);let l=p.length>=2&&p[p.length-1]==="session:codex-notify";return p.length>0&&!l&&At(n,JSON.stringify(p,null,2)+`
|
|
75
75
|
`,{encoding:"utf8",mode:384}),r=i.join(`
|
|
76
76
|
`),r.endsWith(`
|
|
77
77
|
`)||(r+=`
|
|
78
|
-
`),
|
|
79
|
-
`,{encoding:"utf8",mode:384}),e}import{existsSync as
|
|
80
|
-
`);if(
|
|
78
|
+
`),At(e,r,{encoding:"utf8",mode:384}),{configFile:e,previousFile:n,preservedPrevious:p.length>0&&!l}}import{existsSync as vs,mkdirSync as ws,readFileSync as bs,writeFileSync as js}from"node:fs";import{homedir as ks}from"node:os";import{dirname as xs,join as Nt}from"node:path";function Is(t){return`'${t.replace(/'/g,"'\\''")}'`}function _t(t={}){let e=t.hooksFile??Nt(process.env.CODEX_HOME??Nt(ks(),".codex"),"hooks.json");ws(xs(e),{recursive:!0});let n={};if(vs(e))try{n=JSON.parse(bs(e,"utf8"))}catch(u){throw new Error(`Invalid existing Codex hooks.json: ${u instanceof Error?u.message:String(u)}`)}let r=n.hooks&&typeof n.hooks=="object"&&!Array.isArray(n.hooks)?n.hooks:{};n.hooks=r;let o=(Array.isArray(r.SessionStart)?r.SessionStart:[]).filter(u=>{try{return!JSON.stringify(u).includes("session:codex-context")}catch{return!0}}),i=t.binary??"toolnet-memory";return o.push({matcher:"startup|resume|clear|compact",hooks:[{type:"command",command:`${Is(i)} session:codex-context`,timeout:15,additionalContextLimit:1e3,statusMessage:"Loading ToolNet project continuity"}]}),r.SessionStart=o,js(e,JSON.stringify(n,null,2)+`
|
|
79
|
+
`,{encoding:"utf8",mode:384}),e}import{existsSync as Ac,mkdirSync as Cs,readFileSync as Rc,writeFileSync as As}from"node:fs";import{dirname as Rs,join as Lt}from"node:path";function Ae(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 w(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(w(s,280)),e.length>=16))break}return e}function Os(t){let e=[],n=[];for(let r of t.split(/\\r?\\n/u)){let s=r.trim(),o=s.toLowerCase(),u=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(c=>o.startsWith(c));if(!u)continue;let a=s.slice(u.length).trim();a&&(u.includes("enforce")?e.push(a):n.push(a))}return{enforce:e,advisory:n}}function Es(t,e){let n=[];for(let r of t){let s=[...n,r].join(`
|
|
80
|
+
`);if(Ae(s)<=e){n.push(r);continue}let o=Ae(n.join(`
|
|
81
81
|
`)),i=Math.max(0,e-o);if(i>=16){let u=Math.floor(i*3.2),a=w(r,u);a&&n.push(a)}break}return n.join(`
|
|
82
|
-
`).trim()}async function
|
|
82
|
+
`).trim()}async function $t(t){let e=Math.max(256,Math.min(2e3,t.maxTokens??1e3)),n=le(t.project,!1),r=n?.content??"";r||(r=await t.storage.getText(`projects/${t.project.id}/project/manual.md`)??"");let s=Os(r),o=n?n.rules.filter(d=>d.mode==="enforce").map(d=>d.text):s.enforce,i=n?n.rules.filter(d=>d.mode==="advisory").map(d=>d.text):s.advisory,u=r?Ps(r):[],a=await oe(t.project,t.storage),c=await yt(t.project,t.storage),p=await bt(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: ${ue(t.project)}`),o.length){l.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let d of o.slice(0,24))l.push(`- [ENFORCE] ${w(d,240)}`)}if(i.length){l.push("","PROJECT PREFERENCES");for(let d of i.slice(0,10))l.push(`- ${w(d,220)}`)}if(c&&(c.mission&&l.push("","MISSION",w(c.mission.value,420)),c.activeObjective&&l.push("","CURRENT OBJECTIVE",w(c.activeObjective.value,420)),c.why&&l.push("","WHY THIS WORK MATTERS",w(c.why.value,420)),c.desiredOutcome&&l.push("","DESIRED OUTCOME",w(c.desiredOutcome.value,420)),c.planRationale&&l.push("","WHY THIS APPROACH",w(c.planRationale.value,420))),a){if(l.push("","ACTIVE WORK"),a.goal&&l.push(`Goal: ${w(a.goal,320)}`),a.plan&&l.push(`Plan: ${w(a.plan,320)}`),l.push(`Progress: phases ${a.progress.phasesCompleted}/${a.progress.phasesTotal}; tasks ${a.progress.tasksCompleted}/${a.progress.tasksTotal}; blocked ${a.progress.blocked}`),a.currentPhase&&l.push(`Current phase: ${a.currentPhase.title} [${a.currentPhase.status}]`),a.currentPhase&&c){let d=c.phases.find(y=>y.order===a.currentPhase?.order);d&&(d.objective&&l.push(`Phase objective: ${w(d.objective.value,340)}`),d.why?l.push(`Why this phase: ${w(d.why.value,340)}`):l.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),d.deliverable&&l.push(`Deliverable: ${w(d.deliverable.value,340)}`),d.dependencies.length&&l.push(`Depends on: ${d.dependencies.slice(0,4).map(y=>w(y.value,180)).join("; ")}`),d.acceptanceCriteria.length&&(l.push("","DEFINITION OF DONE"),d.acceptanceCriteria.slice(0,6).forEach(y=>{l.push(`- ${w(y.value,260)}`)})),d.openQuestions.length&&(l.push("","OPEN QUESTIONS FOR CURRENT PHASE"),d.openQuestions.slice(0,4).forEach(y=>{l.push(`- ${w(y.value,260)}`)})))}a.currentTask&&l.push(`Current task: ${a.currentTask.title} [${a.currentTask.status}]`),a.nextActions.length&&(l.push("","NEXT ACTIONS"),a.nextActions.slice(0,6).forEach((d,y)=>{l.push(`${y+1}. ${w(d,260)}`)})),a.blockers.length&&(l.push("","BLOCKERS"),a.blockers.slice(0,5).forEach(d=>{l.push(`- ${w(d,260)}`)})),a.warnings.length&&(l.push("","ATTENTION"),a.warnings.slice(-5).forEach(d=>{l.push(`- ${w(d,260)}`)})),a.decisions.length&&(l.push("","RECENT DECISIONS"),a.decisions.slice(-5).forEach(d=>{l.push(`- ${w(d,260)}`)})),a.lastSession&&l.push("",`Last work session: ${a.lastSession.agent} / ${a.lastSession.nativeSessionId}`)}if(c&&c.openQuestions.length&&(l.push("","UNRESOLVED QUESTIONS"),c.openQuestions.slice(0,5).forEach(d=>{l.push(`- ${w(d.value,260)}`)})),p&&l.push(`Latest handoff: ${p.reason} / ${p.sourceSession.agent}`),u.length){l.push("","OPERATING NOTES");for(let d of u)l.push(`- ${d}`)}l.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let f=Es(l,e);return{version:1,projectId:t.project.id,projectName:t.project.name,text:f,estimatedTokens:Ae(f),maxTokens:e,hasManual:!!r,hasWorkState:!!a,hasHandoff:!!p,generatedAt:new Date().toISOString()}}function Ts(t){return Lt(t.rootPath,".toolnet","context","startup.md")}function Ms(t){return Lt(t.rootPath,".toolnet","context","startup.json")}function Ns(t,e){let n=Ts(t);Cs(Rs(n),{recursive:!0}),As(n,e.text.endsWith(`
|
|
83
83
|
`)?e.text:e.text+`
|
|
84
|
-
`,{encoding:"utf8",mode:384}),
|
|
84
|
+
`,{encoding:"utf8",mode:384}),x(Ms(t),e)}async function Kt(t,e,n=900){let r=await $t({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 Ns(t,s),await e.put(`projects/${t.id}/context/startup.md`,s.text+`
|
|
85
85
|
`,"text/markdown"),await e.put(`projects/${t.id}/context/startup.json`,JSON.stringify(s,null,2)+`
|
|
86
|
-
`,"application/json"),s}function
|
|
86
|
+
`,"application/json"),s}function ge(t,e){let n=t.indexOf(e);return n>=0?t[n+1]:void 0}function Ft(t){let e=Me(),n=De(ze({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new Q(n,t.id,t.name,t.remote??t.name)}async function Ws(t){for(let e=0;e<10;e+=1){let n=Ee(t);if(n)return n;await new Promise(r=>setTimeout(r,150))}return null}function zs(t){let e=Fs(Ks(),".config","toolnet-memory","codex-notify-previous.json");if(_s(e))try{let n=JSON.parse($s(e,"utf8"));if(!Array.isArray(n)||n.length===0||!n.every(s=>typeof s=="string"))return;Ls(n[0],[...n.slice(1),t],{detached:!0,stdio:"ignore"}).unref()}catch{}}async function Bs(t){let e;try{e=JSON.parse(t)}catch{return}if(e.type!=="agent-turn-complete")return;let r=typeof e["thread-id"]=="string"?e["thread-id"]:"",s=typeof e["turn-id"]=="string"?e["turn-id"]:"",o=typeof e.cwd=="string"?e.cwd:"",i=typeof e.client=="string"?e.client:void 0;if(!r||!o)return;let u=Ot(o);if(!u)return;let a=await Ws(r);if(!a)return;let c=Ft(u);await V({project:u,storage:c,threadId:r,rolloutPath:a,cwd:o,turnId:s,client:i,idle:!0});try{await Kt(u,c,900)}catch{}}async function Ds(){let[t="help",...e]=process.argv.slice(2);if(t==="install-notify"){let o=ge(e,"--bin"),i=Mt({binary:o}),u=_t({binary:o});console.log(`\u2705 Codex notify installed: ${i.configFile}`),i.preservedPrevious&&console.log(`\u2705 Previous notify preserved: ${i.previousFile}`),console.log(`\u2705 Codex SessionStart context hook: ${u}`);return}if(t==="notify"){let o=e[e.length-1]??"";try{await Bs(o)}finally{zs(o)}return}let n=ge(e,"--project")??process.cwd(),r=new N().detect(n),s=Ft(r);if(t==="sync"){let o=e[0];if(!o)throw new Error("Usage: sync <thread-id>");let i=ge(e,"--rollout")??Ee(o);if(!i)throw new Error(`Codex rollout not found for ${o}`);let u=await V({project:r,storage:s,threadId:o,rolloutPath:i,idle:e.includes("--idle")});console.log(JSON.stringify(u,null,2));return}if(t==="recover"){let o=Number(ge(e,"--limit")??100),i=await Et(r,s,Number.isFinite(o)?o:100);console.log(JSON.stringify({project:r.name,sessions:i.length,imported:i.reduce((u,a)=>u+a.imported,0)},null,2));return}console.log(`Codex Session Adapter
|
|
87
87
|
|
|
88
88
|
Commands:
|
|
89
89
|
install-notify
|
|
90
90
|
sync <thread-id> [--project PATH]
|
|
91
91
|
recover [--project PATH] [--limit N]
|
|
92
|
-
`)}
|
|
92
|
+
`)}Ds().catch(t=>{process.argv[2]==="notify"&&process.exit(0),console.error(t instanceof Error?t.message:t),process.exit(1)});
|