toolnet-memory 0.2.20 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ import{existsSync as Ye,mkdirSync as We,readFileSync as Ue,renameSync as Qe,rmSync as Ze,writeFileSync as Xe}from"node:fs";import{isAbsolute as qe,join as re,relative as et}from"node:path";import{existsSync as ie,readFileSync as ae}from"node:fs";import{homedir as ce}from"node:os";import{join as ue}from"node:path";function de(e){let t=e.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 e=process.env.TOOLNET_GLOBAL_ENV??ue(ce(),".config","toolnet-memory",".env");if(!ie(e))return;let t=ae(e,"utf8");for(let n of t.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]=de(r.slice(o+1)))}}le();import{createHash as fe}from"node:crypto";import{existsSync as w,mkdirSync as pe,readFileSync as me,renameSync as ge,writeFileSync as ye}from"node:fs";import{basename as he,dirname as h,join as x,parse as _,resolve as g}from"node:path";var P=".toolnet",Se="project.json";function xe(e){return fe("sha256").update(e).digest("hex").slice(0,16)}function v(e){return x(e,P,Se)}function ke(e){return w(v(e))}function be(e,t){let n=g(e),r=_(n).root;for(;;){if(ke(n))return n;if(n===r||t&&n===g(t))break;let o=h(n);if(o===n)break;n=o}return null}function we(e){let t=g(e),n=_(t).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>w(x(t,s))))return t;if(t===n)break;let o=h(t);if(o===t)break;t=o}return g(e)}function ve(e){let t;try{t=JSON.parse(me(e,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${e}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${e}`);let n=t;if(typeof n.id!="string"||!n.id.trim())throw new Error(`ToolNet project manifest is missing id: ${e}`);if(typeof n.name!="string"||!n.name.trim())throw new Error(`ToolNet project manifest is missing name: ${e}`);let r=new Date().toISOString();return{version:1,id:n.id,name:n.name,remote:typeof n.remote=="string"&&n.remote.trim()?n.remote:n.name,rootPath:typeof n.rootPath=="string"?n.rootPath:h(h(e)),createdAt:typeof n.createdAt=="string"?n.createdAt:r,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:r,graphVersion:typeof n.graphVersion=="number"?n.graphVersion:0,memoryVersion:typeof n.memoryVersion=="number"?n.memoryVersion:0,metadata:n.metadata&&typeof n.metadata=="object"?n.metadata:void 0}}function j(e,t){let n=x(e,P);pe(n,{recursive:!0});let r=v(e),o=`${r}.tmp-${process.pid}`;ye(o,JSON.stringify(t,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),ge(o,r)}function I(e,t){return{id:e.id,name:e.name,remote:e.remote,rootPath:t,createdAt:e.createdAt,updatedAt:e.updatedAt,graphVersion:e.graphVersion,memoryVersion:e.memoryVersion,metadata:e.metadata}}var S=class{detect(t=process.cwd()){let n=g(t),r=we(n),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>w(x(r,p))),i=be(n,s?r:void 0);if(i){let p=v(i),l=ve(p);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),j(i,l)),I(l,i)}let c=new Date().toISOString(),a=he(r),u={version:1,id:xe(r),name:a,remote:a,rootPath:r,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return j(r,u),I(u,r)}};import*as f from"fs";import*as d from"path";function A(e){return e?Math.ceil(e.length/3.5):0}function Ae(e,t){if(!e)return"";if(A(e)<=t)return e;let r=Math.floor(t*3.5),o=e.slice(0,r),s=o.lastIndexOf("."),i=o.lastIndexOf(`
4
+ `),c=Math.max(s,i);return c>r*.7?o.slice(0,c+1):o}function N(e,t){if(!e)return"";let n=e.split(`
5
+ `).filter(s=>s.trim());if(n.length<=t)return e;let r=n.slice(0,t),o=n.length-t;return[...r,`... (${o} more items omitted)`].join(`
6
+ `)}function Ce(e,t){let{maxTokens:n,trimMarker:r="[Context trimmed by ToolNet Memory token budget]"}=t;if(e.length===0)return"";let o=[...e].sort((a,u)=>u.priority-a.priority),s=[],i=0,c=!1;for(let a of o){let u=`# ${a.title}
7
+
8
+ `,p=A(u),l=A(a.content),y=p+l;if(i+y<=n)s.push(u+a.content),i+=y;else{let m=n-i-p;if(m>50){let k=Ae(a.content,m);s.push(u+k),i=n,c=!0}else c=!0;break}}return c&&s.push(`
9
+ ${r}
10
+ `),s.join(`
11
+
12
+ ---
13
+
14
+ `)}function F(e,t){let n=[{title:"Profile",content:N(e,10),priority:100},{title:"Current Work",content:N(t,15),priority:90}];return Ce(n,{maxTokens:800})}import{chmodSync as Zt,existsSync as Me,mkdirSync as Xt,readFileSync as Ee,renameSync as qt,writeFileSync as en}from"node:fs";import{dirname as nn,join as $}from"node:path";var L="toolnet.context-offload.v1";function Re(e){return $(e,".toolnet","offload")}function Te(e){return $(Re(e),"graph.json")}function C(){return{schema:L,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function Oe(e){let t=Te(e);if(!Me(t))return C();try{let n=JSON.parse(Ee(t,"utf8"));return n.schema!==L||n.version!==1||!Array.isArray(n.nodes)?C():n}catch{return C()}}function D(e,t){let n=e.replace(/\s+/gu," ").trim();return n.length<=t?n:n.slice(0,t-1).trimEnd()+"\u2026"}function H(e,t={}){let n=Oe(e);if(n.nodes.length===0)return"";let r=Math.max(1,Math.min(12,t.maxAssets??6)),o=Math.max(320,Math.min(2400,t.maxChars??900)),s=["[TOOLNET CONTEXT OFFLOAD GRAPH]","Large tool/file payloads stay outside prompt context.","Read only a needed asset with MCP context_offload_read."];for(let i of n.nodes.slice(-r).reverse()){let c=D(i.sourceRefs.at(-1)??"unknown",72),a=i.files.length>0?` files=${D(i.files.join(","),120)}`:"",u=`event:${c} --offloads--> asset:${i.id.slice(0,12)} kind=${i.kind} bytes=${i.bytes}${a}`;if([...s,u].join(`
15
+ `).length>o)break;s.push(u)}return s.join(`
16
+ `)}import{existsSync as z,mkdirSync as Ie,readFileSync as V,renameSync as _e,writeFileSync as Pe}from"node:fs";import{dirname as Ne,join as G}from"node:path";import{createHash as je}from"node:crypto";function M(e){return je("sha256").update(e).digest("hex")}function B(e){return G(e.rootPath,".toolnet","context","handoff.md")}function J(e){return G(e.rootPath,".toolnet","context","handoff.json")}function K(e,t){Ie(Ne(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;Pe(n,t.endsWith(`
17
+ `)?t:`${t}
18
+ `,{encoding:"utf8",mode:384}),_e(n,e)}function Fe(e,t){K(e,`${JSON.stringify(t,null,2)}
19
+ `)}function Y(e,t){let n=t.replace(/\r\n/g,`
20
+ `).trim();if(!n)return null;let r={version:1,projectId:e.id,projectName:e.name,text:n,digest:M(n),generatedAt:new Date().toISOString()};return K(B(e),n),Fe(J(e),r),r}function E(e){let t=B(e);if(!z(t))return null;try{let n=V(t,"utf8").trim();if(!n)return null;let r=new Date(0).toISOString(),o=J(e);if(z(o))try{let s=JSON.parse(V(o,"utf8"));typeof s.generatedAt=="string"&&(r=s.generatedAt)}catch{}return{version:1,projectId:e.id,projectName:e.name,text:n,digest:M(n),generatedAt:r}}catch{return null}}function W(e,t=1800){let n=E(e);if(!n?.text)return null;let r=n.text;return r.length>t&&(r=`${r.slice(0,t)}
21
+
22
+ [Fast handoff truncated]`),["[TOOLNET FAST HANDOFF]","",`Project: ${e.name}`,`Updated: ${n.generatedAt}`,"",r].join(`
23
+ `)}var R="memory_agent_ask";function U(){return`
24
+ [TOOLNET MEMORY AGENT]
25
+
26
+ Tool:
27
+ - ${R}
28
+
29
+ For resume/continue requests:
30
+
31
+ 1. Use the injected ToolNet continuity handoff FIRST.
32
+ 2. If the handoff is missing or ambiguous, invoke
33
+ ${R} directly BEFORE repository/history exploration.
34
+ 3. NEVER reconstruct prior work from:
35
+ - .toolnet/sessions/**
36
+ - state.json
37
+ - events.jsonl
38
+ - raw transcripts
39
+ 4. NEVER search for the implementation/schema of
40
+ ${R}; invoke the MCP tool directly.
41
+ 5. Inspect git/source only AFTER continuity context is known.
42
+
43
+ Use:
44
+ - mode="local" for current task, last file, blocker or next action.
45
+ - mode="ai" for ambiguous or combined continuity questions.
46
+
47
+ Current repository evidence overrides stale memory.
48
+ `.trim()}function T(e){let t=d.resolve(e),n=d.parse(t).root;for(;t!==n;){let r=d.join(t,".toolnet");if(f.existsSync(r)&&f.statSync(r).isDirectory())return t;t=d.dirname(t)}return null}function Q(e){try{return f.existsSync(e)?f.readFileSync(e,"utf-8").trim():null}catch{return null}}function Z(e){return e.split(`
49
+ `).filter(r=>{let o=r.toUpperCase();return!(o.includes("SECRET")||o.includes("TOKEN")||o.includes("API_KEY")||o.includes("APIKEY")||o.includes("PASSWORD")||o.includes("PASS="))}).join(`
50
+ `)}function X(e={}){let t=e.projectPath||process.cwd(),n=T(t);if(!n)return null;let r=d.join(n,".toolnet","project.json"),o="Unknown";try{if(f.existsSync(r)){let b=JSON.parse(f.readFileSync(r,"utf-8"));o=b.name||b.projectName||"Unknown"}}catch{}let s=d.join(n,".toolnet","profile.md"),i=d.join(n,".toolnet","current.md"),c=Q(s)||"",a=Q(i)||"";c=Z(c),a=Z(a);let u=`[TOOLNET PROJECT CONTEXT]
51
+
52
+ Project: ${o}
53
+ Root: ${n}
54
+
55
+ `,p=F(c,a),l=W({id:"",name:o,rootPath:n},1600),y=l?`
56
+
57
+ ${l}
58
+ `:"",m=H(n,{maxAssets:6,maxChars:900}),k=m?`
59
+
60
+ ${m}
61
+ `:"",se=`
62
+
63
+ ${U()}
64
+
65
+ Forbidden At Startup:
66
+ - Do not run session:agy-recover, handoff:latest, or brief automatically.
67
+ - Do not perform deep recovery merely because an agent starts.
68
+ - If the user asks to resume previous work and fast context is insufficient,
69
+ use memory_agent_ask before guessing.
70
+ `;return u+p+y+k+se}import{existsSync as Ve,readFileSync as Ge}from"node:fs";import{join as Be}from"node:path";import{existsSync as De,mkdirSync as xn,readFileSync as $e,renameSync as kn,writeFileSync as bn}from"node:fs";import{dirname as vn,join as Le}from"node:path";function He(e){return Le(e.rootPath,".toolnet","context","session-origin.json")}function ze(e){let t=He(e);if(!De(t))return null;try{let n=JSON.parse($e(t,"utf8"));return n.version!==1||n.projectId!==e.id?null:n}catch{return null}}function q(e){let t=ze(e);if(!t)return null;let n=["Previous session:",`- Agent: ${t.agent}`,`- Session: ${t.nativeSessionId}`];return t.currentPhase&&n.push(`- Current phase: ${t.currentPhase}`),t.currentTask&&n.push(`- Current task: ${t.currentTask}`),t.lastTouchedFile&&n.push(`- Last touched file: ${t.lastTouchedFile}`),t.latestBlocker&&n.push(`- Blocker: ${t.latestBlocker}`),t.latestNextAction&&n.push(`- Next action: ${t.latestNextAction}`),t.latestDecision&&n.push(`- Important decision: ${t.latestDecision}`),n.join(`
71
+ `)}function Je(e){let t=Be(e.rootPath,".toolnet","current.md");if(!Ve(t))return null;try{return Ge(t,"utf8").trim()}catch{return null}}function Ke(e,t){let n=t.replace(/\r\n/g,`
72
+ `).trim(),r=2400,o=n.length>r?`${n.slice(0,r)}
73
+
74
+ [Current work truncated for fast handoff]`:n,s=q(e);return["# ToolNet Fast Handoff","",`Project: ${e.name}`,"",...s?[s,""]:[],o,"","---","","Continuation rule:","- Continue unfinished work; do not redo completed steps.","- Query ToolNet Memory only when deeper history is needed."].join(`
75
+ `)}function O(e){let t=Je(e);if(t===null)return{updated:!1,reason:"missing-current",chars:0};if(!t.trim())return{updated:!1,reason:"empty-current",chars:0};let n=Ke(e,t);return E(e)?.text.trim()===n.trim()?{updated:!1,reason:"unchanged",chars:n.length}:(Y(e,n),{updated:!0,reason:"updated",chars:n.length})}var ee=3200;function te(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function tt(e){return e.length<=ee?e:`${e.slice(0,ee)}
76
+
77
+ [ToolNet startup context truncated]`}function nt(e){let t=T(e);return t?new S().detect(t)??null:null}function rt(e){return re(e.rootPath,".toolnet","context","session-origin.json")}function ot(e,t){if(!qe(t))return t;let n=et(e.rootPath,t);return n.startsWith("..")?t:n}function ne(e,t){let n=rt(e),r={};if(Ye(n))try{let u=JSON.parse(Ue(n,"utf8"));te(u)&&u.projectId===e.id&&(r=u)}catch{}let o,s=t.tool_input;te(s)&&typeof s.file_path=="string"&&(o=ot(e,s.file_path));let i=typeof t.session_id=="string"?t.session_id:typeof r.nativeSessionId=="string"?r.nativeSessionId:"claude",c={...r,version:1,projectId:e.id,agent:"claude",nativeSessionId:i,updatedAt:new Date().toISOString()};o&&(c.lastTouchedFile=o),We(re(e.rootPath,".toolnet","context"),{recursive:!0,mode:448});let a=`${n}.tmp-${process.pid}-${Date.now()}`;try{Xe(a,JSON.stringify(c,null,2)+`
78
+ `,{encoding:"utf8",mode:384}),Qe(a,n)}finally{Ze(a,{force:!0})}}function oe(e){let t=typeof e.hook_event_name=="string"?e.hook_event_name:"",n=typeof e.cwd=="string"?e.cwd:"";if(!n)return{};let r=nt(n);if(!r)return{};try{if(t==="SessionStart"){let o=X({projectPath:n});return o?.trim()?{hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:tt(o)}}:{}}if(t==="PostToolUse"){ne(r,e);try{O(r)}catch{}return{}}if(t==="Stop"){ne(r,e);try{O(r)}catch{}return{}}return{}}catch{return{}}}async function st(){let e="";for await(let t of process.stdin)e+=t.toString();if(!e.trim())return{};try{return JSON.parse(e)}catch{return{}}}async function it(){let e=await st(),t=oe(e);process.stdout.write(JSON.stringify(t))}it().catch(()=>{process.stdout.write("{}"),process.exitCode=0});
@@ -0,0 +1,3 @@
1
+ import{existsSync as I,mkdirSync as v,readFileSync as J,renameSync as E,rmSync as N,writeFileSync as M}from"node:fs";import{dirname as $}from"node:path";import{homedir as y}from"node:os";import{join as g}from"node:path";function x(n={}){return g(n.home??y(),".claude")}function h(n={}){return g(x(n),"settings.json")}function C(n={}){return g(n.home??y(),".claude.json")}function l(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function A(n){return/^[A-Za-z0-9_./:-]+$/u.test(n)?n:`'${n.replace(/'/gu,"'\\''")}'`}function R(n){if(!I(n))return{};let t;try{t=JSON.parse(J(n,"utf8"))}catch(e){throw new Error(`Invalid existing Claude settings.json: ${e instanceof Error?e.message:String(e)}`)}if(!l(t))throw new Error("Invalid existing Claude settings.json: root must be a JSON object.");return t}function f(n){if(n===void 0)return[];if(!Array.isArray(n))throw new Error("Invalid existing Claude settings.json: hook event must be an array.");let t=[];for(let e of n){if(!l(e)){t.push(e);continue}let o=e.hooks;if(!Array.isArray(o)){t.push(e);continue}let s=o.filter(r=>{if(!l(r))return!0;let i=r.command;return!(typeof i=="string"&&i.includes("session:claude-hook"))});s.length!==0&&t.push({...e,hooks:s})}return t}function p(n){return{type:"command",command:n,timeout:10}}function T(n,t){v($(n),{recursive:!0,mode:448});let e=`${n}.toolnet-${process.pid}-${Date.now()}.tmp`;try{M(e,JSON.stringify(t,null,2)+`
2
+ `,{encoding:"utf8",mode:384}),E(e,n)}finally{N(e,{force:!0})}}function b(n={}){let t=n.settingsFile??h(),e=n.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=R(t),s=o.hooks;if(s!==void 0&&!l(s))throw new Error("Invalid existing Claude settings.json: hooks must be an object.");let r=l(s)?{...s}:{},i=`${A(e)} session:claude-hook`,a=f(r.SessionStart);a.push({matcher:"startup|resume|clear|compact",hooks:[p(i)]}),r.SessionStart=a;let d=f(r.PostToolUse);d.push({matcher:"Edit|Write",hooks:[p(i)]}),r.PostToolUse=d;let m=f(r.Stop);m.push({hooks:[p(i)]}),r.Stop=m;let c={...o,hooks:r},j=JSON.stringify(o),F=JSON.stringify(c);return j===F?{settingsFile:t,changed:!1}:(T(t,c),{settingsFile:t,changed:!0})}import{existsSync as H,mkdirSync as P,readFileSync as _,renameSync as U,rmSync as B,writeFileSync as D}from"node:fs";import{dirname as L}from"node:path";function u(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function O(n){if(!H(n))return{};let t;try{t=JSON.parse(_(n,"utf8"))}catch(e){throw new Error(`Invalid existing Claude Code config: ${e instanceof Error?e.message:String(e)}`)}if(!u(t))throw new Error("Invalid existing Claude Code config: root must be a JSON object.");return t}function S(n,t){if(!u(n))return!1;let e=n.args;return n.type==="stdio"&&n.command===t&&Array.isArray(e)&&e.length===1&&e[0]==="mcp"}function W(n,t){P(L(n),{recursive:!0});let e=`${n}.toolnet-${process.pid}-${Date.now()}.tmp`;try{D(e,JSON.stringify(t,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),U(e,n)}finally{B(e,{force:!0})}}function w(n={}){let t=n.stateFile??C(),e=n.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=n.serverName??"toolnet-memory",s=O(t),r=s.mcpServers;if(r!==void 0&&!u(r))throw new Error("Invalid existing Claude Code config: mcpServers must be an object.");let i=u(r)?{...r}:{},a=i[o];if(S(a,e))return{installed:!0,changed:!1,configFile:t,serverName:o,command:[e,"mcp"],repaired:!1};let d=a!==void 0;i[o]={type:"stdio",command:e,args:["mcp"]},W(t,{...s,mcpServers:i});let c=O(t).mcpServers;if(!u(c)||!S(c[o],e))throw new Error("Claude Code MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:t,serverName:o,command:[e,"mcp"],repaired:d}}function k(n={}){let t=n.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",e=b({binary:t,settingsFile:n.settingsFile}),o=w({binary:t,stateFile:n.stateFile});return{hooks:e,mcp:o,files:[e.settingsFile,o.configFile]}}function Y(){if((process.argv[2]??"install")!=="install")throw new Error("Usage: toolnet-memory integrate:claude");let t=k();console.log("\u2705 Claude Code integration installed"),console.log(`Hooks: ${t.hooks.settingsFile}`),console.log(`MCP: ${t.mcp.configFile}`),console.log("Server: toolnet-memory")}try{Y()}catch(n){console.error(n instanceof Error?n.message:String(n)),process.exitCode=1}
@@ -1,35 +1,37 @@
1
- import*as f from"fs";import*as u from"path";function w(e){return e?Math.ceil(e.length/3.5):0}function H(e,t){if(!e)return"";if(w(e)<=t)return e;let n=Math.floor(t*3.5),o=e.slice(0,n),s=o.lastIndexOf("."),i=o.lastIndexOf(`
2
- `),c=Math.max(s,i);return c>n*.7?o.slice(0,c+1):o}function b(e,t){if(!e)return"";let r=e.split(`
3
- `).filter(s=>s.trim());if(r.length<=t)return e;let n=r.slice(0,t),o=r.length-t;return[...n,`... (${o} more items omitted)`].join(`
4
- `)}function V(e,t){let{maxTokens:r,trimMarker:n="[Context trimmed by ToolNet Memory token budget]"}=t;if(e.length===0)return"";let o=[...e].sort((a,m)=>m.priority-a.priority),s=[],i=0,c=!1;for(let a of o){let m=`# ${a.title}
1
+ import*as f from"fs";import*as d from"path";function C(e){return e?Math.ceil(e.length/3.5):0}function Q(e,n){if(!e)return"";if(C(e)<=n)return e;let r=Math.floor(n*3.5),o=e.slice(0,r),s=o.lastIndexOf("."),i=o.lastIndexOf(`
2
+ `),a=Math.max(s,i);return a>r*.7?o.slice(0,a+1):o}function R(e,n){if(!e)return"";let t=e.split(`
3
+ `).filter(s=>s.trim());if(t.length<=n)return e;let r=t.slice(0,n),o=t.length-n;return[...r,`... (${o} more items omitted)`].join(`
4
+ `)}function Z(e,n){let{maxTokens:t,trimMarker:r="[Context trimmed by ToolNet Memory token budget]"}=n;if(e.length===0)return"";let o=[...e].sort((c,u)=>u.priority-c.priority),s=[],i=0,a=!1;for(let c of o){let u=`# ${c.title}
5
5
 
6
- `,d=w(m),p=w(a.content),h=d+p;if(i+h<=r)s.push(m+a.content),i+=h;else{let S=r-i-d;if(S>50){let g=H(a.content,S);s.push(m+g),i=r,c=!0}else c=!0;break}}return c&&s.push(`
7
- ${n}
6
+ `,p=C(u),l=C(c.content),h=p+l;if(i+h<=t)s.push(u+c.content),i+=h;else{let g=t-i-p;if(g>50){let b=Q(c.content,g);s.push(u+b),i=t,a=!0}else a=!0;break}}return a&&s.push(`
7
+ ${r}
8
8
  `),s.join(`
9
9
 
10
10
  ---
11
11
 
12
- `)}function C(e,t){let r=[{title:"Profile",content:b(e,10),priority:100},{title:"Current Work",content:b(t,15),priority:90}];return V(r,{maxTokens:800})}import{existsSync as M,mkdirSync as Ce,readFileSync as _,renameSync as ve,writeFileSync as Me}from"node:fs";import{dirname as je,join as j}from"node:path";import{createHash as Y}from"node:crypto";function v(e){return Y("sha256").update(e).digest("hex")}function U(e){return j(e.rootPath,".toolnet","context","handoff.md")}function G(e){return j(e.rootPath,".toolnet","context","handoff.json")}function J(e){let t=U(e);if(!M(t))return null;try{let r=_(t,"utf8").trim();if(!r)return null;let n=new Date(0).toISOString(),o=G(e);if(M(o))try{let s=JSON.parse(_(o,"utf8"));typeof s.generatedAt=="string"&&(n=s.generatedAt)}catch{}return{version:1,projectId:e.id,projectName:e.name,text:r,digest:v(r),generatedAt:n}}catch{return null}}function O(e,t=1800){let r=J(e);if(!r?.text)return null;let n=r.text;return n.length>t&&(n=`${n.slice(0,t)}
12
+ `)}function T(e,n){let t=[{title:"Profile",content:R(e,10),priority:100},{title:"Current Work",content:R(n,15),priority:90}];return Z(t,{maxTokens:800})}import{chmodSync as Fe,existsSync as X,mkdirSync as $e,readFileSync as q,renameSync as Le,writeFileSync as ze}from"node:fs";import{dirname as Ve,join as _}from"node:path";var I="toolnet.context-offload.v1";function ee(e){return _(e,".toolnet","offload")}function te(e){return _(ee(e),"graph.json")}function E(){return{schema:I,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function ne(e){let n=te(e);if(!X(n))return E();try{let t=JSON.parse(q(n,"utf8"));return t.schema!==I||t.version!==1||!Array.isArray(t.nodes)?E():t}catch{return E()}}function O(e,n){let t=e.replace(/\s+/gu," ").trim();return t.length<=n?t:t.slice(0,n-1).trimEnd()+"\u2026"}function j(e,n={}){let t=ne(e);if(t.nodes.length===0)return"";let r=Math.max(1,Math.min(12,n.maxAssets??6)),o=Math.max(320,Math.min(2400,n.maxChars??900)),s=["[TOOLNET CONTEXT OFFLOAD GRAPH]","Large tool/file payloads stay outside prompt context.","Read only a needed asset with MCP context_offload_read."];for(let i of t.nodes.slice(-r).reverse()){let a=O(i.sourceRefs.at(-1)??"unknown",72),c=i.files.length>0?` files=${O(i.files.join(","),120)}`:"",u=`event:${a} --offloads--> asset:${i.id.slice(0,12)} kind=${i.kind} bytes=${i.bytes}${c}`;if([...s,u].join(`
13
+ `).length>o)break;s.push(u)}return s.join(`
14
+ `)}import{existsSync as P,mkdirSync as Je,readFileSync as D,renameSync as Ue,writeFileSync as We}from"node:fs";import{dirname as Ze,join as F}from"node:path";import{createHash as re}from"node:crypto";function N(e){return re("sha256").update(e).digest("hex")}function oe(e){return F(e.rootPath,".toolnet","context","handoff.md")}function se(e){return F(e.rootPath,".toolnet","context","handoff.json")}function ie(e){let n=oe(e);if(!P(n))return null;try{let t=D(n,"utf8").trim();if(!t)return null;let r=new Date(0).toISOString(),o=se(e);if(P(o))try{let s=JSON.parse(D(o,"utf8"));typeof s.generatedAt=="string"&&(r=s.generatedAt)}catch{}return{version:1,projectId:e.id,projectName:e.name,text:t,digest:N(t),generatedAt:r}}catch{return null}}function $(e,n=1800){let t=ie(e);if(!t?.text)return null;let r=t.text;return r.length>n&&(r=`${r.slice(0,n)}
13
15
 
14
- [Fast handoff truncated]`),["[TOOLNET FAST HANDOFF]","",`Project: ${e.name}`,`Updated: ${r.generatedAt}`,"",n].join(`
15
- `)}var A="memory_agent_ask";function I(){return`
16
+ [Fast handoff truncated]`),["[TOOLNET FAST HANDOFF]","",`Project: ${e.name}`,`Updated: ${t.generatedAt}`,"",r].join(`
17
+ `)}var k="memory_agent_ask";function L(){return`
16
18
  [TOOLNET MEMORY AGENT]
17
19
 
18
20
  Tool:
19
- - ${A}
21
+ - ${k}
20
22
 
21
23
  For resume/continue requests:
22
24
 
23
25
  1. Use the injected ToolNet continuity handoff FIRST.
24
26
  2. If the handoff is missing or ambiguous, invoke
25
- ${A} directly BEFORE repository/history exploration.
27
+ ${k} directly BEFORE repository/history exploration.
26
28
  3. NEVER reconstruct prior work from:
27
29
  - .toolnet/sessions/**
28
30
  - state.json
29
31
  - events.jsonl
30
32
  - raw transcripts
31
33
  4. NEVER search for the implementation/schema of
32
- ${A}; invoke the MCP tool directly.
34
+ ${k}; invoke the MCP tool directly.
33
35
  5. Inspect git/source only AFTER continuity context is known.
34
36
 
35
37
  Use:
@@ -37,28 +39,31 @@ Use:
37
39
  - mode="ai" for ambiguous or combined continuity questions.
38
40
 
39
41
  Current repository evidence overrides stale memory.
40
- `.trim()}function W(e){let t=u.resolve(e),r=u.parse(t).root;for(;t!==r;){let n=u.join(t,".toolnet");if(f.existsSync(n)&&f.statSync(n).isDirectory())return t;t=u.dirname(t)}return null}function N(e){try{return f.existsSync(e)?f.readFileSync(e,"utf-8").trim():null}catch{return null}}function P(e){return e.split(`
41
- `).filter(n=>{let o=n.toUpperCase();return!(o.includes("SECRET")||o.includes("TOKEN")||o.includes("API_KEY")||o.includes("APIKEY")||o.includes("PASSWORD")||o.includes("PASS="))}).join(`
42
- `)}function F(e={}){let t=e.projectPath||process.cwd(),r=W(t);if(!r)return null;let n=u.join(r,".toolnet","project.json"),o="Unknown";try{if(f.existsSync(n)){let g=JSON.parse(f.readFileSync(n,"utf-8"));o=g.name||g.projectName||"Unknown"}}catch{}let s=u.join(r,".toolnet","profile.md"),i=u.join(r,".toolnet","current.md"),c=N(s)||"",a=N(i)||"";c=P(c),a=P(a);let m=`[TOOLNET PROJECT CONTEXT]
42
+ `.trim()}function ae(e){let n=d.resolve(e),t=d.parse(n).root;for(;n!==t;){let r=d.join(n,".toolnet");if(f.existsSync(r)&&f.statSync(r).isDirectory())return n;n=d.dirname(n)}return null}function z(e){try{return f.existsSync(e)?f.readFileSync(e,"utf-8").trim():null}catch{return null}}function G(e){return e.split(`
43
+ `).filter(r=>{let o=r.toUpperCase();return!(o.includes("SECRET")||o.includes("TOKEN")||o.includes("API_KEY")||o.includes("APIKEY")||o.includes("PASSWORD")||o.includes("PASS="))}).join(`
44
+ `)}function V(e={}){let n=e.projectPath||process.cwd(),t=ae(n);if(!t)return null;let r=d.join(t,".toolnet","project.json"),o="Unknown";try{if(f.existsSync(r)){let A=JSON.parse(f.readFileSync(r,"utf-8"));o=A.name||A.projectName||"Unknown"}}catch{}let s=d.join(t,".toolnet","profile.md"),i=d.join(t,".toolnet","current.md"),a=z(s)||"",c=z(i)||"";a=G(a),c=G(c);let u=`[TOOLNET PROJECT CONTEXT]
43
45
 
44
46
  Project: ${o}
45
- Root: ${r}
47
+ Root: ${t}
46
48
 
47
- `,d=C(c,a),p=O({id:"",name:o,rootPath:r},1600),h=p?`
49
+ `,p=T(a,c),l=$({id:"",name:o,rootPath:t},1600),h=l?`
48
50
 
49
- ${p}
50
- `:"",S=`
51
+ ${l}
52
+ `:"",g=j(t,{maxAssets:6,maxChars:900}),b=g?`
51
53
 
52
- ${I()}
54
+ ${g}
55
+ `:"",W=`
56
+
57
+ ${L()}
53
58
 
54
59
  Forbidden At Startup:
55
60
  - Do not run session:agy-recover, handoff:latest, or brief automatically.
56
61
  - Do not perform deep recovery merely because an agent starts.
57
62
  - If the user asks to resume previous work and fast context is insufficient,
58
63
  use memory_agent_ask before guessing.
59
- `;return m+d+h+S}import{existsSync as le}from"node:fs";import{dirname as ge,join as ye,parse as he,resolve as Se}from"node:path";import{existsSync as Z,readFileSync as X}from"node:fs";import{homedir as q}from"node:os";import{join as Q}from"node:path";function ee(e){let t=e.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
60
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function te(){let e=process.env.TOOLNET_GLOBAL_ENV??Q(q(),".config","toolnet-memory",".env");if(!Z(e))return;let t=X(e,"utf8");for(let r of t.split(/\r?\n/)){let n=r.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=ee(n.slice(o+1)))}}te();import{createHash as re}from"node:crypto";import{existsSync as R,mkdirSync as ne,readFileSync as oe,renameSync as se,writeFileSync as ie}from"node:fs";import{basename as ce,dirname as x,join as E,parse as $,resolve as y}from"node:path";var z=".toolnet",ae="project.json";function ue(e){return re("sha256").update(e).digest("hex").slice(0,16)}function k(e){return E(e,z,ae)}function me(e){return R(k(e))}function pe(e,t){let r=y(e),n=$(r).root;for(;;){if(me(r))return r;if(r===n||t&&r===y(t))break;let o=x(r);if(o===r)break;r=o}return null}function fe(e){let t=y(e),r=$(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>R(E(t,s))))return t;if(t===r)break;let o=x(t);if(o===t)break;t=o}return y(e)}function de(e){let t;try{t=JSON.parse(oe(e,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${e}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${e}`);let r=t;if(typeof r.id!="string"||!r.id.trim())throw new Error(`ToolNet project manifest is missing id: ${e}`);if(typeof r.name!="string"||!r.name.trim())throw new Error(`ToolNet project manifest is missing name: ${e}`);let n=new Date().toISOString();return{version:1,id:r.id,name:r.name,remote:typeof r.remote=="string"&&r.remote.trim()?r.remote:r.name,rootPath:typeof r.rootPath=="string"?r.rootPath:x(x(e)),createdAt:typeof r.createdAt=="string"?r.createdAt:n,updatedAt:typeof r.updatedAt=="string"?r.updatedAt:n,graphVersion:typeof r.graphVersion=="number"?r.graphVersion:0,memoryVersion:typeof r.memoryVersion=="number"?r.memoryVersion:0,metadata:r.metadata&&typeof r.metadata=="object"?r.metadata:void 0}}function D(e,t){let r=E(e,z);ne(r,{recursive:!0});let n=k(e),o=`${n}.tmp-${process.pid}`;ie(o,JSON.stringify(t,null,2)+`
61
- `,{encoding:"utf8",mode:384}),se(o,n)}function L(e,t){return{id:e.id,name:e.name,remote:e.remote,rootPath:t,createdAt:e.createdAt,updatedAt:e.updatedAt,graphVersion:e.graphVersion,memoryVersion:e.memoryVersion,metadata:e.metadata}}var T=class{detect(t=process.cwd()){let r=y(t),n=fe(r),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>R(E(n,d))),i=pe(r,s?n:void 0);if(i){let d=k(i),p=de(d);return p.rootPath!==i&&(p.rootPath=i,p.updatedAt=new Date().toISOString(),D(i,p)),L(p,i)}let c=new Date().toISOString(),a=ce(n),m={version:1,id:ue(n),name:a,remote:a,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return D(n,m),L(m,n)}};function K(e){let t=Se(e),r=he(t).root;for(;;){if(le(ye(t,".toolnet","project.json")))return new T().detect(t);if(t===r)break;let n=ge(t);if(n===t)break;t=n}return null}var B=3200;async function xe(){let e="";for await(let t of process.stdin)e+=t.toString();if(!e.trim())return{};try{return JSON.parse(e)}catch{return{}}}function l(){process.stdout.write("{}")}function Te(e){return e.length<=B?e:`${e.slice(0,B)}
64
+ `;return u+p+h+b+W}import{existsSync as ve}from"node:fs";import{dirname as Me,join as Re,parse as Te,resolve as Oe}from"node:path";import{existsSync as ce,readFileSync as ue}from"node:fs";import{homedir as de}from"node:os";import{join as le}from"node:path";function fe(e){let n=e.trim();return n.length>=2&&n.startsWith('"')&&n.endsWith('"')?(n=n.slice(1,-1),n.replace(/\\n/g,`
65
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):n.length>=2&&n.startsWith("'")&&n.endsWith("'")?n.slice(1,-1):n}function pe(){let e=process.env.TOOLNET_GLOBAL_ENV??le(de(),".config","toolnet-memory",".env");if(!ce(e))return;let n=ue(e,"utf8");for(let t of n.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]=fe(r.slice(o+1)))}}pe();import{createHash as me}from"node:crypto";import{existsSync as v,mkdirSync as ge,readFileSync as ye,renameSync as he,writeFileSync as Se}from"node:fs";import{basename as xe,dirname as S,join as w,parse as K,resolve as y}from"node:path";var Y=".toolnet",we="project.json";function be(e){return me("sha256").update(e).digest("hex").slice(0,16)}function M(e){return w(e,Y,we)}function Ae(e){return v(M(e))}function Ce(e,n){let t=y(e),r=K(t).root;for(;;){if(Ae(t))return t;if(t===r||n&&t===y(n))break;let o=S(t);if(o===t)break;t=o}return null}function Ee(e){let n=y(e),t=K(n).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>v(w(n,s))))return n;if(n===t)break;let o=S(n);if(o===n)break;n=o}return y(e)}function ke(e){let n;try{n=JSON.parse(ye(e,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${e}: ${o instanceof Error?o.message:String(o)}`)}if(!n||typeof n!="object")throw new Error(`Invalid ToolNet project manifest: ${e}`);let t=n;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${e}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${e}`);let r=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:S(S(e)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function H(e,n){let t=w(e,Y);ge(t,{recursive:!0});let r=M(e),o=`${r}.tmp-${process.pid}`;Se(o,JSON.stringify(n,null,2)+`
66
+ `,{encoding:"utf8",mode:384}),he(o,r)}function B(e,n){return{id:e.id,name:e.name,remote:e.remote,rootPath:n,createdAt:e.createdAt,updatedAt:e.updatedAt,graphVersion:e.graphVersion,memoryVersion:e.memoryVersion,metadata:e.metadata}}var x=class{detect(n=process.cwd()){let t=y(n),r=Ee(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>v(w(r,p))),i=Ce(t,s?r:void 0);if(i){let p=M(i),l=ke(p);return l.rootPath!==i&&(l.rootPath=i,l.updatedAt=new Date().toISOString(),H(i,l)),B(l,i)}let a=new Date().toISOString(),c=xe(r),u={version:1,id:be(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return H(r,u),B(u,r)}};function J(e){let n=Oe(e),t=Te(n).root;for(;;){if(ve(Re(n,".toolnet","project.json")))return new x().detect(n);if(n===t)break;let r=Me(n);if(r===n)break;n=r}return null}var U=3200;async function _e(){let e="";for await(let n of process.stdin)e+=n.toString();if(!e.trim())return{};try{return JSON.parse(e)}catch{return{}}}function m(){process.stdout.write("{}")}function Ie(e){return e.length<=U?e:`${e.slice(0,U)}
62
67
 
63
- [ToolNet startup context truncated]`}function Ee(e,t,r){if(process.env.TOOLNET_CODEX_STARTUP_DEBUG!=="1")return;let n=Date.now()-e;process.stderr.write(`[toolnet-memory] codex SessionStart ${n}ms cwd=${t} chars=${r}
64
- `)}async function we(){let e=Date.now(),t=await xe();if(t.hook_event_name!=="SessionStart"){l();return}let r=typeof t.cwd=="string"?t.cwd:"";if(!r){l();return}if(!K(r)){l();return}try{let o=F({projectPath:r});if(!o?.trim()){l();return}let s=Te(o),i={hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s}};Ee(e,r,s.length),process.stdout.write(JSON.stringify(i))}catch{l()}}we().catch(()=>{l(),process.exitCode=0});
68
+ [ToolNet startup context truncated]`}function je(e,n,t){if(process.env.TOOLNET_CODEX_STARTUP_DEBUG!=="1")return;let r=Date.now()-e;process.stderr.write(`[toolnet-memory] codex SessionStart ${r}ms cwd=${n} chars=${t}
69
+ `)}async function Ne(){let e=Date.now(),n=await _e();if(n.hook_event_name!=="SessionStart"){m();return}let t=typeof n.cwd=="string"?n.cwd:"";if(!t){m();return}if(!J(t)){m();return}try{let o=V({projectPath:t});if(!o?.trim()){m();return}let s=Ie(o),i={hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s}};je(e,t,s.length),process.stdout.write(JSON.stringify(i))}catch{m()}}Ne().catch(()=>{m(),process.exitCode=0});