toolnet-memory 0.3.14 → 0.3.15

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.
Files changed (48) hide show
  1. package/.env.example +0 -1
  2. package/.release-target +1 -1
  3. package/README.md +25 -1
  4. package/bin/toolnet-memory +5 -0
  5. package/bundle/agy-hook.js +67 -67
  6. package/bundle/agy.js +61 -61
  7. package/bundle/api.js +15 -15
  8. package/bundle/auto-integrate.js +28 -28
  9. package/bundle/background-refresh.js +7 -7
  10. package/bundle/claude-hook.js +51 -50
  11. package/bundle/codex-context.js +25 -24
  12. package/bundle/codex.js +71 -71
  13. package/bundle/context-runtime.js +45 -44
  14. package/bundle/context.js +15 -15
  15. package/bundle/continuity-certify.js +13 -13
  16. package/bundle/copilot-hook.js +87 -85
  17. package/bundle/copilot.js +4 -4
  18. package/bundle/cursor-hook.js +87 -85
  19. package/bundle/cursor.js +4 -4
  20. package/bundle/doctor.js +4 -4
  21. package/bundle/full-index.js +20 -20
  22. package/bundle/gc.js +3 -0
  23. package/bundle/graph-index.js +4 -4
  24. package/bundle/graph-ui.js +3 -3
  25. package/bundle/grok-hook.js +60 -59
  26. package/bundle/grok.js +5 -5
  27. package/bundle/handoff-refresh.js +10 -10
  28. package/bundle/help-cli.js +4 -4
  29. package/bundle/impact.js +4 -4
  30. package/bundle/incremental.js +5 -4
  31. package/bundle/init.js +37 -37
  32. package/bundle/integration-status.js +4 -4
  33. package/bundle/kiro-hook.js +82 -81
  34. package/bundle/learner.js +6 -6
  35. package/bundle/mcp.js +17 -17
  36. package/bundle/memory-agent.js +7 -7
  37. package/bundle/memory-query.js +7 -7
  38. package/bundle/opencode.js +80 -80
  39. package/bundle/project-manual.js +7 -7
  40. package/bundle/recovery-certify.js +15 -15
  41. package/bundle/runtime.js +13 -12
  42. package/bundle/semantic.js +5 -5
  43. package/bundle/snapshot.js +4 -4
  44. package/bundle/status-cli.js +4 -4
  45. package/bundle/toolnet-cli.js +60 -60
  46. package/bundle/work-continuity.js +7 -7
  47. package/package.json +9 -3
  48. package/release-manifest.json +54 -3
package/bundle/context.js CHANGED
@@ -1,8 +1,8 @@
1
- import{existsSync as $e,readFileSync as We}from"node:fs";import{homedir as _e}from"node:os";import{join as Ke}from"node:path";function Fe(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
2
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function Le(){let r=process.env.TOOLNET_GLOBAL_ENV??Ke(_e(),".config","toolnet-memory",".env");if(!$e(r))return;let t=We(r,"utf8");for(let e of t.split(/\r?\n/)){let s=e.trim();if(!s||s.startsWith("#"))continue;s.startsWith("export ")&&(s=s.slice(7));let n=s.indexOf("=");if(n<=0)continue;let i=s.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=Fe(s.slice(n+1)))}}Le();function A(r,t){return r===void 0?t:["1","true","yes","on"].includes(r.toLowerCase())}function P(r,t){if(!r)return t;let e=Number(r);return Number.isFinite(e)?e:t}function ae(){return{memory:{autoCapture:A(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:A(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:A(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:A(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:P(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:P(process.env.MEMORY_RERANK_TOP,10),finalContext:P(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:P(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:A(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:P(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as De}from"node:crypto";import{existsSync as U,mkdirSync as Ve,readFileSync as ze,renameSync as Be,writeFileSync as He}from"node:fs";import{basename as Je,dirname as N,join as W,parse as de,resolve as M}from"node:path";var le=".toolnet",Ue="project.json";function qe(r){return De("sha256").update(r).digest("hex").slice(0,16)}function q(r){return W(r,le,Ue)}function Ge(r){return U(q(r))}function Ye(r,t){let e=M(r),s=de(e).root;for(;;){if(Ge(e))return e;if(e===s||t&&e===M(t))break;let n=N(e);if(n===e)break;e=n}return null}function Qe(r){let t=M(r),e=de(t).root,s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(s.some(i=>U(W(t,i))))return t;if(t===e)break;let n=N(t);if(n===t)break;t=n}return M(r)}function Xe(r){let t;try{t=JSON.parse(ze(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let s=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:N(N(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:s,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:s,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function ce(r,t){let e=W(r,le);Ve(e,{recursive:!0});let s=q(r),n=`${s}.tmp-${process.pid}`;He(n,JSON.stringify(t,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Be(n,s)}function ue(r,t){return{id:r.id,name:r.name,remote:r.remote,rootPath:t,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var $=class{detect(t=process.cwd()){let e=M(t),s=Qe(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(g=>U(W(s,g))),u=Ye(e,i?s:void 0);if(u){let g=q(u),a=Xe(g);return a.rootPath!==u&&(a.rootPath=u,a.updatedAt=new Date().toISOString(),ce(u,a)),ue(a,u)}let l=new Date().toISOString(),c=Je(s),p={version:1,id:qe(s),name:c,remote:c,rootPath:s,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return ce(s,p),ue(p,s)}};import{homedir as bt}from"node:os";import{join as wt}from"node:path";import{DeleteObjectCommand as Ze,GetObjectCommand as et,HeadObjectCommand as tt,ListObjectsV2Command as rt,PutObjectCommand as st,S3Client as nt}from"@aws-sdk/client-s3";import{getSignedUrl as ot}from"@aws-sdk/s3-request-presigner";var _=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new nt({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,s="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new st({Bucket:this.bucket,Key:t,Body:n,ContentType:s}))}async get(t){let e=await ot(this.client,new et({Bucket:this.bucket,Key:t}),{expiresIn:60}),s=await fetch(e,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`HF download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new tt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Ze({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],s;do{let n=await this.client.send(new rt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&e.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return e}};import{access as pe,mkdir as it,readFile as at,readdir as ct,rm as ut,stat as fe,writeFile as dt}from"node:fs/promises";import{dirname as lt,join as pt,relative as me,resolve as ft}from"node:path";var I=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return ft(this.root,e)}async put(t,e){let s=this.path(t);await it(lt(s),{recursive:!0}),await dt(s,e)}async get(t){try{return await at(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await pe(this.path(t)),!0}catch{return!1}}async delete(t){await ut(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),s=[];try{await pe(e)}catch{return s}let n=async u=>{let l=await ct(u,{withFileTypes:!0});for(let c of l){let p=pt(u,c.name);if(c.isDirectory()){await n(p);continue}let g=await fe(p);s.push({key:me(this.root,p),size:g.size,updatedAt:g.mtime.toISOString()})}},i=await fe(e);return i.isDirectory()?await n(e):s.push({key:me(this.root,e),size:i.size,updatedAt:i.mtime.toISOString()}),s}};import{DeleteObjectCommand as mt,GetObjectCommand as gt,HeadObjectCommand as ht,ListObjectsV2Command as yt,PutObjectCommand as kt,S3Client as St}from"@aws-sdk/client-s3";import{getSignedUrl as vt}from"@aws-sdk/s3-request-presigner";var R=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new St({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,s="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new kt({Bucket:this.bucket,Key:t,Body:n,ContentType:s}))}async get(t){let e=await vt(this.client,new gt({Bucket:this.bucket,Key:t}),{expiresIn:60}),s=await fetch(e,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`${this.name} download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new ht({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new mt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],s;do{let n=await this.client.send(new yt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&e.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return e}};function G(r,t){return console.warn(t),new I(r)}function ge(r){let t=r.localRoot??wt(bt(),".toolnet-memory","storage");if(r.provider==="r2"){let e=r.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new R({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):G(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let e=r.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new R({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):G(t,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let e=r.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new _({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):G(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new I(t)}function jt(r){return new Promise(t=>setTimeout(t,r))}async function he(r,t={}){let e=Math.max(1,t.attempts??3),s=t.baseDelayMs??150,n=t.maxDelayMs??2e3,i;for(let u=1;u<=e;u++)try{return await r()}catch(l){if(i=l,u>=e)break;let c=Math.min(n,s*2**(u-1)),p=Math.floor(Math.random()*Math.max(1,c*.2));await jt(c+p)}throw i}var xt=new Set(["put","get","getText","delete","list"]);function ye(r,t={}){return new Proxy(r,{get(e,s){let n=Reflect.get(e,s,e);return typeof n!="function"?n:xt.has(s)?(...i)=>he(()=>Promise.resolve(n.apply(e,i)),t):n.bind(e)}})}function ke(r){let t=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function Se(r){let t=r.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let s=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(s)return`${s[1]}memory/records/${s[2]}`;if(s=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),s)return`${s[1]}memory/vectors/${s[2]}`;if(s=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),s)return`${s[1]}code/graph/${s[2]}`;let n=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:t))}var K=class{constructor(t,e,s,n){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=s,this.folder=ke(n??s),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),s=e,n=await this.provider.getText(t);if(n){let u;try{u=JSON.parse(n)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${l instanceof Error?l.message:String(l)}`)}if(typeof u.id=="string"&&u.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${u.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof u.createdAt=="string"&&(s=u.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:s,updatedAt:e};await this.provider.put(t,JSON.stringify(i,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=Se(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,e,s){return await this.ensureRegistered(),this.provider.put(this.key(t),e,s)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};import{join as Tt}from"node:path";import{createHash as At}from"node:crypto";import{dirname as Pt}from"node:path";import{mkdirSync as Mt,readFileSync as nn,renameSync as It,writeFileSync as Rt}from"node:fs";function S(r){return At("sha256").update(r).digest("hex")}function x(r,t){Mt(Pt(r),{recursive:!0});let e=`${r}.${process.pid}.tmp`;Rt(e,JSON.stringify(t,null,2)+`
5
- `,{encoding:"utf8",mode:384}),It(e,r)}function ve(r,t){let e=r.trim(),s=e.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),n=S(e).slice(0,12);if(!s||s==="."||s==="..")return`${t}--${n}`;let i=s.slice(0,100);return i===e&&e.length<=100?i:`${i.slice(0,85)}--${n}`}function be(r,t,e){let s=t.trim(),n=e.trim();if(!s)throw new Error("Session agent is required");if(!n)throw new Error("Native session ID is required");let i=ve(s.toLowerCase(),"agent"),u=ve(n,"session");return{projectId:r.id,projectName:r.name,projectRoot:r.rootPath,agent:s,nativeSessionId:n,sessionKey:`${s}:${n}`,remotePrefix:["projects",r.id,"runtime","sources",i,u].join("/"),localDirectory:Tt(r.rootPath,".toolnet","runtime","sources",i,u)}}import{existsSync as xe,mkdirSync as Ct,readFileSync as Et,statSync as we,writeFileSync as Ot}from"node:fs";import{dirname as Nt,join as $t}from"node:path";var je=64*1024,Wt=`# ToolNet Project Operating Manual
1
+ import{existsSync as Ve,readFileSync as ze}from"node:fs";import{homedir as Be}from"node:os";import{join as He}from"node:path";function Je(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function Ue(){let r=process.env.TOOLNET_GLOBAL_ENV??He(Be(),".config","toolnet-memory",".env");if(!Ve(r))return;let t=ze(r,"utf8");for(let e of t.split(/\r?\n/)){let n=e.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let o=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Je(n.slice(s+1)))}}Ue();function P(r,t){return r===void 0?t:["1","true","yes","on"].includes(r.toLowerCase())}function M(r,t){if(!r)return t;let e=Number(r);return Number.isFinite(e)?e:t}function de(){return{memory:{autoCapture:P(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:P(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:P(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:P(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:M(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:M(process.env.MEMORY_RERANK_TOP,10),finalContext:M(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:M(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:P(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:M(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as qe}from"node:crypto";import{existsSync as _,mkdirSync as Ge,readFileSync as Ye,renameSync as Qe,writeFileSync as Ze}from"node:fs";import{basename as Xe,dirname as $,join as I,parse as ge,resolve as j}from"node:path";var he=".toolnet",et="project.json";function tt(r){return qe("sha256").update(r).digest("hex").slice(0,16)}function W(r){return I(r,he,et)}function rt(r){return _(W(r))}function le(r,t){let e=j(r),n=ge(e).root;for(;;){if(rt(e))return e;if(e===n||t&&e===j(t))break;let s=$(e);if(s===e)break;e=s}return null}function pe(r){let t=j(r),e=ge(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(o=>_(I(t,o))))return t;if(t===e)break;let s=$(t);if(s===t)break;t=s}return j(r)}function fe(r){let t;try{t=JSON.parse(Ye(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:$($(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:n,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:n,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function me(r,t){let e=I(r,he);Ge(e,{recursive:!0});let n=W(r),s=`${n}.tmp-${process.pid}`;Ze(s,JSON.stringify(t,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Qe(s,n)}function Q(r,t){return{id:r.id,name:r.name,remote:r.remote,rootPath:t,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var K=class{findExisting(t=process.cwd()){let e=j(t),n=pe(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>_(I(n,u))),a=le(e,o?n:void 0);if(!a)return null;let d=fe(W(a));return Q(d,a)}requireExisting(t=process.cwd()){let e=this.findExisting(t);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");return e}detect(t=process.cwd()){let e=j(t),n=pe(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(g=>_(I(n,g))),a=le(e,o?n:void 0);if(a){let g=W(a),c=fe(g);return c.rootPath!==a&&(c.rootPath=a,c.updatedAt=new Date().toISOString(),me(a,c)),Q(c,a)}let d=new Date().toISOString(),u=Xe(n),p={version:1,id:tt(n),name:u,remote:u,rootPath:n,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return me(n,p),Q(p,n)}};var nt=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],st=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ye(r){return r.normalize("NFKC").trim().toLowerCase()}function ot(r){if(r.length===0)return 0;let t=new Map;for(let n of r)t.set(n,(t.get(n)??0)+1);let e=0;for(let n of t.values()){let s=n/r.length;e-=s*Math.log2(s)}return e}function it(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function at(r,t,e){let n=r.slice(Math.max(0,t-48),t),s=r.slice(e,Math.min(r.length,e+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${s}`)}function ct(r,t){return r.start<t.end&&t.start<r.end}function ke(r){return r.sort((t,e)=>t.start!==e.start?t.start-e.start:e.end-e.start-(t.end-t.start))}var D=class{allowValues=new Set;enableEntropyHeuristic;constructor(t={}){for(let e of t.allowValues??[]){let n=ye(e);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=t.enableEntropyHeuristic??!0}scan(t){let e=[];for(let o of nt){let a=new RegExp(o.regex.source,o.regex.flags);for(let d of t.matchAll(a))d.index===void 0||!d[0]||this.allowed(d[0])||e.push({type:o.type,value:d[0],start:d.index,end:d.index+d[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&e.push(...this.entropyMatches(t));let n=ke(e),s=[];for(let o of n)s.some(a=>ct(a,o))||s.push(o);return ke(s)}hasSecrets(t){return this.scan(t).length>0}allowed(t){let e=ye(t);return st.has(e)?!0:this.allowValues.has(e)}entropyMatches(t){let e=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let s of t.matchAll(n)){if(s.index===void 0||!s[0])continue;let o=s[0];this.allowed(o)||it(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||at(t,s.index,s.index+o.length)&&(ot(o)<3.7||e.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return e}};var L=class{scanner;constructor(t={}){this.scanner=new D(t)}sanitize(t){let e=this.scanner.scan(t);if(e.length===0)return{text:t,redacted:0,secretTypes:[]};let n=t,s=[...e].sort((a,d)=>d.start-a.start),o=new Set;for(let a of s)o.add(a.type),n=n.slice(0,a.start)+`[REDACTED:${a.type}]`+n.slice(a.end);return{text:n,redacted:e.length,secretTypes:[...o].sort()}}sanitizeValue(t){if(typeof t=="string")return this.sanitize(t).text;if(Array.isArray(t))return t.map(e=>this.sanitizeValue(e));if(t&&typeof t=="object"){let e={};for(let[n,s]of Object.entries(t)){let o=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){e[n]="[REDACTED]";continue}e[n]=this.sanitizeValue(s)}return e}return t}};var Er=new L;import{homedir as Et}from"node:os";import{join as Ot}from"node:path";import{DeleteObjectCommand as dt,GetObjectCommand as lt,HeadObjectCommand as pt,ListObjectsV2Command as ft,PutObjectCommand as mt,S3Client as gt}from"@aws-sdk/client-s3";import{getSignedUrl as ht}from"@aws-sdk/s3-request-presigner";var F=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new gt({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new mt({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await ht(this.client,new lt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new pt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new dt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new ft({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};import{access as Se,mkdir as yt,readFile as kt,readdir as St,rm as bt,stat as be,writeFile as vt}from"node:fs/promises";import{dirname as wt,join as xt,relative as ve,resolve as jt}from"node:path";var R=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return jt(this.root,e)}async put(t,e){let n=this.path(t);await yt(wt(n),{recursive:!0}),await vt(n,e)}async get(t){try{return await kt(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await Se(this.path(t)),!0}catch{return!1}}async delete(t){await bt(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),n=[];try{await Se(e)}catch{return n}let s=async a=>{let d=await St(a,{withFileTypes:!0});for(let u of d){let p=xt(a,u.name);if(u.isDirectory()){await s(p);continue}let g=await be(p);n.push({key:ve(this.root,p),size:g.size,updatedAt:g.mtime.toISOString()})}},o=await be(e);return o.isDirectory()?await s(e):n.push({key:ve(this.root,e),size:o.size,updatedAt:o.mtime.toISOString()}),n}};import{DeleteObjectCommand as At,GetObjectCommand as Pt,HeadObjectCommand as Mt,ListObjectsV2Command as It,PutObjectCommand as Rt,S3Client as Tt}from"@aws-sdk/client-s3";import{getSignedUrl as Ct}from"@aws-sdk/s3-request-presigner";var T=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Tt({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Rt({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await Ct(this.client,new Pt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new Mt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new At({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new It({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};function Z(r,t){return console.warn(t),new R(r)}function we(r){let t=r.localRoot??Ot(Et(),".toolnet-memory","storage");if(r.provider==="r2"){let e=r.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new T({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):Z(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let e=r.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new T({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):Z(t,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let e=r.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new F({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):Z(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new R(t)}function Nt(r){return new Promise(t=>setTimeout(t,r))}async function xe(r,t={}){let e=Math.max(1,t.attempts??3),n=t.baseDelayMs??150,s=t.maxDelayMs??2e3,o;for(let a=1;a<=e;a++)try{return await r()}catch(d){if(o=d,a>=e)break;let u=Math.min(s,n*2**(a-1)),p=Math.floor(Math.random()*Math.max(1,u*.2));await Nt(u+p)}throw o}var _t=new Set(["put","get","getText","delete","list"]);function je(r,t={}){return new Proxy(r,{get(e,n){let s=Reflect.get(e,n,e);return typeof s!="function"?s:_t.has(n)?(...o)=>xe(()=>Promise.resolve(s.apply(e,o)),t):s.bind(e)}})}function Ae(r){let t=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function Pe(r){let t=r.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let s=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:t))}var V=class{constructor(t,e,n,s){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=n,this.folder=Ae(s??n),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),n=e,s=await this.provider.getText(t);if(s){let a;try{a=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${d instanceof Error?d.message:String(d)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(n=a.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:e};await this.provider.put(t,JSON.stringify(o,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=Pe(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,e,n){return await this.ensureRegistered(),this.provider.put(this.key(t),e,n)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};import{join as Ft}from"node:path";import{createHash as $t}from"node:crypto";import{dirname as Wt}from"node:path";import{mkdirSync as Kt,readFileSync as ks,renameSync as Dt,writeFileSync as Lt}from"node:fs";function S(r){return $t("sha256").update(r).digest("hex")}function A(r,t){Kt(Wt(r),{recursive:!0});let e=`${r}.${process.pid}.tmp`;Lt(e,JSON.stringify(t,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),Dt(e,r)}function Me(r,t){let e=r.trim(),n=e.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=S(e).slice(0,12);if(!n||n==="."||n==="..")return`${t}--${s}`;let o=n.slice(0,100);return o===e&&e.length<=100?o:`${o.slice(0,85)}--${s}`}function Ie(r,t,e){let n=t.trim(),s=e.trim();if(!n)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let o=Me(n.toLowerCase(),"agent"),a=Me(s,"session");return{projectId:r.id,projectName:r.name,projectRoot:r.rootPath,agent:n,nativeSessionId:s,sessionKey:`${n}:${s}`,remotePrefix:["projects",r.id,"runtime","sources",o,a].join("/"),localDirectory:Ft(r.rootPath,".toolnet","runtime","sources",o,a)}}import{existsSync as Ce,mkdirSync as Vt,readFileSync as zt,statSync as Re,writeFileSync as Bt}from"node:fs";import{dirname as Ht,join as Jt}from"node:path";var Te=64*1024,Ut=`# ToolNet Project Operating Manual
6
6
 
7
7
  This file contains persistent instructions for AI agents working on this project.
8
8
 
@@ -45,19 +45,19 @@ Things an AI agent should always remember.
45
45
  <!--
46
46
  - [advisory] Prefer small focused files.
47
47
  -->
48
- `;function F(r){return $t(r.rootPath,".toolnet","PROJECT.md")}function _t(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Kt(r){let t=[],e=new Set,s=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,n;for(;n=s.exec(r);){let i=n[1].toLowerCase(),u=_t(n[2]);if(!u)continue;let l=`${i}:${u.toLowerCase()}`;e.has(l)||(e.add(l),t.push({id:S(l).slice(0,24),mode:i,text:u,source:"manual"}))}return t}function Ft(r){let t=F(r);return xe(t)||(Ct(Nt(t),{recursive:!0}),Ot(t,Wt,{encoding:"utf8",mode:384})),t}function L(r,t=!1){let e=t?Ft(r):F(r);if(!xe(e))return null;if(we(e).size>je)throw new Error(`PROJECT.md exceeds ${je} bytes`);let n=Et(e,"utf8");return{path:e,content:n,digest:S(n),rules:Kt(n),bytes:Buffer.byteLength(n,"utf8"),updatedAt:new Date(we(e).mtimeMs).toISOString()}}import{existsSync as Yt,mkdirSync as Qt}from"node:fs";import{join as Q}from"node:path";import{join as Ae}from"node:path";import{mkdirSync as Lt}from"node:fs";function Me(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function v(r,t=20){let e=[],s=new Set;for(let n of r.slice().reverse()){let i=Me(n);if(!(!i||s.has(i))&&(s.add(i),e.push(n),e.length>=t))break}return e.reverse()}function Dt(r,t=20){let e=new Map;for(let s of r){let n=`${s.kind}|${Me(s.command)}`;e.delete(n),e.set(n,s)}return Array.from(e.values()).slice(-t)}function Vt(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function Pe(r,t){let e=t.status??r?.status??"pending",s=e;r&&(r.status==="completed"&&e!=="completed"?s="completed":e==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(s=r.status));let n=r&&Vt(t)?r.title:t.text;return{id:r?.id??S(t.key).slice(0,24),title:n,status:s,order:t.order??r?.order,confidence:Math.max(t.confidence,r?.confidence??0),updatedAt:t.occurredAt,updatedBy:{agent:t.agent,nativeSessionId:t.nativeSessionId,eventId:t.eventId}}}async function Ie(r,t){let e=`projects/${r.id}/work/observations/`,s=await t.list(e),n=[];for(let i of s.filter(u=>u.key.endsWith(".json")).sort((u,l)=>u.key.localeCompare(l.key))){let u=await t.getText(i.key);if(u)try{let l=JSON.parse(u);l.version===1&&Array.isArray(l.observations)&&n.push(l)}catch{}}return n}async function Y(r,t){let s=(await Ie(r,t)).flatMap(o=>o.observations).sort((o,k)=>{let oe=o.occurredAt.localeCompare(k.occurredAt);if(oe!==0)return oe;let ie=o.sequence-k.sequence;return ie!==0?ie:o.id.localeCompare(k.id)}),n=new Map,i=new Map,u,l,c,p,g,a=[],j=[],d=[],y=[],B=[],C=new Map,E=[],f=[],ee=[],te=[],re=[],se=[];for(let o of s)switch(o.kind){case"request":u=o.text;break;case"activity":l=o.text;break;case"goal":c=o.text;break;case"plan":p=o.text;break;case"phase":n.set(o.key,Pe(n.get(o.key),o));break;case"task":i.set(o.key,Pe(i.get(o.key),o));break;case"decision":a.push(o.text);break;case"blocker":j.push(o.text);break;case"warning":d.push(o.text);break;case"next_action":y.push(o.text);break;case"file":{B.push(o.text);let k=o.fileAction??"active";C.delete(o.text),C.set(o.text,k),k==="modified"?E.push(o.text):k==="created"?f.push(o.text):k==="deleted"&&ee.push(o.text);break}case"command":te.push(o.text);break;case"test":re.push(o.text),o.checkKind&&se.push({kind:o.checkKind,command:o.text,status:o.checkStatus??"unknown",updatedAt:o.occurredAt,agent:o.agent,nativeSessionId:o.nativeSessionId});break;case"session":g={agent:o.agent,nativeSessionId:o.nativeSessionId,sessionKey:o.sessionKey,updatedAt:o.occurredAt};break}let w=Array.from(n.values()).sort((o,k)=>(o.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),b=Array.from(i.values()).sort((o,k)=>(o.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),H=w.find(o=>o.status==="in_progress")??w.find(o=>o.status==="blocked")??w.find(o=>o.status==="pending"),O=b.find(o=>o.status==="in_progress")??b.find(o=>o.status==="blocked")??b.find(o=>o.status==="pending"),Oe=v([...y,...O?[O.title]:[],...!O&&H?[H.title]:[],...b.filter(o=>o.status==="pending").slice(0,5).map(o=>o.title)],8),Ne=v([...j,...w.filter(o=>o.status==="blocked").map(o=>o.title),...b.filter(o=>o.status==="blocked").map(o=>o.title)],20),J={version:1,projectId:r.id,projectName:r.name,currentRequest:u,currentActivity:l,goal:c,plan:p,phases:w,tasks:b,decisions:v(a,20),blockers:Ne,warnings:v(d,20),nextActions:Oe,filesTouched:v(B,30),activeFiles:Array.from(C.entries()).filter(([,o])=>o!=="deleted").map(([o])=>o).slice(-5),modifiedFiles:v(E,30),createdFiles:v(f,30),deletedFiles:v(ee,30),commands:v(te,20),tests:v(re,20),checks:Dt(se,20),currentPhase:H,currentTask:O,progress:{phasesTotal:w.length,phasesCompleted:w.filter(o=>o.status==="completed").length,tasksTotal:b.length,tasksCompleted:b.filter(o=>o.status==="completed").length,blocked:w.filter(o=>o.status==="blocked").length+b.filter(o=>o.status==="blocked").length},lastSession:g,updatedAt:s.length?s[s.length-1].occurredAt:new Date().toISOString()},ne=Ae(r.rootPath,".toolnet","work");return Lt(ne,{recursive:!0}),x(Ae(ne,"current.json"),J),await t.put(`projects/${r.id}/work/current.json`,JSON.stringify(J,null,2)+`
49
- `,"application/json"),J}async function D(r,t){if((await Ie(r,t)).length>0)return Y(r,t);let s=await t.getText(`projects/${r.id}/work/current.json`);if(!s)return null;try{return JSON.parse(s)}catch{return null}}var kn=new Int32Array(new SharedArrayBuffer(4));import{closeSync as jn,existsSync as zt,fsyncSync as xn,mkdirSync as An,openSync as Pn,readFileSync as Bt,renameSync as Mn,writeFileSync as In}from"node:fs";import{dirname as Tn,join as Ht}from"node:path";function Jt(r){return Ht(r.rootPath,".toolnet","work","current.json")}function Re(r){let t=Jt(r);if(!zt(t))return null;try{let e=JSON.parse(Bt(t,"utf8"));return e.version!==1||e.projectId!==r.id?null:e}catch{return null}}function h(r,t){let e=new Set,s=[];for(let n of r){let i=n.replace(/\s+/g," ").trim();if(!i)continue;let u=i.normalize("NFKC").toLowerCase();if(!e.has(u)&&(e.add(u),s.push(i),s.length>=t))break}return s}function Te(r){if(r)return{id:r.id,title:r.title,status:r.status}}function Ut(r,t=[]){let e=t.slice(-10);if(e.some(n=>n.status==="failed"))return"failing";if(e.some(n=>n.status==="passed"))return"passing";let s=r.slice(-10).join(`
50
- `).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(s)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(s)?"passing":"unknown"}function qt(r){return S(JSON.stringify(r))}function Gt(r){let t=[];for(let e of r){if(!e)continue;let s=e.match(/https?:\/\/[^\s<>"'`)\]}]+/giu)??[];for(let n of s){let i=n.replace(/[.,;:!?]+$/gu,"").trim();i&&t.push(i)}}return h(t,30)}function Ce(r){let{project:t,identity:e,state:s}=r,n=s.activeFiles?.at(-1)??s.filesTouched.at(-1),i=s.phases.filter(f=>f.status==="completed").map(f=>f.title),u=s.tasks.filter(f=>f.status==="completed").map(f=>f.title),l=s.phases.filter(f=>f.status!=="completed"&&f.status!=="cancelled").map(f=>f.title),c=s.tasks.filter(f=>f.status!=="completed"&&f.status!=="cancelled").map(f=>f.title),p=new Set(s.tasks.filter(f=>f.status==="completed").map(f=>f.title.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),g=h(s.nextActions.filter(f=>!p.has(f.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),10),a=h([...c,...g],15),j=h(s.tests.slice().reverse(),10),d=h([...(s.activeFiles??[]).slice().reverse(),...s.filesTouched.slice().reverse()],20),y={schema:"toolnet.handoff.v2",version:2,project:{id:t.id,name:t.name},source:{agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,sequence:r.sequence,reason:r.reason},capturedAt:r.capturedAt??new Date().toISOString(),goal:s.goal,request:s.currentRequest,activity:s.currentActivity,current:{phase:Te(s.currentPhase),task:Te(s.currentTask),file:n},completed:{phases:h(i,20),tasks:h(u,30)},remaining:{phases:h(l,20),tasks:h(c,30),todos:a},nextAction:g[0],blockers:h(s.blockers.slice().reverse(),10),decisions:h(s.decisions.slice().reverse(),10),files:{current:n,recent:d,active:h(s.activeFiles??[],10),modified:h(s.modifiedFiles??[],20),created:h(s.createdFiles??[],20),deleted:h(s.deletedFiles??[],20)},tests:{status:Ut(s.tests,s.checks),recent:j,checks:(s.checks??[]).slice(-10).map(f=>({kind:f.kind,status:f.status,command:f.command}))},evidence:{commands:h((s.commands??[]).slice().reverse(),20),references:Gt([s.currentRequest,s.currentActivity,s.goal,s.plan,...s.decisions,...s.blockers,...s.warnings,...s.nextActions,...s.filesTouched,...s.commands??[],...s.tests,...(s.checks??[]).map(f=>f.command)])},attention:h(r.attention??[],20),progress:s.progress},{capturedAt:B,source:C,...E}=y;return{...y,stateDigest:qt(E)}}function Xt(r){return!!(r.currentRequest||r.currentActivity||r.goal||r.plan||r.phases.length>0||r.tasks.length>0||r.nextActions.length>0||r.blockers.length>0||r.decisions.length>0||r.filesTouched.length>0)}function Zt(r,t,e,s,n){if(!Xt(e))return null;let i=L(r,!1),l=[...i?i.rules.filter(a=>a.mode==="enforce").map(a=>a.text):[],...e.warnings].slice(0,20),c=Ce({project:r,identity:t,state:e,reason:s,sequence:n,attention:l}),p=c.stateDigest;return{version:1,id:S([r.id,t.sessionKey,p].join("|")).slice(0,24),projectId:r.id,projectName:r.name,createdAt:new Date().toISOString(),reason:s,sourceSession:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,sequence:n},currentRequest:e.currentRequest,currentActivity:e.currentActivity,goal:e.goal,plan:e.plan,progress:e.progress,currentPhase:e.currentPhase,currentTask:e.currentTask,incompletePhases:e.phases.filter(a=>a.status!=="completed"&&a.status!=="cancelled"),incompleteTasks:e.tasks.filter(a=>a.status!=="completed"&&a.status!=="cancelled"),nextActions:c.remaining.todos.slice(0,10),blockers:e.blockers.slice(-10),decisions:e.decisions.slice(-10),warnings:e.warnings.slice(-10),attention:l,filesTouched:e.filesTouched.slice(-20),activeFiles:e.activeFiles?.slice(-10),modifiedFiles:e.modifiedFiles?.slice(-20),createdFiles:e.createdFiles?.slice(-20),deletedFiles:e.deletedFiles?.slice(-20),tests:e.tests.slice(-15),checks:e.checks?.slice(-10),stateDigest:p,continuity:c}}function er(r,t){let e=Q(r.rootPath,".toolnet","work","handoffs");Qt(e,{recursive:!0});let s=Q(e,`${t.id}.json`);Yt(s)||x(s,t),x(Q(r.rootPath,".toolnet","work","handoff-latest.json"),t)}var V=class{constructor(t){this.options=t}options;async capture(t,e){let s=Re(this.options.project);s||(s=await D(this.options.project,this.options.storage)),s||(s=await Y(this.options.project,this.options.storage));let n=Zt(this.options.project,this.options.identity,s,t,e);if(!n)return null;er(this.options.project,n);let i=`projects/${this.options.project.id}/work/handoffs/${n.id}.json`;return await this.options.storage.exists(i)||await this.options.storage.put(i,JSON.stringify(n,null,2)+`
51
- `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(n,null,2)+`
52
- `,"application/json"),n}};async function z(r,t){let e=await t.getText(`projects/${r.id}/work/handoff-latest.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function Ee(r,t){let e=await t.getText(`projects/${r.id}/work/semantic/current.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}function X(r){if(!r)return 0;let t=Array.from(r).length,e=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(t/3.5,e*1.3))}function m(r,t){let e=r.replace(/\s+/g," ").trim();return e.length<=t?e:e.slice(0,Math.max(0,t-1)).trimEnd()+"\u2026"}function tr(r){let t=[],e=!1;for(let s of r.split(/\r?\n/u)){let n=s.trim();if(n.includes("<!--")&&(e=!0),e){n.includes("-->")&&(e=!1);continue}let i=n.toLowerCase();if(!(!n||n.startsWith("#")||n==="```"||i.startsWith("- [enforce]")||i.startsWith("* [enforce]")||i.startsWith("- [advisory]")||i.startsWith("* [advisory]"))&&(n=n.replace(/^[-*]\s+/u,""),n&&t.push(m(n,280)),t.length>=16))break}return t}function rr(r){let t=[],e=[];for(let s of r.split(/\\r?\\n/u)){let n=s.trim(),i=n.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(p=>i.startsWith(p));if(!l)continue;let c=n.slice(l.length).trim();c&&(l.includes("enforce")?t.push(c):e.push(c))}return{enforce:t,advisory:e}}function sr(r,t){let e=[];for(let s of r){let n=[...e,s].join(`
53
- `);if(X(n)<=t){e.push(s);continue}let i=X(e.join(`
54
- `)),u=Math.max(0,t-i);if(u>=16){let l=Math.floor(u*3.2),c=m(s,l);c&&e.push(c)}break}return e.join(`
55
- `).trim()}async function Z(r){let t=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),e=L(r.project,!1),s=e?.content??"";s||(s=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let n=rr(s),i=e?e.rules.filter(d=>d.mode==="enforce").map(d=>d.text):n.enforce,u=e?e.rules.filter(d=>d.mode==="advisory").map(d=>d.text):n.advisory,l=s?tr(s):[],c=await D(r.project,r.storage),p=await Ee(r.project,r.storage),g=await z(r.project,r.storage),a=[];if(a.push("[TOOLNET PROJECT CONTEXT]"),a.push(`Project: ${r.project.name}`),a.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),s&&a.push(`Full operating manual: ${F(r.project)}`),i.length){a.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let d of i.slice(0,24))a.push(`- [ENFORCE] ${m(d,240)}`)}if(u.length){a.push("","PROJECT PREFERENCES");for(let d of u.slice(0,10))a.push(`- ${m(d,220)}`)}if(p&&(p.mission&&a.push("","MISSION",m(p.mission.value,420)),p.activeObjective&&a.push("","CURRENT OBJECTIVE",m(p.activeObjective.value,420)),p.why&&a.push("","WHY THIS WORK MATTERS",m(p.why.value,420)),p.desiredOutcome&&a.push("","DESIRED OUTCOME",m(p.desiredOutcome.value,420)),p.planRationale&&a.push("","WHY THIS APPROACH",m(p.planRationale.value,420))),c){if(a.push("","ACTIVE WORK"),c.goal&&a.push(`Goal: ${m(c.goal,320)}`),c.plan&&a.push(`Plan: ${m(c.plan,320)}`),a.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&a.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&p){let d=p.phases.find(y=>y.order===c.currentPhase?.order);d&&(d.objective&&a.push(`Phase objective: ${m(d.objective.value,340)}`),d.why?a.push(`Why this phase: ${m(d.why.value,340)}`):a.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),d.deliverable&&a.push(`Deliverable: ${m(d.deliverable.value,340)}`),d.dependencies.length&&a.push(`Depends on: ${d.dependencies.slice(0,4).map(y=>m(y.value,180)).join("; ")}`),d.acceptanceCriteria.length&&(a.push("","DEFINITION OF DONE"),d.acceptanceCriteria.slice(0,6).forEach(y=>{a.push(`- ${m(y.value,260)}`)})),d.openQuestions.length&&(a.push("","OPEN QUESTIONS FOR CURRENT PHASE"),d.openQuestions.slice(0,4).forEach(y=>{a.push(`- ${m(y.value,260)}`)})))}c.currentTask&&a.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(a.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((d,y)=>{a.push(`${y+1}. ${m(d,260)}`)})),c.blockers.length&&(a.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(d=>{a.push(`- ${m(d,260)}`)})),c.warnings.length&&(a.push("","ATTENTION"),c.warnings.slice(-5).forEach(d=>{a.push(`- ${m(d,260)}`)})),c.decisions.length&&(a.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(d=>{a.push(`- ${m(d,260)}`)})),c.lastSession&&a.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(p&&p.openQuestions.length&&(a.push("","UNRESOLVED QUESTIONS"),p.openQuestions.slice(0,5).forEach(d=>{a.push(`- ${m(d.value,260)}`)})),g&&a.push(`Latest handoff: ${g.reason} / ${g.sourceSession.agent}`),l.length){a.push("","OPERATING NOTES");for(let d of l)a.push(`- ${d}`)}a.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let j=sr(a,t);return{version:1,projectId:r.project.id,projectName:r.project.name,text:j,estimatedTokens:X(j),maxTokens:t,hasManual:!!s,hasWorkState:!!c,hasHandoff:!!g,generatedAt:new Date().toISOString()}}function T(r,t){let e=r.indexOf(t);return e>=0?r[e+1]:void 0}function nr(r){let t=ae(),e=ye(ge({provider:t.storage.provider,huggingface:t.storage.huggingface,localRoot:t.storage.localRoot}),{attempts:3});return new K(e,r.id,r.name,r.remote??r.name)}async function or(){let[r="help",...t]=process.argv.slice(2),e=new $().detect(T(t,"--project")??process.cwd()),s=nr(e);if(r==="brief"){let n=Number(T(t,"--tokens")??1e3),i=await Z({project:e,storage:s,maxTokens:Number.isFinite(n)?n:1e3});process.stdout.write(i.text+`
56
- `);return}if(r==="brief-json"){let n=await Z({project:e,storage:s,maxTokens:Number(T(t,"--tokens")??1e3)});console.log(JSON.stringify(n,null,2));return}if(r==="handoff-latest"){let n=await z(e,s);console.log(JSON.stringify(n,null,2));return}if(r==="handoff-create"){let n=T(t,"--agent")??"manual";if(n==="manual")throw new Error("--agent must be opencode, agy, or codex");let i=T(t,"--session");if(!i)throw new Error("--session is required");let u=be(e,n,i),c=await new V({project:e,storage:s,identity:u}).capture("manual",0);console.log(JSON.stringify(c,null,2));return}console.log(`Work Context
48
+ `;function z(r){return Jt(r.rootPath,".toolnet","PROJECT.md")}function qt(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Gt(r){let t=[],e=new Set,n=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=n.exec(r);){let o=s[1].toLowerCase(),a=qt(s[2]);if(!a)continue;let d=`${o}:${a.toLowerCase()}`;e.has(d)||(e.add(d),t.push({id:S(d).slice(0,24),mode:o,text:a,source:"manual"}))}return t}function Yt(r){let t=z(r);return Ce(t)||(Vt(Ht(t),{recursive:!0}),Bt(t,Ut,{encoding:"utf8",mode:384})),t}function B(r,t=!1){let e=t?Yt(r):z(r);if(!Ce(e))return null;if(Re(e).size>Te)throw new Error(`PROJECT.md exceeds ${Te} bytes`);let s=zt(e,"utf8");return{path:e,content:s,digest:S(s),rules:Gt(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(Re(e).mtimeMs).toISOString()}}import{existsSync as ar,mkdirSync as cr}from"node:fs";import{join as ee}from"node:path";import{join as Ee}from"node:path";import{mkdirSync as Qt}from"node:fs";function Ne(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function b(r,t=20){let e=[],n=new Set;for(let s of r.slice().reverse()){let o=Ne(s);if(!(!o||n.has(o))&&(n.add(o),e.push(s),e.length>=t))break}return e.reverse()}function Zt(r,t=20){let e=new Map;for(let n of r){let s=`${n.kind}|${Ne(n.command)}`;e.delete(s),e.set(s,n)}return Array.from(e.values()).slice(-t)}function Xt(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function Oe(r,t){let e=t.status??r?.status??"pending",n=e;r&&(r.status==="completed"&&e!=="completed"?n="completed":e==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(n=r.status));let s=r&&Xt(t)?r.title:t.text;return{id:r?.id??S(t.key).slice(0,24),title:s,status:n,order:t.order??r?.order,confidence:Math.max(t.confidence,r?.confidence??0),updatedAt:t.occurredAt,updatedBy:{agent:t.agent,nativeSessionId:t.nativeSessionId,eventId:t.eventId}}}async function _e(r,t){let e=`projects/${r.id}/work/observations/`,n=await t.list(e),s=[];for(let o of n.filter(a=>a.key.endsWith(".json")).sort((a,d)=>a.key.localeCompare(d.key))){let a=await t.getText(o.key);if(a)try{let d=JSON.parse(a);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}async function X(r,t){let n=(await _e(r,t)).flatMap(i=>i.observations).sort((i,k)=>{let ce=i.occurredAt.localeCompare(k.occurredAt);if(ce!==0)return ce;let ue=i.sequence-k.sequence;return ue!==0?ue:i.id.localeCompare(k.id)}),s=new Map,o=new Map,a,d,u,p,g,c=[],x=[],l=[],y=[],q=[],E=new Map,O=[],f=[],ne=[],se=[],oe=[],ie=[];for(let i of n)switch(i.kind){case"request":a=i.text;break;case"activity":d=i.text;break;case"goal":u=i.text;break;case"plan":p=i.text;break;case"phase":s.set(i.key,Oe(s.get(i.key),i));break;case"task":o.set(i.key,Oe(o.get(i.key),i));break;case"decision":c.push(i.text);break;case"blocker":x.push(i.text);break;case"warning":l.push(i.text);break;case"next_action":y.push(i.text);break;case"file":{q.push(i.text);let k=i.fileAction??"active";E.delete(i.text),E.set(i.text,k),k==="modified"?O.push(i.text):k==="created"?f.push(i.text):k==="deleted"&&ne.push(i.text);break}case"command":se.push(i.text);break;case"test":oe.push(i.text),i.checkKind&&ie.push({kind:i.checkKind,command:i.text,status:i.checkStatus??"unknown",updatedAt:i.occurredAt,agent:i.agent,nativeSessionId:i.nativeSessionId});break;case"session":g={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let w=Array.from(s.values()).sort((i,k)=>(i.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),v=Array.from(o.values()).sort((i,k)=>(i.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),G=w.find(i=>i.status==="in_progress")??w.find(i=>i.status==="blocked")??w.find(i=>i.status==="pending"),N=v.find(i=>i.status==="in_progress")??v.find(i=>i.status==="blocked")??v.find(i=>i.status==="pending"),Le=b([...y,...N?[N.title]:[],...!N&&G?[G.title]:[],...v.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Fe=b([...x,...w.filter(i=>i.status==="blocked").map(i=>i.title),...v.filter(i=>i.status==="blocked").map(i=>i.title)],20),Y={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:d,goal:u,plan:p,phases:w,tasks:v,decisions:b(c,20),blockers:Fe,warnings:b(l,20),nextActions:Le,filesTouched:b(q,30),activeFiles:Array.from(E.entries()).filter(([,i])=>i!=="deleted").map(([i])=>i).slice(-5),modifiedFiles:b(O,30),createdFiles:b(f,30),deletedFiles:b(ne,30),commands:b(se,20),tests:b(oe,20),checks:Zt(ie,20),currentPhase:G,currentTask:N,progress:{phasesTotal:w.length,phasesCompleted:w.filter(i=>i.status==="completed").length,tasksTotal:v.length,tasksCompleted:v.filter(i=>i.status==="completed").length,blocked:w.filter(i=>i.status==="blocked").length+v.filter(i=>i.status==="blocked").length},lastSession:g,updatedAt:n.length?n[n.length-1].occurredAt:new Date().toISOString()},ae=Ee(r.rootPath,".toolnet","work");return Qt(ae,{recursive:!0}),A(Ee(ae,"current.json"),Y),await t.put(`projects/${r.id}/work/current.json`,JSON.stringify(Y,null,2)+`
49
+ `,"application/json"),Y}async function H(r,t){if((await _e(r,t)).length>0)return X(r,t);let n=await t.getText(`projects/${r.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}var Cs=new Int32Array(new SharedArrayBuffer(4));import{closeSync as $s,existsSync as er,fsyncSync as Ws,mkdirSync as Ks,openSync as Ds,readFileSync as tr,renameSync as Ls,writeFileSync as Fs}from"node:fs";import{dirname as zs,join as rr}from"node:path";function nr(r){return rr(r.rootPath,".toolnet","work","current.json")}function $e(r){let t=nr(r);if(!er(t))return null;try{let e=JSON.parse(tr(t,"utf8"));return e.version!==1||e.projectId!==r.id?null:e}catch{return null}}function h(r,t){let e=new Set,n=[];for(let s of r){let o=s.replace(/\s+/g," ").trim();if(!o)continue;let a=o.normalize("NFKC").toLowerCase();if(!e.has(a)&&(e.add(a),n.push(o),n.length>=t))break}return n}function We(r){if(r)return{id:r.id,title:r.title,status:r.status}}function sr(r,t=[]){let e=t.slice(-10);if(e.some(s=>s.status==="failed"))return"failing";if(e.some(s=>s.status==="passed"))return"passing";let n=r.slice(-10).join(`
50
+ `).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(n)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(n)?"passing":"unknown"}function or(r){return S(JSON.stringify(r))}function ir(r){let t=[];for(let e of r){if(!e)continue;let n=e.match(/https?:\/\/[^\s<>"'`)\]}]+/giu)??[];for(let s of n){let o=s.replace(/[.,;:!?]+$/gu,"").trim();o&&t.push(o)}}return h(t,30)}function Ke(r){let{project:t,identity:e,state:n}=r,s=n.activeFiles?.at(-1)??n.filesTouched.at(-1),o=n.phases.filter(f=>f.status==="completed").map(f=>f.title),a=n.tasks.filter(f=>f.status==="completed").map(f=>f.title),d=n.phases.filter(f=>f.status!=="completed"&&f.status!=="cancelled").map(f=>f.title),u=n.tasks.filter(f=>f.status!=="completed"&&f.status!=="cancelled").map(f=>f.title),p=new Set(n.tasks.filter(f=>f.status==="completed").map(f=>f.title.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),g=h(n.nextActions.filter(f=>!p.has(f.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),10),c=h([...u,...g],15),x=h(n.tests.slice().reverse(),10),l=h([...(n.activeFiles??[]).slice().reverse(),...n.filesTouched.slice().reverse()],20),y={schema:"toolnet.handoff.v2",version:2,project:{id:t.id,name:t.name},source:{agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,sequence:r.sequence,reason:r.reason},capturedAt:r.capturedAt??new Date().toISOString(),goal:n.goal,request:n.currentRequest,activity:n.currentActivity,current:{phase:We(n.currentPhase),task:We(n.currentTask),file:s},completed:{phases:h(o,20),tasks:h(a,30)},remaining:{phases:h(d,20),tasks:h(u,30),todos:c},nextAction:g[0],blockers:h(n.blockers.slice().reverse(),10),decisions:h(n.decisions.slice().reverse(),10),files:{current:s,recent:l,active:h(n.activeFiles??[],10),modified:h(n.modifiedFiles??[],20),created:h(n.createdFiles??[],20),deleted:h(n.deletedFiles??[],20)},tests:{status:sr(n.tests,n.checks),recent:x,checks:(n.checks??[]).slice(-10).map(f=>({kind:f.kind,status:f.status,command:f.command}))},evidence:{commands:h((n.commands??[]).slice().reverse(),20),references:ir([n.currentRequest,n.currentActivity,n.goal,n.plan,...n.decisions,...n.blockers,...n.warnings,...n.nextActions,...n.filesTouched,...n.commands??[],...n.tests,...(n.checks??[]).map(f=>f.command)])},attention:h(r.attention??[],20),progress:n.progress},{capturedAt:q,source:E,...O}=y;return{...y,stateDigest:or(O)}}function ur(r){return!!(r.currentRequest||r.currentActivity||r.goal||r.plan||r.phases.length>0||r.tasks.length>0||r.nextActions.length>0||r.blockers.length>0||r.decisions.length>0||r.filesTouched.length>0)}function dr(r,t,e,n,s){if(!ur(e))return null;let o=B(r,!1),d=[...o?o.rules.filter(c=>c.mode==="enforce").map(c=>c.text):[],...e.warnings].slice(0,20),u=Ke({project:r,identity:t,state:e,reason:n,sequence:s,attention:d}),p=u.stateDigest;return{version:1,id:S([r.id,t.sessionKey,p].join("|")).slice(0,24),projectId:r.id,projectName:r.name,createdAt:new Date().toISOString(),reason:n,sourceSession:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,sequence:s},currentRequest:e.currentRequest,currentActivity:e.currentActivity,goal:e.goal,plan:e.plan,progress:e.progress,currentPhase:e.currentPhase,currentTask:e.currentTask,incompletePhases:e.phases.filter(c=>c.status!=="completed"&&c.status!=="cancelled"),incompleteTasks:e.tasks.filter(c=>c.status!=="completed"&&c.status!=="cancelled"),nextActions:u.remaining.todos.slice(0,10),blockers:e.blockers.slice(-10),decisions:e.decisions.slice(-10),warnings:e.warnings.slice(-10),attention:d,filesTouched:e.filesTouched.slice(-20),activeFiles:e.activeFiles?.slice(-10),modifiedFiles:e.modifiedFiles?.slice(-20),createdFiles:e.createdFiles?.slice(-20),deletedFiles:e.deletedFiles?.slice(-20),tests:e.tests.slice(-15),checks:e.checks?.slice(-10),stateDigest:p,continuity:u}}function lr(r,t){let e=ee(r.rootPath,".toolnet","work","handoffs");cr(e,{recursive:!0});let n=ee(e,`${t.id}.json`);ar(n)||A(n,t),A(ee(r.rootPath,".toolnet","work","handoff-latest.json"),t)}var J=class{constructor(t){this.options=t}options;async capture(t,e){let n=$e(this.options.project);n||(n=await H(this.options.project,this.options.storage)),n||(n=await X(this.options.project,this.options.storage));let s=dr(this.options.project,this.options.identity,n,t,e);if(!s)return null;lr(this.options.project,s);let o=`projects/${this.options.project.id}/work/handoffs/${s.id}.json`;return await this.options.storage.exists(o)||await this.options.storage.put(o,JSON.stringify(s,null,2)+`
51
+ `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(s,null,2)+`
52
+ `,"application/json"),s}};async function U(r,t){let e=await t.getText(`projects/${r.id}/work/handoff-latest.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function De(r,t){let e=await t.getText(`projects/${r.id}/work/semantic/current.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}function te(r){if(!r)return 0;let t=Array.from(r).length,e=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(t/3.5,e*1.3))}function m(r,t){let e=r.replace(/\s+/g," ").trim();return e.length<=t?e:e.slice(0,Math.max(0,t-1)).trimEnd()+"\u2026"}function pr(r){let t=[],e=!1;for(let n of r.split(/\r?\n/u)){let s=n.trim();if(s.includes("<!--")&&(e=!0),e){s.includes("-->")&&(e=!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&&t.push(m(s,280)),t.length>=16))break}return t}function fr(r){let t=[],e=[];for(let n of r.split(/\\r?\\n/u)){let s=n.trim(),o=s.toLowerCase(),d=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(p=>o.startsWith(p));if(!d)continue;let u=s.slice(d.length).trim();u&&(d.includes("enforce")?t.push(u):e.push(u))}return{enforce:t,advisory:e}}function mr(r,t){let e=[];for(let n of r){let s=[...e,n].join(`
53
+ `);if(te(s)<=t){e.push(n);continue}let o=te(e.join(`
54
+ `)),a=Math.max(0,t-o);if(a>=16){let d=Math.floor(a*3.2),u=m(n,d);u&&e.push(u)}break}return e.join(`
55
+ `).trim()}async function re(r){let t=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),e=B(r.project,!1),n=e?.content??"";n||(n=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=fr(n),o=e?e.rules.filter(l=>l.mode==="enforce").map(l=>l.text):s.enforce,a=e?e.rules.filter(l=>l.mode==="advisory").map(l=>l.text):s.advisory,d=n?pr(n):[],u=await H(r.project,r.storage),p=await De(r.project,r.storage),g=await U(r.project,r.storage),c=[];if(c.push("[TOOLNET PROJECT CONTEXT]"),c.push(`Project: ${r.project.name}`),c.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),n&&c.push(`Full operating manual: ${z(r.project)}`),o.length){c.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let l of o.slice(0,24))c.push(`- [ENFORCE] ${m(l,240)}`)}if(a.length){c.push("","PROJECT PREFERENCES");for(let l of a.slice(0,10))c.push(`- ${m(l,220)}`)}if(p&&(p.mission&&c.push("","MISSION",m(p.mission.value,420)),p.activeObjective&&c.push("","CURRENT OBJECTIVE",m(p.activeObjective.value,420)),p.why&&c.push("","WHY THIS WORK MATTERS",m(p.why.value,420)),p.desiredOutcome&&c.push("","DESIRED OUTCOME",m(p.desiredOutcome.value,420)),p.planRationale&&c.push("","WHY THIS APPROACH",m(p.planRationale.value,420))),u){if(c.push("","ACTIVE WORK"),u.goal&&c.push(`Goal: ${m(u.goal,320)}`),u.plan&&c.push(`Plan: ${m(u.plan,320)}`),c.push(`Progress: phases ${u.progress.phasesCompleted}/${u.progress.phasesTotal}; tasks ${u.progress.tasksCompleted}/${u.progress.tasksTotal}; blocked ${u.progress.blocked}`),u.currentPhase&&c.push(`Current phase: ${u.currentPhase.title} [${u.currentPhase.status}]`),u.currentPhase&&p){let l=p.phases.find(y=>y.order===u.currentPhase?.order);l&&(l.objective&&c.push(`Phase objective: ${m(l.objective.value,340)}`),l.why?c.push(`Why this phase: ${m(l.why.value,340)}`):c.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),l.deliverable&&c.push(`Deliverable: ${m(l.deliverable.value,340)}`),l.dependencies.length&&c.push(`Depends on: ${l.dependencies.slice(0,4).map(y=>m(y.value,180)).join("; ")}`),l.acceptanceCriteria.length&&(c.push("","DEFINITION OF DONE"),l.acceptanceCriteria.slice(0,6).forEach(y=>{c.push(`- ${m(y.value,260)}`)})),l.openQuestions.length&&(c.push("","OPEN QUESTIONS FOR CURRENT PHASE"),l.openQuestions.slice(0,4).forEach(y=>{c.push(`- ${m(y.value,260)}`)})))}u.currentTask&&c.push(`Current task: ${u.currentTask.title} [${u.currentTask.status}]`),u.nextActions.length&&(c.push("","NEXT ACTIONS"),u.nextActions.slice(0,6).forEach((l,y)=>{c.push(`${y+1}. ${m(l,260)}`)})),u.blockers.length&&(c.push("","BLOCKERS"),u.blockers.slice(0,5).forEach(l=>{c.push(`- ${m(l,260)}`)})),u.warnings.length&&(c.push("","ATTENTION"),u.warnings.slice(-5).forEach(l=>{c.push(`- ${m(l,260)}`)})),u.decisions.length&&(c.push("","RECENT DECISIONS"),u.decisions.slice(-5).forEach(l=>{c.push(`- ${m(l,260)}`)})),u.lastSession&&c.push("",`Last work session: ${u.lastSession.agent} / ${u.lastSession.nativeSessionId}`)}if(p&&p.openQuestions.length&&(c.push("","UNRESOLVED QUESTIONS"),p.openQuestions.slice(0,5).forEach(l=>{c.push(`- ${m(l.value,260)}`)})),g&&c.push(`Latest handoff: ${g.reason} / ${g.sourceSession.agent}`),d.length){c.push("","OPERATING NOTES");for(let l of d)c.push(`- ${l}`)}c.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let x=mr(c,t);return{version:1,projectId:r.project.id,projectName:r.project.name,text:x,estimatedTokens:te(x),maxTokens:t,hasManual:!!n,hasWorkState:!!u,hasHandoff:!!g,generatedAt:new Date().toISOString()}}function C(r,t){let e=r.indexOf(t);return e>=0?r[e+1]:void 0}function gr(r){let t=de(),e=je(we({provider:t.storage.provider,huggingface:t.storage.huggingface,localRoot:t.storage.localRoot}),{attempts:3});return new V(e,r.id,r.name,r.remote??r.name)}async function hr(){let[r="help",...t]=process.argv.slice(2),e=new K().detect(C(t,"--project")??process.cwd()),n=gr(e);if(r==="brief"){let s=Number(C(t,"--tokens")??1e3),o=await re({project:e,storage:n,maxTokens:Number.isFinite(s)?s:1e3});process.stdout.write(o.text+`
56
+ `);return}if(r==="brief-json"){let s=await re({project:e,storage:n,maxTokens:Number(C(t,"--tokens")??1e3)});console.log(JSON.stringify(s,null,2));return}if(r==="handoff-latest"){let s=await U(e,n);console.log(JSON.stringify(s,null,2));return}if(r==="handoff-create"){let s=C(t,"--agent")??"manual";if(s==="manual")throw new Error("--agent must be opencode, agy, or codex");let o=C(t,"--session");if(!o)throw new Error("--session is required");let a=Ie(e,s,o),u=await new J({project:e,storage:n,identity:a}).capture("manual",0);console.log(JSON.stringify(u,null,2));return}console.log(`Work Context
57
57
 
58
58
  Commands:
59
59
  brief [--project PATH] [--tokens N]
60
60
  brief-json [--project PATH] [--tokens N]
61
61
  handoff-latest [--project PATH]
62
62
  handoff-create --agent <opencode|agy|codex> --session <id>
63
- `)}or().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
63
+ `)}hr().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
@@ -1,13 +1,13 @@
1
- import{mkdirSync as j,mkdtempSync as St,rmSync as Ct,writeFileSync as re}from"node:fs";import{tmpdir as Mt}from"node:os";import{join as k}from"node:path";import{z as N}from"zod";import{existsSync as _e,readFileSync as Pe}from"node:fs";import{join as Re}from"node:path";var Ft=new Int32Array(new SharedArrayBuffer(4));import{closeSync as Nt,existsSync as ue,fsyncSync as Ot,mkdirSync as jt,openSync as Lt,readFileSync as le,renameSync as Dt,writeFileSync as Kt}from"node:fs";import{dirname as qt,join as de}from"node:path";function fe(t){return de(t.rootPath,".toolnet","work","current.json")}function R(t){let e=fe(t);if(!ue(e))return null;try{let n=JSON.parse(le(e,"utf8"));return n.version!==1||n.projectId!==t.id?null:n}catch{return null}}import{existsSync as me,mkdirSync as Bt,readFileSync as pe,renameSync as Ut,writeFileSync as Qt}from"node:fs";import{dirname as Yt,join as ge}from"node:path";function ke(t){return ge(t.rootPath,".toolnet","context","session-origin.json")}function $(t){let e=ke(t);if(!me(e))return null;try{let n=JSON.parse(pe(e,"utf8"));return n.version!==1||n.projectId!==t.id?null:n}catch{return null}}function ye(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function M(t){let e=ye(t),n=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),r=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return n&&r?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}import{existsSync as Ae,mkdirSync as Un,readFileSync as Te}from"node:fs";import{join as D}from"node:path";var be=[{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}],w=class{scan(e){let n=[];for(let r of be){let o=new RegExp(r.regex.source,r.regex.flags);for(let s of e.matchAll(o))n.push({type:r.type,value:s[0]})}return n}hasSecrets(e){return this.scan(e).length>0}};var A=class{scanner=new w;sanitize(e){let n=e,r=this.scanner.scan(e),o=new Set;for(let s of r)o.add(s.type),n=n.split(s.value).join(`[REDACTED:${s.type}]`);return{text:n,redacted:r.length,secretTypes:[...o]}}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,o]of Object.entries(e)){let s=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")?n[r]="[REDACTED]":n[r]=this.sanitizeValue(o)}return n}return e}};import{existsSync as ve,readFileSync as xe}from"node:fs";import{homedir as Se}from"node:os";import{join as Ce}from"node:path";function Me(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 we(){let t=process.env.TOOLNET_GLOBAL_ENV??Ce(Se(),".config","toolnet-memory",".env");if(!ve(t))return;let e=xe(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 o=r.indexOf("=");if(o<=0)continue;let s=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Me(r.slice(o+1)))}}we();var Pn=new A;function Ee(t){return D(t.rootPath,".toolnet","memory","checkpoints")}function Ie(t){return D(Ee(t),"latest.json")}function Fe(t){let e=Ie(t);if(!Ae(e))return null;try{let n=JSON.parse(Te(e,"utf8"));return n.schema!=="toolnet.memory.checkpoint.v1"||n.project.id!==t.id?null:n}catch{return null}}function K(t){return Fe(t)}var $e={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,request:95,activity:90,phase:75,file:65,next_action:55,blocker:45},next_action:{next_action:100,todo:80,task:65,blocker:60,file:40},last_file:{file:100,task:65,next_action:40},blocker:{blocker:100,task:60,next_action:50,file:35},decision:{decision:100,rule:85,architecture:80,task:45,file:30},completed:{completed:100,progress:70,task:30},status:{progress:100,task:85,phase:75,blocker:65,next_action:60},summary:{task:100,request:98,activity:96,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,rule:54,architecture:53,fix:52,progress:50,test:45,goal:35}},Ne={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function Oe(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function i(t,e){let n=e.value.replace(/\s+/g," ").trim();n&&t.push({...e,value:n,score:0})}function je(t){let e=Re(t.rootPath,".toolnet","work","handoff-latest.json");if(!_e(e))return null;try{let r=JSON.parse(Pe(e,"utf8")).continuity;return r?.schema!=="toolnet.handoff.v2"||r.project.id!==t.id?null:r}catch{return null}}function Le(t){let e=K(t);if(!e)return[];let n=[];e.request&&i(n,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&i(n,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&i(n,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&i(n,{kind:"task",value:e.current.task.title,source:"checkpoint"});let r=e.files.active.at(-1);r&&i(n,{kind:"file",value:r,source:"checkpoint"});for(let o of e.nextActions)i(n,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)i(n,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)i(n,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)i(n,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)i(n,{kind:o.kind,value:o.content,source:"checkpoint"});return n}function De(t){let e=je(t);if(!e)return[];let n=[];i(n,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&i(n,{kind:"request",value:e.request,source:"handoff"}),e.activity&&i(n,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&i(n,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&i(n,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&i(n,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&i(n,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&i(n,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let r of e.blockers)i(n,{kind:"blocker",value:r,source:"handoff"});for(let r of e.decisions)i(n,{kind:"decision",value:r,source:"handoff"});for(let r of e.completed.tasks)i(n,{kind:"completed",value:r,source:"handoff"});for(let r of e.remaining.todos)i(n,{kind:"todo",value:r,source:"handoff"});return i(n,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),i(n,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),n}function Ke(t){let e=$(t);if(!e)return[];let n=[];return i(n,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&i(n,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&i(n,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&i(n,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&i(n,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&i(n,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&i(n,{kind:"decision",value:e.latestDecision,source:"session-origin"}),n}function He(t){let e=R(t);if(!e)return[];let n=[];e.currentRequest&&i(n,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&i(n,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&i(n,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&i(n,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&i(n,{kind:"task",value:e.currentTask.title,source:"work-state"});let r=e.activeFiles?.at(-1)??e.filesTouched.at(-1);r&&i(n,{kind:"file",value:r,source:"work-state"});for(let o of e.nextActions.slice(0,5))i(n,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))i(n,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))i(n,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(s=>s.status==="completed").slice(-8))i(n,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(s=>s.status!=="completed"&&s.status!=="cancelled").slice(0,8))i(n,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))i(n,{kind:"test",value:o,source:"work-state"});return i(n,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),n}function qe(t,e){let n=$e[t];return e.map((r,o)=>({...r,score:(n[r.kind]??10)+Ne[r.source]+Math.max(0,5-o*.01)}))}function We(t){let e=new Map;for(let n of t){let r=`${n.kind}:${Oe(n.value)}`,o=e.get(r);(!o||n.score>o.score)&&e.set(r,n)}return[...e.values()]}function h(t,e,n={}){let r=M(e),o=[...Le(t),...De(t),...Ke(t),...He(t)],s=We(qe(r,o)).sort((d,p)=>p.score-d.score),c=Math.max(1,n.maxFacts??12),l=Math.max(300,n.maxChars??3200),f=[],a=0;for(let d of s){if(f.length>=c)break;let p=d.kind.length+d.value.length+d.source.length+16;f.length>0&&a+p>l||(f.push(d),a+=p)}return{intent:r,facts:f,context:{project:{id:t.id,name:t.name},intent:r,selectedFacts:f.map(d=>({kind:d.kind,value:d.value,source:d.source}))},stats:{candidates:o.length,selected:f.length,chars:a}}}var H={previous_agent:"Agent tr\u01B0\u1EDBc",request:"Y\xEAu c\u1EA7u hi\u1EC7n t\u1EA1i",activity:"\u0110ang l\xE0m",goal:"M\u1EE5c ti\xEAu",phase:"Phase",task:"Task hi\u1EC7n t\u1EA1i",file:"File hi\u1EC7n t\u1EA1i",todo:"TODO",next_action:"Ti\u1EBFp theo",blocker:"Blocker",decision:"Quy\u1EBFt \u0111\u1ECBnh",rule:"Quy t\u1EAFc",architecture:"Ki\u1EBFn tr\xFAc",fix:"\u0110\xE3 s\u1EEDa",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},q=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],ze={previous_agent:["previous_agent"],current_task:["request","activity","task","file","next_action"],next_action:["next_action","task","file","todo"],last_file:["file","task","next_action"],blocker:["blocker"],decision:["decision"],completed:["completed"],status:["progress","task","next_action","blocker"],summary:q};function Be(t){let e=t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)}function Ue(t){let e=t.filter(r=>r.source==="handoff");if(e.length===0)return t;let n=t.filter(r=>r.source==="checkpoint"&&["rule","architecture","fix"].includes(r.kind));return[...e,...n]}function Qe(t){let e=new Set,n=[];for(let r of t){let o=`${r.kind}:${r.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),n.push(r))}return n}function W(t){switch(t){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function Ve(t,e){let n=[];for(let r of e){let o=t.filter(s=>s.kind===r).slice(0,W(r));for(let s of o)n.push(`${H[r]}: ${s.value}`)}return n.join(`
3
- `)}function Ye(t,e){let n=ze[e]??q,r=[];for(let o of n){let s=t.filter(c=>c.kind===o).slice(0,W(o));for(let c of s)r.push(`${H[o]}: ${c.value}`)}return r.join(`
4
- `)}function z(t,e){let n=h(t,e,{maxFacts:32,maxChars:6400}),r=Qe(Ue(n.facts)),o=Be(e)?Ve(r,["todo","task","next_action","file"]):Ye(r,String(n.intent));return o?{intent:String(n.intent),answer:o,source:r[0]?.source??"none"}:{intent:String(n.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}import{existsSync as Je,mkdirSync as Xe,readFileSync as Ge,renameSync as Ze,rmSync as et,writeFileSync as tt}from"node:fs";import{join as B}from"node:path";var nt=720*60*1e3;function U(t){return B(t.rootPath,".toolnet","context","memory-agent-conversation.json")}function C(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function rt(t){let e=C(t);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(n=>n.test(e))}function ot(t){if(rt(t))return!1;let e=C(t),n=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(r=>r.test(e))?!0:n.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function st(t,e,n){let r=U(t);if(!Je(r))return null;try{let o=JSON.parse(Ge(r,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==t.id||!Array.isArray(o.focus))return null;let s=Date.parse(o.updatedAt);return!Number.isFinite(s)||e-s>n?null:o}catch{return null}}function it(t,e=8){let n=new Set,r=[];for(let o of t){let s=o.value.replace(/\s+/gu," ").trim();if(!s)continue;let c=[o.kind,C(s)].join(":");if(!n.has(c)&&(n.add(c),r.push({...o,value:s}),r.length>=e))break}return r}function ct(t,e){let n=U(t),r=B(t.rootPath,".toolnet","context");Xe(r,{recursive:!0,mode:448});let o=`${n}.${process.pid}.tmp`;try{tt(o,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),Ze(o,n)}finally{et(o,{force:!0})}}function at(t){return t.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
6
- `)}function ut(t,e){return t.priorFocus.find(n=>n.kind===e)?.value}function Q(t){if(!t.usedPriorFocus||t.currentIntent!=="summary"||t.priorFocus.length===0)return null;let e=C(t.originalQuestion),n=/^(?:tại sao|vì sao|sao vậy|why|why so|why that)\b/u.test(e),r=/^(?:rồi sao|sau đó|tiếp thì sao|thế tiếp theo|then what|what next)\b/u.test(e),o=n?["decision","blocker","next_action","task","file"]:r?["next_action","todo","task","blocker","file","decision"]:["task","next_action","file","decision","blocker"],s={task:"Task li\xEAn quan",next_action:"Vi\u1EC7c ti\u1EBFp theo",file:"File li\xEAn quan",decision:"Quy\u1EBFt \u0111\u1ECBnh li\xEAn quan",blocker:"Blocker",todo:"TODO"},c=[];for(let l of o){let f=ut(t,l);if(f&&(c.push(`${s[l]??l}: ${f}.`),n&&c.length>=2||!n&&c.length>=3))break}return c.length===0?null:{answer:c.join(" "),intent:"summary",source:"conversation-focus"}}function lt(t){let e=C(t);return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function V(t,e,n={}){let r=n.now??Date.now(),o=n.maxAgeMs??nt,s=st(t,r,o),c=!!(s&&s.focus.length>0&&ot(e)&&!lt(e)),l=c&&s?[e.trim(),"","Previous ToolNet Memory conversation focus:",at(s),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
7
- `):e.trim(),f=M(e),d=h(t,l,{maxFacts:8,maxChars:1800}).facts.map(y=>({kind:y.kind,value:y.value,source:y.source})),p=it(c&&s?[...d,...s.focus]:d);return ct(t,{schema:"toolnet.memory-conversation.v1",version:1,projectId:t.id,updatedAt:new Date(r).toISOString(),lastIntent:f,focus:p}),{question:l,originalQuestion:e,usedPriorFocus:c,previousIntent:s?.lastIntent,currentIntent:f,priorFocus:s?.focus??[],focusCount:p.length}}import{existsSync as dt,readFileSync as ft}from"node:fs";import{join as mt}from"node:path";function g(t){return!!t?.trim()}function Y(t){let e=[],n=[],r=100;g(t.goal)||g(t.request)||(e.push("goal_or_request"),r-=20),g(t.activity)||g(t.current.task?.title)||g(t.current.phase?.title)||(e.push("current_work"),r-=25),g(t.nextAction)||g(t.remaining.todos[0])||(e.push("next_action"),r-=25),t.tests.status!=="unknown"||t.tests.recent.length>0||(t.tests.checks?.length??0)>0||(t.evidence?.commands.length??0)>0||(t.evidence?.references.length??0)>0||(e.push("evidence"),r-=20),g(t.files.current)||t.files.recent.length>0||(t.files.active?.length??0)>0||(t.files.modified?.length??0)>0||(t.files.created?.length??0)>0||(e.push("files"),r-=10),t.tests.status==="failing"&&n.push("tests_failing"),t.blockers.length>0&&n.push("active_blockers"),r=Math.max(0,Math.min(100,r));let a=e.includes("current_work")||e.includes("next_action"),d;return r>=80&&!a?d="high":r>=50?d="medium":d="low",{confidence:d,score:r,missingContext:e,warnings:n}}var J={compact:{completed:3,evidence:3,files:5,blockers:2,maxChars:1800},normal:{completed:10,evidence:10,files:15,blockers:5,maxChars:4200},benchmark:{completed:30,evidence:30,files:40,blockers:10,maxChars:1e4}};function b(t){let e=new Set,n=[];for(let r of t){let o=r?.replace(/\s+/gu," ").trim();if(!o)continue;let s=o.normalize("NFKC").toLowerCase();e.has(s)||(e.add(s),n.push(o))}return n}function v(t){return t.length>0?t.map(e=>`- ${e}`).join(`
8
- `):"- none"}function pt(t,e){return t.length<=e?t:[t.slice(0,e).trimEnd(),"","[Structured handoff truncated]"].join(`
9
- `)}function X(t,e){if(e)return e;let n=t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/\bbenchmark\b/u.test(n)||/\bdeep handoff\b/u.test(n)||/\bfull handoff\b/u.test(n)||/\btakeover\b/u.test(n)||/\btake over\b/u.test(n)||/tiếp quản/u.test(n)||/bằng chứng đầy đủ/u.test(n)||/evidence.*(?:file|test|command)/u.test(n)?"benchmark":/\bcompact\b/u.test(n)||/\bbrief\b/u.test(n)||/ngắn gọn/u.test(n)||/tóm tắt ngắn/u.test(n)?"compact":"normal"}function gt(t,e="normal"){let n=J[e],r=b([`Source agent: ${t.source.agent}`,`Captured: ${t.capturedAt}`,t.goal?`Goal: ${t.goal}`:void 0,t.request?`Request: ${t.request}`:void 0,t.activity?`Activity: ${t.activity}`:void 0,t.current.phase?`Phase: ${t.current.phase.title} [${t.current.phase.status}]`:void 0,t.current.task?`Task: ${t.current.task.title} [${t.current.task.status}]`:void 0,t.current.file?`Current file: ${t.current.file}`:void 0,`Progress: ${JSON.stringify(t.progress)}`]),o=b([...t.completed.phases.map(a=>`Phase: ${a}`),...t.completed.tasks.map(a=>`Task: ${a}`)]).slice(0,n.completed),s=b([`Tests status: ${t.tests.status}`,...t.tests.recent.map(a=>`Test: ${a}`),...(t.tests.checks??[]).map(a=>`Check [${a.status}] ${a.kind}: ${a.command}`),...(t.evidence?.commands??[]).map(a=>`Command: ${a}`),...(t.evidence?.references??[]).map(a=>`Reference: ${a}`),...t.decisions.map(a=>`Decision: ${a}`),...t.attention.map(a=>`Attention: ${a}`)]).slice(0,n.evidence),c=b([t.files.current,...(t.files.active??[]).map(a=>`Active: ${a}`),...(t.files.modified??[]).map(a=>`Modified: ${a}`),...(t.files.created??[]).map(a=>`Created: ${a}`),...(t.files.deleted??[]).map(a=>`Deleted: ${a}`),...t.files.recent.map(a=>`Recent: ${a}`)]).slice(0,n.files),l=b(t.blockers).slice(0,n.blockers),f=b([t.nextAction,t.nextAction?void 0:t.remaining.todos[0]]).slice(0,1);return{currentState:r,completed:o,evidence:s,filesTouched:c,blockers:l,nextAction:f}}function kt(t,e,n){return[`HANDOFF_DETAIL: ${e}`,`CONTINUITY_CONFIDENCE: ${n.confidence}`,`QUALITY_SCORE: ${n.score}`,`MISSING_CONTEXT: ${n.missingContext.length>0?n.missingContext.join(", "):"none"}`,`QUALITY_WARNINGS: ${n.warnings.length>0?n.warnings.join(", "):"none"}`,"","CURRENT_STATE",v(t.currentState),"","COMPLETED",v(t.completed),"","EVIDENCE",v(t.evidence),"","FILES_TOUCHED",v(t.filesTouched),"","BLOCKERS",v(t.blockers),"","NEXT_ACTION",v(t.nextAction)].join(`
10
- `)}function G(t,e="normal"){let n=mt(t.rootPath,".toolnet","work","handoff-latest.json");if(!dt(n))return null;try{let o=JSON.parse(ft(n,"utf8")).continuity;if(!o||o.schema!=="toolnet.handoff.v2"||o.version!==2)return null;let s=gt(o,e),c=Y(o),l=pt(kt(s,e,c),J[e].maxChars);return{detail:e,data:s,quality:c,text:l}}catch{return null}}function yt(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}var ht=[/\bhandoff\b/u,/\bcontinuity\b/u,/\bcontinue\b/u,/\bresume\b/u,/\btakeover\b/u,/\btake over\b/u,/tiếp tục/u,/tiếp quản/u,/bàn giao/u,/dừng ở đâu/u,/đang làm gì/u],bt=[/\bcurrent state\b/u,/\bcurrent task\b/u,/\bevidence\b/u,/\breport locations?\b/u,/\bfiles?\b/u,/\burls?\b/u,/\bassets?\b/u,/\btests?\b/u,/\bcommands?\b/u,/\bblockers?\b/u,/\bnext actions?\b/u,/trạng thái hiện tại/u,/task hiện tại/u,/bằng chứng/u,/vị trí báo cáo/u,/file/u,/url/u,/blocker/u,/việc tiếp theo/u,/bước tiếp theo/u],vt=[/\bsummarize\b/u,/\bsummary\b/u,/\bfull state\b/u,/\bfull context\b/u,/tóm tắt/u,/đầy đủ/u,/toàn bộ trạng thái/u];function xt(t){let e=0;for(let n of bt)n.test(t)&&(e+=1);return e}function Z(t,e){let n=yt(t);if(/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(n)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(n)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(n))return!1;if(e==="summary"||e==="status")return!0;if(!n)return!1;let o=ht.some(l=>l.test(n)),s=vt.some(l=>l.test(n)),c=xt(n);return!!(o&&c>=1||s&&c>=2||c>=4)}var Sr={question:N.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:N.enum(["local"]).optional().describe("Returns deterministic local memory only. No external AI is used."),detail:N.enum(["compact","normal","benchmark"]).optional().describe("Handoff detail level. compact=minimal, normal=standard, benchmark=deep evidence/files/tests for agent takeover.")};function ee(t,e,n,r,o){if(!Z(e,n))return{answer:r};let s=X(e,o),c=G(t.project,s);return c?{answer:c.text,handoff:c.data,detail:c.detail,confidence:c.quality.confidence,missingContext:c.quality.missingContext,quality:c.quality}:{answer:r}}async function O(t,e){let n=V(t.project,e.question),r=Q(n);if(r)return{...ee(t,n.originalQuestion,String(r.intent),r.answer,e.detail),mode:"local",usedAi:!1,source:r.source,intent:r.intent};let o=z(t.project,n.originalQuestion),s=ee(t,n.originalQuestion,String(o.intent),o.answer,e.detail);return"handoff"in s?{...s,mode:"local",usedAi:!1,source:o.source,intent:o.intent,routing:"deterministic-handoff"}:{...s,mode:"local",usedAi:!1,source:o.source,intent:o.intent}}var te="RAW_TRANSCRIPT_MUST_NEVER_ENTER_CONTINUITY_CONTEXT_X1";function ne(t,e){re(t,JSON.stringify(e,null,2)+`
11
- `,"utf8")}function wt(t,e,n,r,o,s,c,l){return{continuity:{schema:"toolnet.handoff.v2",version:2,project:{id:t,name:e},source:{agent:n,nativeSessionId:`${n}-x1-source`,sessionKey:`${n}:${n}-x1-source`,sequence:42,reason:"checkpoint"},capturedAt:"2026-08-13T05:30:00.000Z",goal:`Continue ${e} safely across agents`,request:`Recover ${o} with exact evidence and next action`,activity:`Preparing ${r} takeover from ${n}`,current:{phase:{id:"x1",title:"Cross-Agent Continuity E2E",status:"in_progress"},task:{id:"x1-cross-agent",title:o,status:"in_progress"},file:s},completed:{phases:["A1 OpenCode Adapter","A2 Agy Adapter","A3 Claude Code Adapter"],tasks:["Build canonical handoff schema","Build intelligent memory retrieval"]},remaining:{phases:["X1 Cross-Agent Continuity E2E"],tasks:[o],todos:[c]},nextAction:l,blockers:[],decisions:["Canonical handoff must override stale session state","Never replay raw transcripts during continuity recovery"],files:{current:s,recent:[s]},tests:{status:"passing",recent:["A1-A3 adapter tests passed"],checks:[{kind:"test",status:"passed",command:`node scripts/${n}-to-${r}-verify.mjs`}]},evidence:{commands:[`node scripts/${n}-to-${r}-verify.mjs`],references:[`https://example.test/${n}/${r}/continuity-report`]},attention:[],progress:{phasesTotal:3,phasesCompleted:2,tasksTotal:4,tasksCompleted:3,blocked:0},stateDigest:"a".repeat(64)}}}async function T(t,e){return O({project:t},{question:e,mode:"local"})}async function At(t,e){let n=St(k(Mt(),`toolnet-x1-${t}-${e}-`));try{let r=`x1-${t}-${e}`,o=`x1-${t}-to-${e}`,s={id:r,name:o,rootPath:n,createdAt:"2026-08-13T05:30:00.000Z",updatedAt:"2026-08-13T05:30:00.000Z",graphVersion:1,memoryVersion:1},c=k(n,".toolnet","work"),l=k(n,".toolnet","context"),f=k(n,".toolnet","runtime","sources",t,"raw-session-x1");j(c,{recursive:!0}),j(l,{recursive:!0}),j(f,{recursive:!0});let a=`X1 ${t} to ${e} canonical continuity`,d=`src/x1/${t}-to-${e}.ts`,p=`Implement ${e} continuation step`,y=`Continue ${a} in ${d}`;ne(k(c,"handoff-latest.json"),wt(r,o,t,e,a,d,p,y)),ne(k(l,"session-origin.json"),{version:1,projectId:r,agent:"stale-agent",nativeSessionId:"stale-session",updatedAt:"2026-01-01T00:00:00.000Z",currentTask:"STALE TASK MUST NOT WIN",currentPhase:"STALE PHASE",lastTouchedFile:"src/stale/old.ts",latestNextAction:"STALE NEXT ACTION"}),re(k(f,"events.jsonl"),JSON.stringify({text:te})+`
12
- `,"utf8");let se=h(s,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?",{maxFacts:12,maxChars:3200}),E=await T(s,"Task hi\u1EC7n t\u1EA1i \u0111ang l\xE0m l\xE0 g\xEC?"),I=await T(s,"File hi\u1EC7n t\u1EA1i l\xE0 file n\xE0o?"),F=await T(s,"TODO c\xF2n l\u1EA1i l\xE0 g\xEC?"),_=await T(s,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?"),m=await O({project:s},{mode:"local",detail:"benchmark",question:"Summarize current state, completed work, evidence, files, tests, blockers and exact next action for benchmark agent takeover."}),x=m,ie=`node scripts/${t}-to-${e}-verify.mjs`,ce=`https://example.test/${t}/${e}/continuity-report`,ae=[E.answer,I.answer,F.answer,_.answer,m.answer].join(`
13
- `),P=[E,I,F,_],L={canonicalHandoffPreferred:se.facts[0]?.source==="handoff",taskRecovered:E.answer.includes(a),fileRecovered:I.answer.includes(d),todoRecovered:F.answer.includes(p),nextActionRecovered:_.answer.includes(y),localModeOnly:P.every(S=>S.mode==="local"),noAiRequired:P.every(S=>S.usedAi===!1),rawTranscriptIsolated:!ae.includes(te),compact:P.every(S=>S.answer.length<1600),structuredTakeoverRecovered:m.answer.includes("CURRENT_STATE")&&m.answer.includes("COMPLETED")&&m.answer.includes("EVIDENCE")&&m.answer.includes("FILES_TOUCHED")&&m.answer.includes("BLOCKERS")&&m.answer.includes("NEXT_ACTION"),benchmarkDetailRecovered:x.detail==="benchmark"&&m.answer.includes("HANDOFF_DETAIL: benchmark"),highConfidence:x.confidence==="high"&&Array.isArray(x.missingContext)&&x.missingContext.length===0,evidenceRecovered:m.answer.includes(ie)&&m.answer.includes(ce),deterministicTakeover:m.usedAi===!1&&x.routing==="deterministic-handoff"};return{from:t,to:e,passed:Object.values(L).every(Boolean),checks:L}}finally{Ct(n,{recursive:!0,force:!0})}}async function oe(){let t=[["agy","codex"],["codex","opencode"],["opencode","claude"],["claude","kiro"],["kiro","cursor"],["cursor","copilot"],["copilot","grok"],["grok","toolnet-cli"],["toolnet-cli","kilo"],["kilo","agy"]],e=[];for(let[r,o]of t)e.push(await At(r,o));let n=e.filter(r=>r.passed).length;return{passed:n===e.length,total:e.length,passedCount:n,cases:e}}var u={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",cyan:"\x1B[36m",gray:"\x1B[90m",white:"\x1B[97m"};function Tt(t){return t?`${u.green}\u2713${u.reset}`:`${u.red}\u2717${u.reset}`}function Et(t){let e=`${t.from.padEnd(8)} \u2192 ${t.to.padEnd(8)}`;if(console.log(`\u2502 ${Tt(t.passed)} ${e}`),!t.passed)for(let[n,r]of Object.entries(t.checks))r||console.log(`\u2502 ${u.red}\u2717${u.reset} ${n}`)}async function It(){console.log(""),console.log(`${u.cyan}\u25C7${u.reset} ${u.white}ToolNet Cross-Agent Continuity Certification${u.reset}`),console.log(`${u.gray}\u2502${u.reset}`);let t=await oe();for(let e of t.cases)Et(e);if(console.log(`${u.gray}\u2502${u.reset}`),t.passed){console.log(`${u.green}\u25C6 PASS${u.reset} ${t.passedCount}/${t.total} cross-agent transitions`),console.log(`${u.green}\u2713${u.reset} canonical handoff`),console.log(`${u.green}\u2713${u.reset} memory_agent_ask`),console.log(`${u.green}\u2713${u.reset} task / file / TODO / next action`),console.log(`${u.green}\u2713${u.reset} raw transcripts isolated`),console.log(`${u.green}\u2713${u.reset} AI not required for direct continuity`);return}console.log(`${u.red}\u25C6 FAIL${u.reset} ${t.passedCount}/${t.total} cross-agent transitions`),process.exitCode=1}It().catch(t=>{console.error(t instanceof Error?t.message:String(t)),process.exitCode=1});
1
+ import{mkdirSync as L,mkdtempSync as _t,rmSync as It,writeFileSync as se}from"node:fs";import{tmpdir as Ft}from"node:os";import{join as y}from"node:path";import{z as N}from"zod";import{existsSync as je,readFileSync as De}from"node:fs";import{join as Ke}from"node:path";var Lt=new Int32Array(new SharedArrayBuffer(4));import{closeSync as Yt,existsSync as ke,fsyncSync as Jt,mkdirSync as Zt,openSync as Xt,readFileSync as he,renameSync as Gt,writeFileSync as en}from"node:fs";import{dirname as nn,join as be}from"node:path";var de=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],fe=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function D(t){return t.normalize("NFKC").trim().toLowerCase()}function me(t){if(t.length===0)return 0;let e=new Map;for(let r of t)e.set(r,(e.get(r)??0)+1);let n=0;for(let r of e.values()){let o=r/t.length;n-=o*Math.log2(o)}return n}function pe(t){return/^[a-f0-9]{32}$/iu.test(t)||/^[a-f0-9]{40}$/iu.test(t)||/^[a-f0-9]{64}$/iu.test(t)}function ge(t,e,n){let r=t.slice(Math.max(0,e-48),e),o=t.slice(n,Math.min(t.length,n+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${o}`)}function ye(t,e){return t.start<e.end&&e.start<t.end}function K(t){return t.sort((e,n)=>e.start!==n.start?e.start-n.start:n.end-n.start-(e.end-e.start))}var w=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let n of e.allowValues??[]){let r=D(n);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let n=[];for(let s of de){let i=new RegExp(s.regex.source,s.regex.flags);for(let u of e.matchAll(i))u.index===void 0||!u[0]||this.allowed(u[0])||n.push({type:s.type,value:u[0],start:u.index,end:u.index+u[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&n.push(...this.entropyMatches(e));let r=K(n),o=[];for(let s of r)o.some(i=>ye(i,s))||o.push(s);return K(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let n=D(e);return fe.has(n)?!0:this.allowValues.has(n)}entropyMatches(e){let n=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(r)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||pe(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||ge(e,o.index,o.index+s.length)&&(me(s)<3.7||n.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return n}};var h=class{scanner;constructor(e={}){this.scanner=new w(e)}sanitize(e){let n=this.scanner.scan(e);if(n.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,o=[...n].sort((i,u)=>u.start-i.start),s=new Set;for(let i of o)s.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:n.length,secretTypes:[...s].sort()}}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,o]of Object.entries(e)){let s=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){n[r]="[REDACTED]";continue}n[r]=this.sanitizeValue(o)}return n}return e}};var qt=new h;function xe(t){return be(t.rootPath,".toolnet","work","current.json")}function R(t){let e=xe(t);if(!ke(e))return null;try{let n=JSON.parse(he(e,"utf8"));return n.version!==1||n.projectId!==t.id?null:n}catch{return null}}import{existsSync as Se,mkdirSync as cn,readFileSync as ve,renameSync as an,writeFileSync as un}from"node:fs";import{dirname as dn,join as Me}from"node:path";function Ce(t){return Me(t.rootPath,".toolnet","context","session-origin.json")}function $(t){let e=Ce(t);if(!Se(e))return null;try{let n=JSON.parse(ve(e,"utf8"));return n.version!==1||n.projectId!==t.id?null:n}catch{return null}}function we(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function A(t){let e=we(t),n=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),r=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return n&&r?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}import{existsSync as Re,mkdirSync as or,readFileSync as $e}from"node:fs";import{join as z}from"node:path";import{existsSync as Te,readFileSync as Ee}from"node:fs";import{homedir as _e}from"node:os";import{join as Ie}from"node:path";function Fe(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 Pe(){let t=process.env.TOOLNET_GLOBAL_ENV??Ie(_e(),".config","toolnet-memory",".env");if(!Te(t))return;let e=Ee(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 o=r.indexOf("=");if(o<=0)continue;let s=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Fe(r.slice(o+1)))}}Pe();var Wn=new h;function Ne(t){return z(t.rootPath,".toolnet","memory","checkpoints")}function Oe(t){return z(Ne(t),"latest.json")}function Le(t){let e=Oe(t);if(!Re(e))return null;try{let n=JSON.parse($e(e,"utf8"));return n.schema!=="toolnet.memory.checkpoint.v1"||n.project.id!==t.id?null:n}catch{return null}}function H(t){return Le(t)}var ze={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,request:95,activity:90,phase:75,file:65,next_action:55,blocker:45},next_action:{next_action:100,todo:80,task:65,blocker:60,file:40},last_file:{file:100,task:65,next_action:40},blocker:{blocker:100,task:60,next_action:50,file:35},decision:{decision:100,rule:85,architecture:80,task:45,file:30},completed:{completed:100,progress:70,task:30},status:{progress:100,task:85,phase:75,blocker:65,next_action:60},summary:{task:100,request:98,activity:96,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,rule:54,architecture:53,fix:52,progress:50,test:45,goal:35}},He={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function qe(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function c(t,e){let n=e.value.replace(/\s+/g," ").trim();n&&t.push({...e,value:n,score:0})}function We(t){let e=Ke(t.rootPath,".toolnet","work","handoff-latest.json");if(!je(e))return null;try{let r=JSON.parse(De(e,"utf8")).continuity;return r?.schema!=="toolnet.handoff.v2"||r.project.id!==t.id?null:r}catch{return null}}function Be(t){let e=H(t);if(!e)return[];let n=[];e.request&&c(n,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&c(n,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&c(n,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&c(n,{kind:"task",value:e.current.task.title,source:"checkpoint"});let r=e.files.active.at(-1);r&&c(n,{kind:"file",value:r,source:"checkpoint"});for(let o of e.nextActions)c(n,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)c(n,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)c(n,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)c(n,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)c(n,{kind:o.kind,value:o.content,source:"checkpoint"});return n}function Ve(t){let e=We(t);if(!e)return[];let n=[];c(n,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&c(n,{kind:"request",value:e.request,source:"handoff"}),e.activity&&c(n,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&c(n,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&c(n,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&c(n,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&c(n,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&c(n,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let r of e.blockers)c(n,{kind:"blocker",value:r,source:"handoff"});for(let r of e.decisions)c(n,{kind:"decision",value:r,source:"handoff"});for(let r of e.completed.tasks)c(n,{kind:"completed",value:r,source:"handoff"});for(let r of e.remaining.todos)c(n,{kind:"todo",value:r,source:"handoff"});return c(n,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),c(n,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),n}function Ue(t){let e=$(t);if(!e)return[];let n=[];return c(n,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&c(n,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&c(n,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&c(n,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&c(n,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&c(n,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&c(n,{kind:"decision",value:e.latestDecision,source:"session-origin"}),n}function Qe(t){let e=R(t);if(!e)return[];let n=[];e.currentRequest&&c(n,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&c(n,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&c(n,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&c(n,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&c(n,{kind:"task",value:e.currentTask.title,source:"work-state"});let r=e.activeFiles?.at(-1)??e.filesTouched.at(-1);r&&c(n,{kind:"file",value:r,source:"work-state"});for(let o of e.nextActions.slice(0,5))c(n,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))c(n,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))c(n,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(s=>s.status==="completed").slice(-8))c(n,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(s=>s.status!=="completed"&&s.status!=="cancelled").slice(0,8))c(n,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))c(n,{kind:"test",value:o,source:"work-state"});return c(n,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),n}function Ye(t,e){let n=ze[t];return e.map((r,o)=>({...r,score:(n[r.kind]??10)+He[r.source]+Math.max(0,5-o*.01)}))}function Je(t){let e=new Map;for(let n of t){let r=`${n.kind}:${qe(n.value)}`,o=e.get(r);(!o||n.score>o.score)&&e.set(r,n)}return[...e.values()]}function b(t,e,n={}){let r=A(e),o=[...Be(t),...Ve(t),...Ue(t),...Qe(t)],s=Je(Ye(r,o)).sort((d,p)=>p.score-d.score),i=Math.max(1,n.maxFacts??12),u=Math.max(300,n.maxChars??3200),f=[],a=0;for(let d of s){if(f.length>=i)break;let p=d.kind.length+d.value.length+d.source.length+16;f.length>0&&a+p>u||(f.push(d),a+=p)}return{intent:r,facts:f,context:{project:{id:t.id,name:t.name},intent:r,selectedFacts:f.map(d=>({kind:d.kind,value:d.value,source:d.source}))},stats:{candidates:o.length,selected:f.length,chars:a}}}var q={previous_agent:"Agent tr\u01B0\u1EDBc",request:"Y\xEAu c\u1EA7u hi\u1EC7n t\u1EA1i",activity:"\u0110ang l\xE0m",goal:"M\u1EE5c ti\xEAu",phase:"Phase",task:"Task hi\u1EC7n t\u1EA1i",file:"File hi\u1EC7n t\u1EA1i",todo:"TODO",next_action:"Ti\u1EBFp theo",blocker:"Blocker",decision:"Quy\u1EBFt \u0111\u1ECBnh",rule:"Quy t\u1EAFc",architecture:"Ki\u1EBFn tr\xFAc",fix:"\u0110\xE3 s\u1EEDa",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},W=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],Ze={previous_agent:["previous_agent"],current_task:["request","activity","task","file","next_action"],next_action:["next_action","task","file","todo"],last_file:["file","task","next_action"],blocker:["blocker"],decision:["decision"],completed:["completed"],status:["progress","task","next_action","blocker"],summary:W};function Xe(t){let e=t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)}function Ge(t){let e=t.filter(r=>r.source==="handoff");if(e.length===0)return t;let n=t.filter(r=>r.source==="checkpoint"&&["rule","architecture","fix"].includes(r.kind));return[...e,...n]}function et(t){let e=new Set,n=[];for(let r of t){let o=`${r.kind}:${r.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),n.push(r))}return n}function B(t){switch(t){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function tt(t,e){let n=[];for(let r of e){let o=t.filter(s=>s.kind===r).slice(0,B(r));for(let s of o)n.push(`${q[r]}: ${s.value}`)}return n.join(`
3
+ `)}function nt(t,e){let n=Ze[e]??W,r=[];for(let o of n){let s=t.filter(i=>i.kind===o).slice(0,B(o));for(let i of s)r.push(`${q[o]}: ${i.value}`)}return r.join(`
4
+ `)}function V(t,e){let n=b(t,e,{maxFacts:32,maxChars:6400}),r=et(Ge(n.facts)),o=Xe(e)?tt(r,["todo","task","next_action","file"]):nt(r,String(n.intent));return o?{intent:String(n.intent),answer:o,source:r[0]?.source??"none"}:{intent:String(n.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}import{existsSync as rt,mkdirSync as ot,readFileSync as st,renameSync as it,rmSync as ct,writeFileSync as at}from"node:fs";import{join as U}from"node:path";var ut=720*60*1e3;function Q(t){return U(t.rootPath,".toolnet","context","memory-agent-conversation.json")}function C(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function lt(t){let e=C(t);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(n=>n.test(e))}function dt(t){if(lt(t))return!1;let e=C(t),n=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(r=>r.test(e))?!0:n.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function ft(t,e,n){let r=Q(t);if(!rt(r))return null;try{let o=JSON.parse(st(r,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==t.id||!Array.isArray(o.focus))return null;let s=Date.parse(o.updatedAt);return!Number.isFinite(s)||e-s>n?null:o}catch{return null}}function mt(t,e=8){let n=new Set,r=[];for(let o of t){let s=o.value.replace(/\s+/gu," ").trim();if(!s)continue;let i=[o.kind,C(s)].join(":");if(!n.has(i)&&(n.add(i),r.push({...o,value:s}),r.length>=e))break}return r}function pt(t,e){let n=Q(t),r=U(t.rootPath,".toolnet","context");ot(r,{recursive:!0,mode:448});let o=`${n}.${process.pid}.tmp`;try{at(o,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),it(o,n)}finally{ct(o,{force:!0})}}function gt(t){return t.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
6
+ `)}function yt(t,e){return t.priorFocus.find(n=>n.kind===e)?.value}function Y(t){if(!t.usedPriorFocus||t.currentIntent!=="summary"||t.priorFocus.length===0)return null;let e=C(t.originalQuestion),n=/^(?:tại sao|vì sao|sao vậy|why|why so|why that)\b/u.test(e),r=/^(?:rồi sao|sau đó|tiếp thì sao|thế tiếp theo|then what|what next)\b/u.test(e),o=n?["decision","blocker","next_action","task","file"]:r?["next_action","todo","task","blocker","file","decision"]:["task","next_action","file","decision","blocker"],s={task:"Task li\xEAn quan",next_action:"Vi\u1EC7c ti\u1EBFp theo",file:"File li\xEAn quan",decision:"Quy\u1EBFt \u0111\u1ECBnh li\xEAn quan",blocker:"Blocker",todo:"TODO"},i=[];for(let u of o){let f=yt(t,u);if(f&&(i.push(`${s[u]??u}: ${f}.`),n&&i.length>=2||!n&&i.length>=3))break}return i.length===0?null:{answer:i.join(" "),intent:"summary",source:"conversation-focus"}}function kt(t){let e=C(t);return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function J(t,e,n={}){let r=n.now??Date.now(),o=n.maxAgeMs??ut,s=ft(t,r,o),i=!!(s&&s.focus.length>0&&dt(e)&&!kt(e)),u=i&&s?[e.trim(),"","Previous ToolNet Memory conversation focus:",gt(s),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
7
+ `):e.trim(),f=A(e),d=b(t,u,{maxFacts:8,maxChars:1800}).facts.map(k=>({kind:k.kind,value:k.value,source:k.source})),p=mt(i&&s?[...d,...s.focus]:d);return pt(t,{schema:"toolnet.memory-conversation.v1",version:1,projectId:t.id,updatedAt:new Date(r).toISOString(),lastIntent:f,focus:p}),{question:u,originalQuestion:e,usedPriorFocus:i,previousIntent:s?.lastIntent,currentIntent:f,priorFocus:s?.focus??[],focusCount:p.length}}import{existsSync as ht,readFileSync as bt}from"node:fs";import{join as xt}from"node:path";function g(t){return!!t?.trim()}function Z(t){let e=[],n=[],r=100;g(t.goal)||g(t.request)||(e.push("goal_or_request"),r-=20),g(t.activity)||g(t.current.task?.title)||g(t.current.phase?.title)||(e.push("current_work"),r-=25),g(t.nextAction)||g(t.remaining.todos[0])||(e.push("next_action"),r-=25),t.tests.status!=="unknown"||t.tests.recent.length>0||(t.tests.checks?.length??0)>0||(t.evidence?.commands.length??0)>0||(t.evidence?.references.length??0)>0||(e.push("evidence"),r-=20),g(t.files.current)||t.files.recent.length>0||(t.files.active?.length??0)>0||(t.files.modified?.length??0)>0||(t.files.created?.length??0)>0||(e.push("files"),r-=10),t.tests.status==="failing"&&n.push("tests_failing"),t.blockers.length>0&&n.push("active_blockers"),r=Math.max(0,Math.min(100,r));let a=e.includes("current_work")||e.includes("next_action"),d;return r>=80&&!a?d="high":r>=50?d="medium":d="low",{confidence:d,score:r,missingContext:e,warnings:n}}var X={compact:{completed:3,evidence:3,files:5,blockers:2,maxChars:1800},normal:{completed:10,evidence:10,files:15,blockers:5,maxChars:4200},benchmark:{completed:30,evidence:30,files:40,blockers:10,maxChars:1e4}};function x(t){let e=new Set,n=[];for(let r of t){let o=r?.replace(/\s+/gu," ").trim();if(!o)continue;let s=o.normalize("NFKC").toLowerCase();e.has(s)||(e.add(s),n.push(o))}return n}function S(t){return t.length>0?t.map(e=>`- ${e}`).join(`
8
+ `):"- none"}function St(t,e){return t.length<=e?t:[t.slice(0,e).trimEnd(),"","[Structured handoff truncated]"].join(`
9
+ `)}function G(t,e){if(e)return e;let n=t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/\bbenchmark\b/u.test(n)||/\bdeep handoff\b/u.test(n)||/\bfull handoff\b/u.test(n)||/\btakeover\b/u.test(n)||/\btake over\b/u.test(n)||/tiếp quản/u.test(n)||/bằng chứng đầy đủ/u.test(n)||/evidence.*(?:file|test|command)/u.test(n)?"benchmark":/\bcompact\b/u.test(n)||/\bbrief\b/u.test(n)||/ngắn gọn/u.test(n)||/tóm tắt ngắn/u.test(n)?"compact":"normal"}function vt(t,e="normal"){let n=X[e],r=x([`Source agent: ${t.source.agent}`,`Captured: ${t.capturedAt}`,t.goal?`Goal: ${t.goal}`:void 0,t.request?`Request: ${t.request}`:void 0,t.activity?`Activity: ${t.activity}`:void 0,t.current.phase?`Phase: ${t.current.phase.title} [${t.current.phase.status}]`:void 0,t.current.task?`Task: ${t.current.task.title} [${t.current.task.status}]`:void 0,t.current.file?`Current file: ${t.current.file}`:void 0,`Progress: ${JSON.stringify(t.progress)}`]),o=x([...t.completed.phases.map(a=>`Phase: ${a}`),...t.completed.tasks.map(a=>`Task: ${a}`)]).slice(0,n.completed),s=x([`Tests status: ${t.tests.status}`,...t.tests.recent.map(a=>`Test: ${a}`),...(t.tests.checks??[]).map(a=>`Check [${a.status}] ${a.kind}: ${a.command}`),...(t.evidence?.commands??[]).map(a=>`Command: ${a}`),...(t.evidence?.references??[]).map(a=>`Reference: ${a}`),...t.decisions.map(a=>`Decision: ${a}`),...t.attention.map(a=>`Attention: ${a}`)]).slice(0,n.evidence),i=x([t.files.current,...(t.files.active??[]).map(a=>`Active: ${a}`),...(t.files.modified??[]).map(a=>`Modified: ${a}`),...(t.files.created??[]).map(a=>`Created: ${a}`),...(t.files.deleted??[]).map(a=>`Deleted: ${a}`),...t.files.recent.map(a=>`Recent: ${a}`)]).slice(0,n.files),u=x(t.blockers).slice(0,n.blockers),f=x([t.nextAction,t.nextAction?void 0:t.remaining.todos[0]]).slice(0,1);return{currentState:r,completed:o,evidence:s,filesTouched:i,blockers:u,nextAction:f}}function Mt(t,e,n){return[`HANDOFF_DETAIL: ${e}`,`CONTINUITY_CONFIDENCE: ${n.confidence}`,`QUALITY_SCORE: ${n.score}`,`MISSING_CONTEXT: ${n.missingContext.length>0?n.missingContext.join(", "):"none"}`,`QUALITY_WARNINGS: ${n.warnings.length>0?n.warnings.join(", "):"none"}`,"","CURRENT_STATE",S(t.currentState),"","COMPLETED",S(t.completed),"","EVIDENCE",S(t.evidence),"","FILES_TOUCHED",S(t.filesTouched),"","BLOCKERS",S(t.blockers),"","NEXT_ACTION",S(t.nextAction)].join(`
10
+ `)}function ee(t,e="normal"){let n=xt(t.rootPath,".toolnet","work","handoff-latest.json");if(!ht(n))return null;try{let o=JSON.parse(bt(n,"utf8")).continuity;if(!o||o.schema!=="toolnet.handoff.v2"||o.version!==2)return null;let s=vt(o,e),i=Z(o),u=St(Mt(s,e,i),X[e].maxChars);return{detail:e,data:s,quality:i,text:u}}catch{return null}}function Ct(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}var wt=[/\bhandoff\b/u,/\bcontinuity\b/u,/\bcontinue\b/u,/\bresume\b/u,/\btakeover\b/u,/\btake over\b/u,/tiếp tục/u,/tiếp quản/u,/bàn giao/u,/dừng ở đâu/u,/đang làm gì/u],At=[/\bcurrent state\b/u,/\bcurrent task\b/u,/\bevidence\b/u,/\breport locations?\b/u,/\bfiles?\b/u,/\burls?\b/u,/\bassets?\b/u,/\btests?\b/u,/\bcommands?\b/u,/\bblockers?\b/u,/\bnext actions?\b/u,/trạng thái hiện tại/u,/task hiện tại/u,/bằng chứng/u,/vị trí báo cáo/u,/file/u,/url/u,/blocker/u,/việc tiếp theo/u,/bước tiếp theo/u],Tt=[/\bsummarize\b/u,/\bsummary\b/u,/\bfull state\b/u,/\bfull context\b/u,/tóm tắt/u,/đầy đủ/u,/toàn bộ trạng thái/u];function Et(t){let e=0;for(let n of At)n.test(t)&&(e+=1);return e}function te(t,e){let n=Ct(t);if(/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(n)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(n)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(n))return!1;if(e==="summary"||e==="status")return!0;if(!n)return!1;let o=wt.some(u=>u.test(n)),s=Tt.some(u=>u.test(n)),i=Et(n);return!!(o&&i>=1||s&&i>=2||i>=4)}var $r={question:N.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:N.enum(["local"]).optional().describe("Returns deterministic local memory only. No external AI is used."),detail:N.enum(["compact","normal","benchmark"]).optional().describe("Handoff detail level. compact=minimal, normal=standard, benchmark=deep evidence/files/tests for agent takeover.")};function ne(t,e,n,r,o){if(!te(e,n))return{answer:r};let s=G(e,o),i=ee(t.project,s);return i?{answer:i.text,handoff:i.data,detail:i.detail,confidence:i.quality.confidence,missingContext:i.quality.missingContext,quality:i.quality}:{answer:r}}async function O(t,e){let n=J(t.project,e.question),r=Y(n);if(r)return{...ne(t,n.originalQuestion,String(r.intent),r.answer,e.detail),mode:"local",usedAi:!1,source:r.source,intent:r.intent};let o=V(t.project,n.originalQuestion),s=ne(t,n.originalQuestion,String(o.intent),o.answer,e.detail);return"handoff"in s?{...s,mode:"local",usedAi:!1,source:o.source,intent:o.intent,routing:"deterministic-handoff"}:{...s,mode:"local",usedAi:!1,source:o.source,intent:o.intent}}var re="RAW_TRANSCRIPT_MUST_NEVER_ENTER_CONTINUITY_CONTEXT_X1";function oe(t,e){se(t,JSON.stringify(e,null,2)+`
11
+ `,"utf8")}function Pt(t,e,n,r,o,s,i,u){return{continuity:{schema:"toolnet.handoff.v2",version:2,project:{id:t,name:e},source:{agent:n,nativeSessionId:`${n}-x1-source`,sessionKey:`${n}:${n}-x1-source`,sequence:42,reason:"checkpoint"},capturedAt:"2026-08-13T05:30:00.000Z",goal:`Continue ${e} safely across agents`,request:`Recover ${o} with exact evidence and next action`,activity:`Preparing ${r} takeover from ${n}`,current:{phase:{id:"x1",title:"Cross-Agent Continuity E2E",status:"in_progress"},task:{id:"x1-cross-agent",title:o,status:"in_progress"},file:s},completed:{phases:["A1 OpenCode Adapter","A2 Agy Adapter","A3 Claude Code Adapter"],tasks:["Build canonical handoff schema","Build intelligent memory retrieval"]},remaining:{phases:["X1 Cross-Agent Continuity E2E"],tasks:[o],todos:[i]},nextAction:u,blockers:[],decisions:["Canonical handoff must override stale session state","Never replay raw transcripts during continuity recovery"],files:{current:s,recent:[s]},tests:{status:"passing",recent:["A1-A3 adapter tests passed"],checks:[{kind:"test",status:"passed",command:`node scripts/${n}-to-${r}-verify.mjs`}]},evidence:{commands:[`node scripts/${n}-to-${r}-verify.mjs`],references:[`https://example.test/${n}/${r}/continuity-report`]},attention:[],progress:{phasesTotal:3,phasesCompleted:2,tasksTotal:4,tasksCompleted:3,blocked:0},stateDigest:"a".repeat(64)}}}async function T(t,e){return O({project:t},{question:e,mode:"local"})}async function Rt(t,e){let n=_t(y(Ft(),`toolnet-x1-${t}-${e}-`));try{let r=`x1-${t}-${e}`,o=`x1-${t}-to-${e}`,s={id:r,name:o,rootPath:n,createdAt:"2026-08-13T05:30:00.000Z",updatedAt:"2026-08-13T05:30:00.000Z",graphVersion:1,memoryVersion:1},i=y(n,".toolnet","work"),u=y(n,".toolnet","context"),f=y(n,".toolnet","runtime","sources",t,"raw-session-x1");L(i,{recursive:!0}),L(u,{recursive:!0}),L(f,{recursive:!0});let a=`X1 ${t} to ${e} canonical continuity`,d=`src/x1/${t}-to-${e}.ts`,p=`Implement ${e} continuation step`,k=`Continue ${a} in ${d}`;oe(y(i,"handoff-latest.json"),Pt(r,o,t,e,a,d,p,k)),oe(y(u,"session-origin.json"),{version:1,projectId:r,agent:"stale-agent",nativeSessionId:"stale-session",updatedAt:"2026-01-01T00:00:00.000Z",currentTask:"STALE TASK MUST NOT WIN",currentPhase:"STALE PHASE",lastTouchedFile:"src/stale/old.ts",latestNextAction:"STALE NEXT ACTION"}),se(y(f,"events.jsonl"),JSON.stringify({text:re})+`
12
+ `,"utf8");let ce=b(s,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?",{maxFacts:12,maxChars:3200}),E=await T(s,"Task hi\u1EC7n t\u1EA1i \u0111ang l\xE0m l\xE0 g\xEC?"),_=await T(s,"File hi\u1EC7n t\u1EA1i l\xE0 file n\xE0o?"),I=await T(s,"TODO c\xF2n l\u1EA1i l\xE0 g\xEC?"),F=await T(s,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?"),m=await O({project:s},{mode:"local",detail:"benchmark",question:"Summarize current state, completed work, evidence, files, tests, blockers and exact next action for benchmark agent takeover."}),v=m,ae=`node scripts/${t}-to-${e}-verify.mjs`,ue=`https://example.test/${t}/${e}/continuity-report`,le=[E.answer,_.answer,I.answer,F.answer,m.answer].join(`
13
+ `),P=[E,_,I,F],j={canonicalHandoffPreferred:ce.facts[0]?.source==="handoff",taskRecovered:E.answer.includes(a),fileRecovered:_.answer.includes(d),todoRecovered:I.answer.includes(p),nextActionRecovered:F.answer.includes(k),localModeOnly:P.every(M=>M.mode==="local"),noAiRequired:P.every(M=>M.usedAi===!1),rawTranscriptIsolated:!le.includes(re),compact:P.every(M=>M.answer.length<1600),structuredTakeoverRecovered:m.answer.includes("CURRENT_STATE")&&m.answer.includes("COMPLETED")&&m.answer.includes("EVIDENCE")&&m.answer.includes("FILES_TOUCHED")&&m.answer.includes("BLOCKERS")&&m.answer.includes("NEXT_ACTION"),benchmarkDetailRecovered:v.detail==="benchmark"&&m.answer.includes("HANDOFF_DETAIL: benchmark"),highConfidence:v.confidence==="high"&&Array.isArray(v.missingContext)&&v.missingContext.length===0,evidenceRecovered:m.answer.includes(ae)&&m.answer.includes(ue),deterministicTakeover:m.usedAi===!1&&v.routing==="deterministic-handoff"};return{from:t,to:e,passed:Object.values(j).every(Boolean),checks:j}}finally{It(n,{recursive:!0,force:!0})}}async function ie(){let t=[["agy","codex"],["codex","opencode"],["opencode","claude"],["claude","kiro"],["kiro","cursor"],["cursor","copilot"],["copilot","grok"],["grok","toolnet-cli"],["toolnet-cli","kilo"],["kilo","agy"]],e=[];for(let[r,o]of t)e.push(await Rt(r,o));let n=e.filter(r=>r.passed).length;return{passed:n===e.length,total:e.length,passedCount:n,cases:e}}var l={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",cyan:"\x1B[36m",gray:"\x1B[90m",white:"\x1B[97m"};function $t(t){return t?`${l.green}\u2713${l.reset}`:`${l.red}\u2717${l.reset}`}function Nt(t){let e=`${t.from.padEnd(8)} \u2192 ${t.to.padEnd(8)}`;if(console.log(`\u2502 ${$t(t.passed)} ${e}`),!t.passed)for(let[n,r]of Object.entries(t.checks))r||console.log(`\u2502 ${l.red}\u2717${l.reset} ${n}`)}async function Ot(){console.log(""),console.log(`${l.cyan}\u25C7${l.reset} ${l.white}ToolNet Cross-Agent Continuity Certification${l.reset}`),console.log(`${l.gray}\u2502${l.reset}`);let t=await ie();for(let e of t.cases)Nt(e);if(console.log(`${l.gray}\u2502${l.reset}`),t.passed){console.log(`${l.green}\u25C6 PASS${l.reset} ${t.passedCount}/${t.total} cross-agent transitions`),console.log(`${l.green}\u2713${l.reset} canonical handoff`),console.log(`${l.green}\u2713${l.reset} memory_agent_ask`),console.log(`${l.green}\u2713${l.reset} task / file / TODO / next action`),console.log(`${l.green}\u2713${l.reset} raw transcripts isolated`),console.log(`${l.green}\u2713${l.reset} AI not required for direct continuity`);return}console.log(`${l.red}\u25C6 FAIL${l.reset} ${t.passedCount}/${t.total} cross-agent transitions`),process.exitCode=1}Ot().catch(t=>{console.error(t instanceof Error?t.message:String(t)),process.exitCode=1});