toolnet-memory 0.3.12 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -4
- package/README.md +5 -48
- package/bin/toolnet-memory +15 -42
- package/bundle/agy-hook.js +50 -50
- package/bundle/agy.js +17 -17
- package/bundle/api.js +15 -55
- package/bundle/auto-integrate.js +34 -33
- package/bundle/config.js +17 -12
- package/bundle/context-runtime.js +9 -9
- package/bundle/continuity-certify.js +13 -53
- package/bundle/doctor.js +4 -6
- package/bundle/full-index.js +21 -22
- package/bundle/graph-index.js +3 -3
- package/bundle/graph-ui.js +3 -3
- package/bundle/help-cli.js +4 -4
- package/bundle/impact.js +3 -3
- package/bundle/incremental.js +3 -3
- package/bundle/init.js +37 -36
- package/bundle/kilo.js +2 -0
- package/bundle/learner.js +4 -4
- package/bundle/mcp.js +18 -59
- package/bundle/memory-agent.js +7 -47
- package/bundle/project-manual.js +2 -2
- package/bundle/recovery-certify.js +13 -53
- package/bundle/runtime.js +11 -11
- package/bundle/semantic.js +5 -6
- package/bundle/snapshot.js +3 -3
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +2 -0
- package/bundle/work-continuity.js +5 -5
- package/package.json +1 -3
- package/bundle/model-cli.js +0 -2
- package/bundle/provider.js +0 -6
- package/bundle/setup.js +0 -1159
|
@@ -1,56 +1,16 @@
|
|
|
1
|
-
import{mkdirSync as
|
|
2
|
-
|
|
3
|
-
`)
|
|
4
|
-
|
|
5
|
-
`)
|
|
6
|
-
|
|
7
|
-
`)}function
|
|
8
|
-
[
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
You are NOT the coding agent.
|
|
12
|
-
|
|
13
|
-
Your job is to help another coding AI continue work from previous sessions.
|
|
14
|
-
|
|
15
|
-
Rules:
|
|
16
|
-
|
|
17
|
-
1. Answer only from the supplied ToolNet project memory.
|
|
18
|
-
2. Never invent completed work, files, blockers, decisions, or test results.
|
|
19
|
-
3. Prefer the latest session/work state over old information.
|
|
20
|
-
4. Be concise.
|
|
21
|
-
5. Do not dump raw JSON or full memory files.
|
|
22
|
-
6. Tell the coding agent exactly:
|
|
23
|
-
- what the previous agent was doing,
|
|
24
|
-
- what is already completed,
|
|
25
|
-
- what remains unfinished,
|
|
26
|
-
- what file was last touched,
|
|
27
|
-
- what should be done next,
|
|
28
|
-
when those facts are available.
|
|
29
|
-
7. If information is missing, say it is not recorded.
|
|
30
|
-
8. Do not explain ToolNet internals unless asked.
|
|
31
|
-
9. Do not repeat irrelevant history.
|
|
32
|
-
10. Respond in the same language as the question.
|
|
33
|
-
|
|
34
|
-
Think of yourself as the project's memory coworker talking directly to another AI.
|
|
35
|
-
`.trim()},{role:"user",content:`
|
|
36
|
-
Question from coding agent:
|
|
37
|
-
|
|
38
|
-
${e}
|
|
39
|
-
|
|
40
|
-
ToolNet selected memory:
|
|
41
|
-
|
|
42
|
-
${o}
|
|
43
|
-
|
|
44
|
-
Answer the coding agent directly.
|
|
45
|
-
`.trim()}]}),m=a.text.trim();return m?{answer:m,provider:a.provider,model:a.model,usedAi:!0}:{answer:r.answer,usedAi:!1}}catch{return{answer:r.answer,usedAi:!1}}}import{existsSync as tn,mkdirSync as nn,readFileSync as rn,renameSync as on,rmSync as sn,writeFileSync as an}from"node:fs";import{join as Be}from"node:path";var We=720*60*1e3;function qe(n){return Be(n.rootPath,".toolnet","context","memory-agent-conversation.json")}function X(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function cn(n){let e=X(n);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(t=>t.test(e))}function ln(n){if(cn(n))return!1;let e=X(n),t=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:t.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function ze(n,e,t){let r=qe(n);if(!tn(r))return null;try{let o=JSON.parse(rn(r,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==n.id||!Array.isArray(o.focus))return null;let s=Date.parse(o.updatedAt);return!Number.isFinite(s)||e-s>t?null:o}catch{return null}}function un(n,e=8){let t=new Set,r=[];for(let o of n){let s=o.value.replace(/\s+/gu," ").trim();if(!s)continue;let a=[o.kind,X(s)].join(":");if(!t.has(a)&&(t.add(a),r.push({...o,value:s}),r.length>=e))break}return r}function dn(n,e){let t=qe(n),r=Be(n.rootPath,".toolnet","context");nn(r,{recursive:!0,mode:448});let o=`${t}.${process.pid}.tmp`;try{an(o,JSON.stringify(e,null,2)+`
|
|
46
|
-
`,{encoding:"utf8",mode:384}),on(o,t)}finally{sn(o,{force:!0})}}function mn(n){return n.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
|
|
47
|
-
`)}function pn(n){let e=X(n);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 se(n,e,t={}){let r=t.now??Date.now(),o=t.maxAgeMs??We,s=ze(n,r,o),a=!!(s&&s.focus.length>0&&ln(e)&&!pn(e)),m=a&&s?[e.trim(),"","Previous ToolNet Memory conversation focus:",mn(s),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
|
|
48
|
-
`):e.trim(),d=V(e),p=R(n,m,{maxFacts:8,maxChars:1800}).facts.map(T=>({kind:T.kind,value:T.value,source:T.source})),v=un(a&&s?[...p,...s.focus]:p);return dn(n,{schema:"toolnet.memory-conversation.v1",version:1,projectId:n.id,updatedAt:new Date(r).toISOString(),lastIntent:d,focus:v}),{question:m,originalQuestion:e,usedPriorFocus:a,previousIntent:s?.lastIntent,currentIntent:d,priorFocus:s?.focus??[],focusCount:v.length}}function He(n,e={}){return ze(n,e.now??Date.now(),e.maxAgeMs??We)}import{existsSync as fn,readFileSync as gn,writeFileSync as yn}from"node:fs";import{join as hn}from"node:path";var Ye="<!-- TOOLNET:STABLE-WORK:BEGIN -->",ie="<!-- TOOLNET:STABLE-WORK:END -->";function ae(n){switch(n.status){case"completed":return"[x]";case"in_progress":return"[~]";case"blocked":return"[!]";case"cancelled":return"[-]";default:return"[ ]"}}function b(n,e){return e.length?["",`${n}:`,...e.map(t=>`- ${t}`)]:[]}function Ge(n,e){return e.length?["",`${n}:`,...e.map(t=>`- ${ae(t)} ${t.title}`)]:[]}function kn(n){let e=[Ye,"# ToolNet Stable Work State","",`Updated: ${n.updatedAt}`];return n.lastSession&&e.push(`Last agent: ${n.lastSession.agent}`,`Last session: ${n.lastSession.nativeSessionId}`),n.currentRequest&&e.push("","Current request:",n.currentRequest),n.currentActivity&&e.push("","Current activity:",n.currentActivity),n.goal&&e.push("","Goal:",n.goal),n.plan&&e.push("","Plan:",n.plan),n.currentPhase&&e.push("","Current phase:",`${ae(n.currentPhase)} ${n.currentPhase.title}`),n.currentTask&&e.push("","Current task:",`${ae(n.currentTask)} ${n.currentTask.title}`),e.push(...Ge("Phases",n.phases)),e.push(...Ge("TODO / Tasks",n.tasks)),e.push(...b("Next actions",n.nextActions)),e.push(...b("Blockers",n.blockers)),e.push(...b("Important decisions",n.decisions)),e.push(...b("Active files",n.activeFiles??[])),e.push(...b("Modified files",n.modifiedFiles??[])),e.push(...b("Created files",n.createdFiles??[])),e.push(...b("Deleted files",n.deletedFiles??[])),e.push(...b("Files touched",n.filesTouched)),e.push(...b("Recent commands",n.commands??[])),e.push(...b("Checks",(n.checks??[]).map(t=>`[${t.status}] ${t.kind}: ${t.command}`))),e.push("","Progress:",`- Phases: ${n.progress.phasesCompleted}/${n.progress.phasesTotal}`,`- Tasks: ${n.progress.tasksCompleted}/${n.progress.tasksTotal}`,`- Blocked: ${n.progress.blocked}`,"","Continuation:","- Resume current unfinished task.","- Never redo completed TODO/Phase unless explicitly requested.","- Ask ToolNet Memory for deeper history only when necessary.",ie),e.join(`
|
|
49
|
-
`)}function Ve(n,e){let t=hn(n.rootPath,".toolnet","current.md"),r="";if(fn(t))try{r=gn(t,"utf8")}catch{r=""}r=r.replace(/<!-- TOOLNET:AUTO-CURRENT:BEGIN -->[\s\S]*?<!-- TOOLNET:AUTO-CURRENT:END -->/gu,"");let o=kn(e),s=r.indexOf(Ye),a=r.indexOf(ie),m;s>=0&&a>=s?m=[r.slice(0,s).trimEnd(),o,r.slice(a+ie.length).trimStart()].filter(Boolean).join(`
|
|
1
|
+
import{mkdirSync as W,mkdtempSync as h,readFileSync as V,readdirSync as Wt,rmSync as b,writeFileSync as T}from"node:fs";import{tmpdir as v}from"node:os";import{join as u}from"node:path";import{existsSync as st,readFileSync as it}from"node:fs";import{join as ct}from"node:path";import{existsSync as _e,mkdirSync as Re,readFileSync as Pe,renameSync as Ne,writeFileSync as Oe}from"node:fs";import{dirname as $e,join as je}from"node:path";function Ke(n,e){Re($e(n),{recursive:!0});let t=`${n}.tmp-${process.pid}-${Date.now()}`;Oe(t,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),Ne(t,n)}function le(n){return je(n.rootPath,".toolnet","work","current.json")}function P(n){let e=le(n);if(!_e(e))return null;try{let t=JSON.parse(Pe(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function N(n){return n.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function p(n,e,t){let r=[],o=new Set;for(let s of[...n,...e].reverse()){let a=N(s);if(!(!a||o.has(a))&&(o.add(a),r.push(s),r.length>=t))break}return r.reverse()}function Le(n,e,t=20){let r=new Map;for(let o of[...n,...e]){let s=`${o.kind}|${N(o.command)}`;r.delete(s),r.set(s,o)}return Array.from(r.values()).slice(-t)}function De(n){return n.kind==="phase"?/^Phase\s+\d+$/iu.test(n.text):n.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(n.text):!1}function se(n,e){let t=e.status??n?.status??"pending",r=t;n?.status==="completed"&&t!=="completed"&&(r="completed"),n&&t==="pending"&&(n.status==="in_progress"||n.status==="blocked")&&(r=n.status);let o=n&&De(e)?n.title:e.text;return{id:n?.id??e.id,title:o,status:r,order:e.order??n?.order,confidence:Math.max(n?.confidence??0,e.confidence),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}function ie(n){let e=new Map;for(let t of n){let r=t.order!==void 0?`order:${t.order}`:N(t.title);e.set(r,t)}return e}function ce(n){return n.order!==void 0?`order:${n.order}`:N(n.key||n.text)}function ae(n){return Array.from(n).sort((e,t)=>{let r=e.order??Number.MAX_SAFE_INTEGER,o=t.order??Number.MAX_SAFE_INTEGER;return r!==o?r-o:e.updatedAt.localeCompare(t.updatedAt)})}function ue(n){return n.find(e=>e.status==="in_progress")??n.find(e=>e.status==="blocked")??n.find(e=>e.status==="pending")}function de(n,e){let t=P(n),r=ie(t?.phases??[]),o=ie(t?.tasks??[]),s=t?.currentRequest,a=t?.currentActivity,m=t?.goal,f=t?.plan,w=t?.lastSession,l=[],g=[],A=[],J=[],G=[],E=[...t?.activeFiles??[]],X=[],Z=[],ee=[],te=[],ne=[],re=[],_=[...e].sort((i,d)=>{let I=i.occurredAt.localeCompare(d.occurredAt);return I!==0?I:i.sequence-d.sequence});for(let i of _)switch(i.kind){case"request":s=i.text;break;case"activity":a=i.text;break;case"goal":m=i.text;break;case"plan":f=i.text;break;case"phase":{let d=ce(i);r.set(d,se(r.get(d),i));break}case"task":{let d=ce(i);o.set(d,se(o.get(d),i));break}case"decision":l.push(i.text);break;case"blocker":g.push(i.text);break;case"warning":A.push(i.text);break;case"next_action":J.push(i.text);break;case"file":{G.push(i.text);let d=i.fileAction??"active",I=E.indexOf(i.text);I>=0&&E.splice(I,1),d!=="deleted"&&E.push(i.text),d==="modified"?X.push(i.text):d==="created"?Z.push(i.text):d==="deleted"&&ee.push(i.text);break}case"command":te.push(i.text);break;case"test":ne.push(i.text),i.checkKind&&re.push({kind:i.checkKind,command:i.text,status:i.checkStatus??"unknown",updatedAt:i.occurredAt,agent:i.agent,nativeSessionId:i.nativeSessionId});break;case"session":w={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let F=ae(r.values()),C=ae(o.values()),z=ue(F),R=ue(C),Fe=p(t?.nextActions??[],[...J,...R?[R.title]:[],...!R&&z?[z.title]:[],...C.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Ie=p(t?.blockers??[],[...g,...F.filter(i=>i.status==="blocked").map(i=>i.title),...C.filter(i=>i.status==="blocked").map(i=>i.title)],20),Ee=_.length>0?_[_.length-1].occurredAt:t?.updatedAt??new Date().toISOString(),oe={version:1,projectId:n.id,projectName:n.name,currentRequest:s,currentActivity:a,goal:m,plan:f,phases:F,tasks:C,decisions:p(t?.decisions??[],l,20),blockers:Ie,warnings:p(t?.warnings??[],A,20),nextActions:Fe,filesTouched:p(t?.filesTouched??[],G,30),activeFiles:p([],E,5),modifiedFiles:p(t?.modifiedFiles??[],X,30),createdFiles:p(t?.createdFiles??[],Z,30),deletedFiles:p(t?.deletedFiles??[],ee,30),commands:p(t?.commands??[],te,20),tests:p(t?.tests??[],ne,20),checks:Le(t?.checks??[],re,20),currentPhase:z,currentTask:R,progress:{phasesTotal:F.length,phasesCompleted:F.filter(i=>i.status==="completed").length,tasksTotal:C.length,tasksCompleted:C.filter(i=>i.status==="completed").length,blocked:F.filter(i=>i.status==="blocked").length+C.filter(i=>i.status==="blocked").length},lastSession:w,updatedAt:Ee};return Ke(le(n),oe),oe}import{existsSync as We,mkdirSync as Vt,readFileSync as ze,renameSync as Yt,writeFileSync as Jt}from"node:fs";import{dirname as Xt,join as qe}from"node:path";function Be(n){return qe(n.rootPath,".toolnet","context","session-origin.json")}function q(n){let e=Be(n);if(!We(e))return null;try{let t=JSON.parse(ze(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function He(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function O(n){let e=He(n),t=/(?: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 t&&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 et,mkdirSync as Bn,readFileSync as tt}from"node:fs";import{join as fe}from"node:path";var Qe=[{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}],$=class{scan(e){let t=[];for(let r of Qe){let o=new RegExp(r.regex.source,r.regex.flags);for(let s of e.matchAll(o))t.push({type:r.type,value:s[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var j=class{scanner=new $;sanitize(e){let t=e,r=this.scanner.scan(e),o=new Set;for(let s of r)o.add(s.type),t=t.split(s.value).join(`[REDACTED:${s.type}]`);return{text:t,redacted:r.length,secretTypes:[...o]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};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")?t[r]="[REDACTED]":t[r]=this.sanitizeValue(o)}return t}return e}};import{existsSync as Ve,readFileSync as Ye}from"node:fs";import{homedir as Je}from"node:os";import{join as Ge}from"node:path";function Xe(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
3
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Ze(){let n=process.env.TOOLNET_GLOBAL_ENV??Ge(Je(),".config","toolnet-memory",".env");if(!Ve(n))return;let e=Ye(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.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]=Xe(r.slice(o+1)))}}Ze();var Rn=new j;function nt(n){return fe(n.rootPath,".toolnet","memory","checkpoints")}function rt(n){return fe(nt(n),"latest.json")}function ot(n){let e=rt(n);if(!et(e))return null;try{let t=JSON.parse(tt(e,"utf8"));return t.schema!=="toolnet.memory.checkpoint.v1"||t.project.id!==n.id?null:t}catch{return null}}function me(n){return ot(n)}var at={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}},ut={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function lt(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function c(n,e){let t=e.value.replace(/\s+/g," ").trim();t&&n.push({...e,value:t,score:0})}function dt(n){let e=ct(n.rootPath,".toolnet","work","handoff-latest.json");if(!st(e))return null;try{let r=JSON.parse(it(e,"utf8")).continuity;return r?.schema!=="toolnet.handoff.v2"||r.project.id!==n.id?null:r}catch{return null}}function ft(n){let e=me(n);if(!e)return[];let t=[];e.request&&c(t,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&c(t,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&c(t,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&c(t,{kind:"task",value:e.current.task.title,source:"checkpoint"});let r=e.files.active.at(-1);r&&c(t,{kind:"file",value:r,source:"checkpoint"});for(let o of e.nextActions)c(t,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)c(t,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)c(t,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)c(t,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)c(t,{kind:o.kind,value:o.content,source:"checkpoint"});return t}function mt(n){let e=dt(n);if(!e)return[];let t=[];c(t,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&c(t,{kind:"request",value:e.request,source:"handoff"}),e.activity&&c(t,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&c(t,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&c(t,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&c(t,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&c(t,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&c(t,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let r of e.blockers)c(t,{kind:"blocker",value:r,source:"handoff"});for(let r of e.decisions)c(t,{kind:"decision",value:r,source:"handoff"});for(let r of e.completed.tasks)c(t,{kind:"completed",value:r,source:"handoff"});for(let r of e.remaining.todos)c(t,{kind:"todo",value:r,source:"handoff"});return c(t,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),c(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),t}function pt(n){let e=q(n);if(!e)return[];let t=[];return c(t,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&c(t,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&c(t,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&c(t,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&c(t,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&c(t,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&c(t,{kind:"decision",value:e.latestDecision,source:"session-origin"}),t}function gt(n){let e=P(n);if(!e)return[];let t=[];e.currentRequest&&c(t,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&c(t,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&c(t,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&c(t,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&c(t,{kind:"task",value:e.currentTask.title,source:"work-state"});let r=e.activeFiles?.at(-1)??e.filesTouched.at(-1);r&&c(t,{kind:"file",value:r,source:"work-state"});for(let o of e.nextActions.slice(0,5))c(t,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))c(t,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))c(t,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(s=>s.status==="completed").slice(-8))c(t,{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(t,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))c(t,{kind:"test",value:o,source:"work-state"});return c(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),t}function kt(n,e){let t=at[n];return e.map((r,o)=>({...r,score:(t[r.kind]??10)+ut[r.source]+Math.max(0,5-o*.01)}))}function yt(n){let e=new Map;for(let t of n){let r=`${t.kind}:${lt(t.value)}`,o=e.get(r);(!o||t.score>o.score)&&e.set(r,t)}return[...e.values()]}function K(n,e,t={}){let r=O(e),o=[...ft(n),...mt(n),...pt(n),...gt(n)],s=yt(kt(r,o)).sort((l,g)=>g.score-l.score),a=Math.max(1,t.maxFacts??12),m=Math.max(300,t.maxChars??3200),f=[],w=0;for(let l of s){if(f.length>=a)break;let g=l.kind.length+l.value.length+l.source.length+16;f.length>0&&w+g>m||(f.push(l),w+=g)}return{intent:r,facts:f,context:{project:{id:n.id,name:n.name},intent:r,selectedFacts:f.map(l=>({kind:l.kind,value:l.value,source:l.source}))},stats:{candidates:o.length,selected:f.length,chars:w}}}var pe={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"},ge=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],ht={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:ge};function bt(n){let e=n.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 vt(n){let e=n.filter(r=>r.source==="handoff");if(e.length===0)return n;let t=n.filter(r=>r.source==="checkpoint"&&["rule","architecture","fix"].includes(r.kind));return[...e,...t]}function xt(n){let e=new Set,t=[];for(let r of n){let o=`${r.kind}:${r.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),t.push(r))}return t}function ke(n){switch(n){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function St(n,e){let t=[];for(let r of e){let o=n.filter(s=>s.kind===r).slice(0,ke(r));for(let s of o)t.push(`${pe[r]}: ${s.value}`)}return t.join(`
|
|
4
|
+
`)}function Mt(n,e){let t=ht[e]??ge,r=[];for(let o of t){let s=n.filter(a=>a.kind===o).slice(0,ke(o));for(let a of s)r.push(`${pe[o]}: ${a.value}`)}return r.join(`
|
|
5
|
+
`)}function k(n,e){let t=K(n,e,{maxFacts:32,maxChars:6400}),r=xt(vt(t.facts)),o=bt(e)?St(r,["todo","task","next_action","file"]):Mt(r,String(t.intent));return o?{intent:String(t.intent),answer:o,source:r[0]?.source??"none"}:{intent:String(t.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}async function ye(n,e){let t=k(n,e);return t.answer?{answer:t.answer,usedAi:!1}:{answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",usedAi:!1}}import{existsSync as wt,mkdirSync as Ct,readFileSync as Tt,renameSync as At,rmSync as Ft,writeFileSync as It}from"node:fs";import{join as he}from"node:path";var be=720*60*1e3;function ve(n){return he(n.rootPath,".toolnet","context","memory-agent-conversation.json")}function L(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function Et(n){let e=L(n);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(t=>t.test(e))}function _t(n){if(Et(n))return!1;let e=L(n),t=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:t.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function xe(n,e,t){let r=ve(n);if(!wt(r))return null;try{let o=JSON.parse(Tt(r,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==n.id||!Array.isArray(o.focus))return null;let s=Date.parse(o.updatedAt);return!Number.isFinite(s)||e-s>t?null:o}catch{return null}}function Rt(n,e=8){let t=new Set,r=[];for(let o of n){let s=o.value.replace(/\s+/gu," ").trim();if(!s)continue;let a=[o.kind,L(s)].join(":");if(!t.has(a)&&(t.add(a),r.push({...o,value:s}),r.length>=e))break}return r}function Pt(n,e){let t=ve(n),r=he(n.rootPath,".toolnet","context");Ct(r,{recursive:!0,mode:448});let o=`${t}.${process.pid}.tmp`;try{It(o,JSON.stringify(e,null,2)+`
|
|
6
|
+
`,{encoding:"utf8",mode:384}),At(o,t)}finally{Ft(o,{force:!0})}}function Nt(n){return n.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
|
|
7
|
+
`)}function Ot(n){let e=L(n);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 B(n,e,t={}){let r=t.now??Date.now(),o=t.maxAgeMs??be,s=xe(n,r,o),a=!!(s&&s.focus.length>0&&_t(e)&&!Ot(e)),m=a&&s?[e.trim(),"","Previous ToolNet Memory conversation focus:",Nt(s),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
|
|
8
|
+
`):e.trim(),f=O(e),l=K(n,m,{maxFacts:8,maxChars:1800}).facts.map(A=>({kind:A.kind,value:A.value,source:A.source})),g=Rt(a&&s?[...l,...s.focus]:l);return Pt(n,{schema:"toolnet.memory-conversation.v1",version:1,projectId:n.id,updatedAt:new Date(r).toISOString(),lastIntent:f,focus:g}),{question:m,originalQuestion:e,usedPriorFocus:a,previousIntent:s?.lastIntent,currentIntent:f,priorFocus:s?.focus??[],focusCount:g.length}}function Se(n,e={}){return xe(n,e.now??Date.now(),e.maxAgeMs??be)}import{existsSync as $t,readFileSync as jt,writeFileSync as Kt}from"node:fs";import{join as Lt}from"node:path";var we="<!-- TOOLNET:STABLE-WORK:BEGIN -->",H="<!-- TOOLNET:STABLE-WORK:END -->";function U(n){switch(n.status){case"completed":return"[x]";case"in_progress":return"[~]";case"blocked":return"[!]";case"cancelled":return"[-]";default:return"[ ]"}}function y(n,e){return e.length?["",`${n}:`,...e.map(t=>`- ${t}`)]:[]}function Me(n,e){return e.length?["",`${n}:`,...e.map(t=>`- ${U(t)} ${t.title}`)]:[]}function Dt(n){let e=[we,"# ToolNet Stable Work State","",`Updated: ${n.updatedAt}`];return n.lastSession&&e.push(`Last agent: ${n.lastSession.agent}`,`Last session: ${n.lastSession.nativeSessionId}`),n.currentRequest&&e.push("","Current request:",n.currentRequest),n.currentActivity&&e.push("","Current activity:",n.currentActivity),n.goal&&e.push("","Goal:",n.goal),n.plan&&e.push("","Plan:",n.plan),n.currentPhase&&e.push("","Current phase:",`${U(n.currentPhase)} ${n.currentPhase.title}`),n.currentTask&&e.push("","Current task:",`${U(n.currentTask)} ${n.currentTask.title}`),e.push(...Me("Phases",n.phases)),e.push(...Me("TODO / Tasks",n.tasks)),e.push(...y("Next actions",n.nextActions)),e.push(...y("Blockers",n.blockers)),e.push(...y("Important decisions",n.decisions)),e.push(...y("Active files",n.activeFiles??[])),e.push(...y("Modified files",n.modifiedFiles??[])),e.push(...y("Created files",n.createdFiles??[])),e.push(...y("Deleted files",n.deletedFiles??[])),e.push(...y("Files touched",n.filesTouched)),e.push(...y("Recent commands",n.commands??[])),e.push(...y("Checks",(n.checks??[]).map(t=>`[${t.status}] ${t.kind}: ${t.command}`))),e.push("","Progress:",`- Phases: ${n.progress.phasesCompleted}/${n.progress.phasesTotal}`,`- Tasks: ${n.progress.tasksCompleted}/${n.progress.tasksTotal}`,`- Blocked: ${n.progress.blocked}`,"","Continuation:","- Resume current unfinished task.","- Never redo completed TODO/Phase unless explicitly requested.","- Ask ToolNet Memory for deeper history only when necessary.",H),e.join(`
|
|
9
|
+
`)}function Ce(n,e){let t=Lt(n.rootPath,".toolnet","current.md"),r="";if($t(t))try{r=jt(t,"utf8")}catch{r=""}r=r.replace(/<!-- TOOLNET:AUTO-CURRENT:BEGIN -->[\s\S]*?<!-- TOOLNET:AUTO-CURRENT:END -->/gu,"");let o=Dt(e),s=r.indexOf(we),a=r.indexOf(H),m;s>=0&&a>=s?m=[r.slice(0,s).trimEnd(),o,r.slice(a+H.length).trimStart()].filter(Boolean).join(`
|
|
50
10
|
|
|
51
11
|
`):m=r.trim()?`${r.trim()}
|
|
52
12
|
|
|
53
|
-
${o}`:o,
|
|
54
|
-
`,{encoding:"utf8",mode:384})}function
|
|
55
|
-
`,{encoding:"utf8",mode:384})}function
|
|
56
|
-
`,"utf8");let s=
|
|
13
|
+
${o}`:o,Kt(t,`${m.trim()}
|
|
14
|
+
`,{encoding:"utf8",mode:384})}function x(n,e){return{id:e,name:e,rootPath:n,createdAt:"2026-08-13T16:00:00.000Z",updatedAt:"2026-08-13T16:00:00.000Z",graphVersion:1,memoryVersion:1}}function S(n){W(u(n,".toolnet","work"),{recursive:!0,mode:448}),W(u(n,".toolnet","context"),{recursive:!0,mode:448}),W(u(n,".toolnet","sessions"),{recursive:!0,mode:448})}function Y(n,e){W(u(n,".."),{recursive:!0}),T(n,JSON.stringify(e,null,2)+`
|
|
15
|
+
`,{encoding:"utf8",mode:384})}function D(n,e,t,r){Y(u(n.rootPath,".toolnet","context","session-origin.json"),{version:1,projectId:n.id,agent:"codex",nativeSessionId:"x2-origin",updatedAt:"2026-08-13T16:00:00.000Z",currentTask:e,currentPhase:"X2 Recovery",lastTouchedFile:t,latestNextAction:r})}function Q(n,e,t,r){let s={version:1,projectId:n.id,confidence:1,occurredAt:"2026-08-13T16:00:00.000Z",sequence:1,agent:"opencode",nativeSessionId:"x2-work",sessionKey:"opencode:x2-work"},a=de(n,[{...s,id:"x2-task-observation",kind:"task",key:"task:x2",text:e,status:"in_progress",order:1,eventId:"x2-task-event"},{...s,id:"x2-file-observation",kind:"file",key:"file:x2",text:t,eventId:"x2-file-event"},{...s,id:"x2-next-observation",kind:"next_action",key:"next:x2",text:r,eventId:"x2-next-event"}]);Ce(n,a)}function Te(n,e,t,r,o){return{continuity:{schema:"toolnet.handoff.v2",version:2,project:{id:n.id,name:n.name},source:{agent:"agy",nativeSessionId:"x2-handoff",sessionKey:"agy:x2-handoff",sequence:99,reason:"checkpoint"},capturedAt:"2026-08-13T16:00:00.000Z",current:{phase:{id:"x2",title:"X2 Recovery",status:"in_progress"},task:{id:"x2-task",title:e,status:"in_progress"},file:t},completed:{phases:["X1"],tasks:["X1 cross-agent continuity"]},remaining:{phases:["X2"],tasks:[e],todos:[r]},nextAction:o,blockers:[],decisions:["Canonical handoff must remain authoritative"],files:{current:t,recent:[t]},tests:{status:"passing",recent:["X1 PASS 4/4"]},attention:[],progress:{phasesTotal:3,phasesCompleted:1,tasksTotal:3,tasksCompleted:1,blocked:0},stateDigest:"a".repeat(64)}}}function zt(n){let e=u(n,".toolnet","context");for(let t of Wt(e)){let r=u(e,t);if(t.endsWith(".json"))try{if(JSON.parse(V(r,"utf8")).schema==="toolnet.memory-conversation.v1")return r}catch{}}return null}async function M(n,e,t){try{let r=await t();return{id:n,label:e,passed:r,detail:r?void 0:"Certification condition returned false."}}catch(r){return{id:n,label:e,passed:!1,detail:r instanceof Error?r.message:String(r)}}}async function Ae(){let n=[];n.push(await M("corrupt-handoff","corrupt handoff \u2192 safe fallback",()=>{let t=h(u(v(),"toolnet-x2-corrupt-handoff-"));try{let r=x(t,"x2-corrupt-handoff");S(t),T(u(t,".toolnet","work","handoff-latest.json"),"{ definitely broken","utf8"),D(r,"Recover task from session origin","src/x2/session-origin.ts","Continue safely");let o=k(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="session-origin"&&o.answer.includes("Recover task from session origin")}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("missing-handoff","missing handoff \u2192 WorkState fallback",()=>{let t=h(u(v(),"toolnet-x2-missing-handoff-"));try{let r=x(t,"x2-missing-handoff");S(t),Q(r,"Recover task from WorkState","src/x2/work-state.ts","Continue from WorkState");let o=k(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="work-state"&&o.answer.includes("Recover task from WorkState")}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("corrupt-session-origin","corrupt session-origin \u2192 WorkState fallback",()=>{let t=h(u(v(),"toolnet-x2-corrupt-origin-"));try{let r=x(t,"x2-corrupt-origin");S(t),T(u(t,".toolnet","context","session-origin.json"),"{ broken origin","utf8"),Q(r,"WorkState survives corrupt origin","src/x2/origin-fallback.ts","Use current WorkState");let o=k(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="work-state"&&o.answer.includes("WorkState survives corrupt origin")}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("corrupt-conversation","corrupt conversation \u2192 fresh clean state",()=>{let t=h(u(v(),"toolnet-x2-conversation-"));try{let r=x(t,"x2-conversation");S(t),D(r,"Conversation recovery task","src/x2/conversation.ts","Recover conversation"),B(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");let o=zt(t);if(!o)return!1;T(o,"{ broken conversation","utf8");let s=B(r,"R\u1ED3i sao?"),a=Se(r);return s.usedPriorFocus===!1&&a?.schema==="toolnet.memory-conversation.v1"&&a.projectId===r.id}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("corrupt-work-state","corrupt WorkState \u2192 safe empty answer",()=>{let t=h(u(v(),"toolnet-x2-workstate-"));try{let r=x(t,"x2-corrupt-workstate");S(t),T(u(t,".toolnet","work","current.json"),"{ broken work state","utf8");let o=k(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.source==="none"&&o.answer.includes("ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory")}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("ai-failure","AI/provider failure \u2192 deterministic local continuity",async()=>{let t=h(u(v(),"toolnet-x2-ai-"));try{let r=x(t,"x2-ai");S(t),D(r,"Deterministic AI outage fallback","src/x2/ai-fallback.ts","Continue without provider");let o=await ye(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return o.usedAi===!1&&o.answer.includes("Deterministic AI outage fallback")}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("canonical-priority","valid canonical handoff \u2192 stale fallback rejected",()=>{let t=h(u(v(),"toolnet-x2-priority-"));try{let r=x(t,"x2-priority");S(t);let o=u(t,".toolnet","work","handoff-latest.json");Y(o,Te(r,"CANONICAL X2 TASK","src/x2/canonical.ts","Canonical TODO","Canonical next action")),D(r,"STALE ORIGIN TASK","src/x2/stale-origin.ts","Stale origin next"),Q(r,"STALE WORKSTATE TASK","src/x2/stale-work.ts","Stale WorkState next");let s=k(r,"Task hi\u1EC7n t\u1EA1i l\xE0 g\xEC?");return s.source==="handoff"&&s.answer.includes("CANONICAL X2 TASK")&&!s.answer.includes("STALE ORIGIN TASK")&&!s.answer.includes("STALE WORKSTATE TASK")}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("memory-preserved","recovery read \u2192 valid handoff never destroyed",()=>{let t=h(u(v(),"toolnet-x2-preserve-"));try{let r=x(t,"x2-preserve");S(t);let o=u(t,".toolnet","work","handoff-latest.json");Y(o,Te(r,"Preserve canonical state","src/x2/preserve.ts","Preserve TODO","Preserve next action"));let s=V(o,"utf8");k(r,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?");let a=V(o,"utf8");return s===a}finally{b(t,{recursive:!0,force:!0})}})),n.push(await M("raw-transcript-isolation","raw transcript \u2192 never used for recovery",()=>{let t=h(u(v(),"toolnet-x2-transcript-"));try{let r=x(t,"x2-transcript");S(t);let o="X2_SECRET_RAW_TRANSCRIPT_MUST_NEVER_ENTER_CONTINUITY";T(u(t,".toolnet","sessions","raw-transcript.json"),JSON.stringify({transcript:o}),"utf8"),T(u(t,".toolnet","sessions","events.jsonl"),JSON.stringify({text:o})+`
|
|
16
|
+
`,"utf8");let s=k(r,"Agent tr\u01B0\u1EDBc \u0111ang l\xE0m g\xEC?");return s.source==="none"&&!s.answer.includes(o)}finally{b(t,{recursive:!0,force:!0})}}));let e=n.filter(t=>t.passed).length;return{passed:e===n.length,total:n.length,passedCount:e,checks:n}}async function qt(){let n=await Ae();console.log(""),console.log("\u25C7 ToolNet Recovery & Resilience Certification"),console.log("\u2502");for(let e of n.checks)console.log(`\u2502 ${e.passed?"\u2713":"\u2717"} ${e.label}`),!e.passed&&e.detail&&console.log(`\u2502 \u21B3 ${e.detail}`);if(console.log("\u2502"),n.passed){console.log(`\u25C6 PASS ${n.passedCount}/${n.total} recovery checks`);return}console.log(`\u25C6 FAIL ${n.passedCount}/${n.total} recovery checks`),process.exitCode=1}await qt();
|