toolnet-memory 0.2.15 → 0.2.17

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.
@@ -1,5 +1,51 @@
1
- import{existsSync as g}from"node:fs";import{homedir as h}from"node:os";import{join as x}from"node:path";import{spawnSync as ee}from"node:child_process";import{existsSync as _,mkdirSync as M,readFileSync as F,writeFileSync as P}from"node:fs";import{homedir as $}from"node:os";import{dirname as D,join as H}from"node:path";function L(o){return`'${o.replace(/'/g,"'\\''")}'`}function O(o={}){let t=o.hooksFile??H($(),".gemini","config","hooks.json");M(D(t),{recursive:!0});let e={};if(_(t))try{e=JSON.parse(F(t,"utf8"))}catch(a){throw new Error(`Invalid existing Agy hooks.json: ${a instanceof Error?a.message:String(a)}`)}let r=o.binary??"toolnet-memory",n=`${L(r)} session:agy-hook`;return e["toolnet-memory"]={enabled:!0,PreInvocation:[{type:"command",command:`${n} pre`,timeout:15}],PostInvocation:[{type:"command",command:`${n} post`,timeout:15}],Stop:[{type:"command",command:`${n} stop`,timeout:30}]},P(t,JSON.stringify(e,null,2)+`
2
- `,{encoding:"utf8",mode:384}),t}import{existsSync as B,mkdirSync as I,readFileSync as J,writeFileSync as T}from"node:fs";import{homedir as m}from"node:os";import{join as p}from"node:path";var C="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",f="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function Y(){let o=p(m(),".config","opencode","AGENTS.md");I(p(m(),".config","opencode"),{recursive:!0});let t=`${C}
1
+ import{existsSync as O}from"node:fs";import{homedir as C}from"node:os";import{join as w}from"node:path";import{spawnSync as _e}from"node:child_process";import{existsSync as K,mkdirSync as V,readFileSync as z,writeFileSync as Q}from"node:fs";import{homedir as Z}from"node:os";import{dirname as ee,join as te}from"node:path";function ne(e){return`'${e.replace(/'/g,"'\\''")}'`}function N(e={}){let n=e.hooksFile??te(Z(),".gemini","config","hooks.json");V(ee(n),{recursive:!0});let t={};if(K(n))try{t=JSON.parse(z(n,"utf8"))}catch(s){throw new Error(`Invalid existing Agy hooks.json: ${s instanceof Error?s.message:String(s)}`)}let o=e.binary??"toolnet-memory",r=`${ne(o)} session:agy-hook`;return t["toolnet-memory"]={enabled:!0,PreInvocation:[{type:"command",command:`${r} pre`,timeout:15}],PostInvocation:[{type:"command",command:`${r} post`,timeout:15}],Stop:[{type:"command",command:`${r} stop`,timeout:30}]},Q(n,JSON.stringify(t,null,2)+`
2
+ `,{encoding:"utf8",mode:384}),n}import{existsSync as oe,mkdirSync as re,readFileSync as se,renameSync as ie,writeFileSync as ce}from"node:fs";import{homedir as ae}from"node:os";import{dirname as le,join as de}from"node:path";function p(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function ue(e,n){re(le(e),{recursive:!0});let t=`${e}.tmp-${process.pid}-${Date.now()}`;ce(t,`${JSON.stringify(n,null,2)}
3
+ `,{encoding:"utf8",mode:384}),ie(t,e)}function I(e){if(!oe(e))return{};let n=se(e,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(o){throw new Error(`Invalid existing Agy MCP config: ${o instanceof Error?o.message:String(o)}`)}if(!p(t))throw new Error("Invalid existing Agy MCP config: root must be a JSON object.");return t}function T(e,n){return p(e)?e.command===n&&Array.isArray(e.args)&&e.args.length===1&&e.args[0]==="mcp":!1}function k(e={}){let n=e.configFile??de(ae(),".gemini","config","mcp_config.json"),t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",r=I(n),s=r.mcpServers;if(s!==void 0&&!p(s))throw new Error("Invalid existing Agy MCP config: mcpServers must be an object.");let i=p(s)?{...s}:{},c=i[o];if(T(c,t))return{installed:!0,changed:!1,configFile:n,serverName:o,command:t,args:["mcp"]};i[o]={command:t,args:["mcp"]};let d={...r,mcpServers:i};ue(n,d);let l=I(n).mcpServers;if(!p(l)||!T(l[o],t))throw new Error("Agy MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:n,serverName:o,command:t,args:["mcp"]}}import{existsSync as pe,mkdirSync as M,readFileSync as fe,writeFileSync as A}from"node:fs";import{homedir as x}from"node:os";import{join as g}from"node:path";var me="memory_agent_ask";function E(){return`
4
+ [TOOLNET MEMORY AGENT]
5
+
6
+ Tool available:
7
+ - ${me}
8
+
9
+ Use it automatically BEFORE guessing when:
10
+
11
+ - The user asks to continue, resume, or pick up previous work.
12
+ - The user says things like:
13
+ - "ti\u1EBFp t\u1EE5c task l\xFAc n\xE3y"
14
+ - "l\xE0m ti\u1EBFp ph\u1EA7n \u0111ang d\u1EDF"
15
+ - "agent tr\u01B0\u1EDBc \u0111ang l\xE0m g\xEC?"
16
+ - "d\u1EEBng \u1EDF \u0111\xE2u?"
17
+ - "todo n\xE0o ch\u01B0a xong?"
18
+ - "continue the previous task"
19
+ - "resume the last session"
20
+ - Previous-agent state, unfinished work, blockers,
21
+ decisions, touched files, or next actions are unclear.
22
+ - Fast startup context is not enough to safely continue.
23
+
24
+ Preferred mode:
25
+
26
+ - mode="local"
27
+ for direct factual questions such as:
28
+ current task, last file, blocker, completed TODOs.
29
+
30
+ - mode="ai"
31
+ for composite or ambiguous continuity questions
32
+ that benefit from ToolNet Memory Agent reasoning.
33
+
34
+ Do NOT call it automatically when:
35
+
36
+ - Normal startup context already gives enough information.
37
+ - The question is unrelated to previous project work.
38
+ - The answer is obvious from current repository evidence.
39
+
40
+ Rules:
41
+
42
+ - Never invent previous work.
43
+ - Current repository evidence overrides stale memory.
44
+ - Do not dump raw transcripts or full memory.
45
+ - After receiving the ToolNet answer, continue the task
46
+ instead of asking the user to repeat known context.
47
+ - If ToolNet says information is not recorded, say so.
48
+ `.trim()}var j="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",h="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function ge(){let e=g(x(),".config","opencode","AGENTS.md");M(g(x(),".config","opencode"),{recursive:!0});let n=`${j}
3
49
  ## ToolNet Memory
4
50
 
5
51
  ToolNet Memory is available for projects that already contain a valid \`.toolnet/project.json\`.
@@ -14,10 +60,13 @@ Rules:
14
60
  6. Raw transcripts must not be injected into prompts.
15
61
  7. Current repository evidence has priority over stale memory when they conflict.
16
62
 
17
- ${f}`,e=B(o)?J(o,"utf8"):"",r=e.indexOf(C),n=e.indexOf(f);return r>=0&&n>=r?e=e.slice(0,r)+t+e.slice(n+f.length):(e=e.trimEnd(),e&&(e+=`
18
63
 
19
- `),e+=t),T(o,e.trimEnd()+`
20
- `,{encoding:"utf8",mode:384}),o}function N(o={}){let t=o.directory??p(m(),".config","opencode","plugins");I(t,{recursive:!0}),Y();let e=p(t,"toolnet-memory.js"),r=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=`
64
+ ${E()}
65
+
66
+ ${h}`,t=pe(e)?fe(e,"utf8"):"",o=t.indexOf(j),r=t.indexOf(h);return o>=0&&r>=o?t=t.slice(0,o)+n+t.slice(r+h.length):(t=t.trimEnd(),t&&(t+=`
67
+
68
+ `),t+=n),A(e,t.trimEnd()+`
69
+ `,{encoding:"utf8",mode:384}),e}function R(e={}){let n=e.directory??g(x(),".config","opencode","plugins");M(n,{recursive:!0}),ge();let t=g(n,"toolnet-memory.js"),o=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",r=`
21
70
  // Generated by ToolNet Memory.
22
71
  // OpenCode integration:
23
72
  // - project gated
@@ -31,7 +80,7 @@ import path from "node:path"
31
80
  import os from "node:os"
32
81
 
33
82
  const TOOLNET_BINARY =
34
- ${JSON.stringify(r)}
83
+ ${JSON.stringify(o)}
35
84
 
36
85
  const CONTEXT_MAX_TOKENS = 700
37
86
 
@@ -645,11 +694,12 @@ export const ToolNetMemoryPlugin =
645
694
  },
646
695
  }
647
696
  }
648
- `;return T(e,n.trimStart(),{encoding:"utf8",mode:384}),e}import{existsSync as X,mkdirSync as w,readFileSync as q,writeFileSync as k}from"node:fs";import{homedir as E}from"node:os";import{dirname as j,join as y}from"node:path";function U(o){let t=[],e=/"((?:\\.|[^"\\])*)"|'([^']*)'/g,r;for(;r=e.exec(o);){let n=r[1]??r[2]??"";try{t.push(r[1]!==void 0?JSON.parse(`"${n}"`):n)}catch{t.push(n)}}return t}function b(o={}){let t=o.configFile??y(process.env.CODEX_HOME??y(E(),".codex"),"config.toml"),e=o.previousFile??y(E(),".config","toolnet-memory","codex-notify-previous.json");w(j(t),{recursive:!0}),w(j(e),{recursive:!0});let r=X(t)?q(t,"utf8"):"",n=o.binary??"toolnet-memory",a=`notify = [${JSON.stringify(n)}, "session:codex-notify"]`,s=r.split(`
649
- `),i=s.findIndex(c=>/^\s*\[/.test(c));i<0&&(i=s.length);let u=-1,d=-1;for(let c=0;c<i;c+=1)if(/^\s*notify\s*=/.test(s[c])){if(u=c,d=c,s[c].includes("[")&&!s[c].includes("]"))for(;d+1<i&&(d+=1,!s[d].includes("]")););break}let l=[];if(u>=0){let c=s.slice(u,d+1).join(`
650
- `);l=U(c),s.splice(u,d-u+1,a)}else i=s.findIndex(c=>/^\s*\[/.test(c)),i<0&&(i=s.length),s.splice(i,0,a);let v=l.length>=2&&l[l.length-1]==="session:codex-notify";return l.length>0&&!v&&k(e,JSON.stringify(l,null,2)+`
651
- `,{encoding:"utf8",mode:384}),r=s.join(`
652
- `),r.endsWith(`
653
- `)||(r+=`
654
- `),k(t,r,{encoding:"utf8",mode:384}),{configFile:t,previousFile:e,preservedPrevious:l.length>0&&!v}}import{existsSync as W,mkdirSync as G,readFileSync as K,writeFileSync as V}from"node:fs";import{homedir as z}from"node:os";import{dirname as Q,join as A}from"node:path";function Z(o){return`'${o.replace(/'/g,"'\\''")}'`}function R(o={}){let t=o.hooksFile??A(process.env.CODEX_HOME??A(z(),".codex"),"hooks.json");G(Q(t),{recursive:!0});let e={};if(W(t))try{e=JSON.parse(K(t,"utf8"))}catch(i){throw new Error(`Invalid existing Codex hooks.json: ${i instanceof Error?i.message:String(i)}`)}let r=e.hooks&&typeof e.hooks=="object"&&!Array.isArray(e.hooks)?e.hooks:{};e.hooks=r;let a=(Array.isArray(r.SessionStart)?r.SessionStart:[]).filter(i=>{try{return!JSON.stringify(i).includes("session:codex-context")}catch{return!0}}),s=o.binary??"toolnet-memory";return a.push({matcher:"startup|resume|clear|compact",hooks:[{type:"command",command:`${Z(s)} session:codex-context`,timeout:15,additionalContextLimit:1e3,statusMessage:"Loading ToolNet project continuity"}]}),r.SessionStart=a,V(t,JSON.stringify(e,null,2)+`
655
- `,{encoding:"utf8",mode:384}),t}function S(o){return ee("sh",["-lc",`command -v ${JSON.stringify(o)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function te(){return S("agy")||g(x(h(),".gemini"))}function oe(){return S("opencode")||g(x(h(),".config","opencode"))}function ne(){return S("codex")||g(process.env.CODEX_HOME??x(h(),".codex"))}function re(o={}){let t=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",e=[];if(!(o.force===!0||te()))e.push({agent:"agy",detected:!1,installed:!1,targets:[]});else try{let n=O({binary:t});e.push({agent:"agy",detected:!0,installed:!0,targets:[n]})}catch(n){e.push({agent:"agy",detected:!0,installed:!1,targets:[],error:n instanceof Error?n.message:String(n)})}if(!(o.force===!0||oe()))e.push({agent:"opencode",detected:!1,installed:!1,targets:[]});else try{let n=N({binary:t});e.push({agent:"opencode",detected:!0,installed:!0,targets:[n]})}catch(n){e.push({agent:"opencode",detected:!0,installed:!1,targets:[],error:n instanceof Error?n.message:String(n)})}if(!(o.force===!0||ne()))e.push({agent:"codex",detected:!1,installed:!1,targets:[]});else try{let n=b({binary:t}),a=R({binary:t}),s=[n.configFile,a];n.preservedPrevious&&s.push(n.previousFile),e.push({agent:"codex",detected:!0,installed:!0,targets:s})}catch(n){e.push({agent:"codex",detected:!0,installed:!1,targets:[],error:n instanceof Error?n.message:String(n)})}return e}function se(o){console.log(""),console.log("ToolNet Memory AI Integrations"),console.log("=============================="),console.log("");for(let t of o){let e=t.agent==="agy"?"Agy / Antigravity":t.agent==="opencode"?"OpenCode":"Codex";if(!t.detected){console.log(`- ${e}: not detected`);continue}if(t.installed){console.log(`\u2713 ${e}: automatic memory enabled`);continue}console.log(`\u2717 ${e}: integration failed`),t.error&&console.log(` ${t.error}`)}console.log("")}async function ie(){let o=process.argv.slice(2),t=o.includes("--all"),e=o.includes("--json"),r=re({force:t});if(e){console.log(JSON.stringify(r,null,2));return}se(r)}var ce=process.argv[1]&&(process.argv[1].endsWith("auto-integrate.js")||process.argv[1].endsWith("auto-integrate.ts"));ce&&ie().catch(o=>{console.error(o instanceof Error?o.message:String(o)),process.exitCode=1});export{re as installAutoIntegrations};
697
+ `;return A(t,r.trimStart(),{encoding:"utf8",mode:384}),t}import{existsSync as $,mkdirSync as ye,readFileSync as he,renameSync as xe,writeFileSync as ve}from"node:fs";import{homedir as Se}from"node:os";import{dirname as P,join as y}from"node:path";function f(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Oe(){let e=process.env.XDG_CONFIG_HOME?.trim();return e?y(e,"opencode"):y(Se(),".config","opencode")}function Ce(){return y(Oe(),"opencode.json")}function we(e,n){ye(P(e),{recursive:!0});let t=`${e}.tmp-${process.pid}-${Date.now()}`;ve(t,`${JSON.stringify(n,null,2)}
698
+ `,{encoding:"utf8",mode:384}),xe(t,e)}function F(e){if(!$(e))return{};let n=he(e,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(o){throw new Error(`Invalid existing OpenCode opencode.json: ${o instanceof Error?o.message:String(o)}`)}if(!f(t))throw new Error("Invalid existing OpenCode opencode.json: root must be a JSON object.");return t}function _(e,n){if(!f(e))return!1;let t=e.command;return e.type==="local"&&e.enabled!==!1&&Array.isArray(t)&&t.length===2&&t[0]===n&&t[1]==="mcp"}function J(e={}){let n=e.configFile??Ce(),t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",r=y(P(n),"opencode.jsonc"),s=$(r)?r:void 0,i=F(n),c=i.mcp;if(c!==void 0&&!f(c))throw new Error("Invalid existing OpenCode config: mcp must be an object.");let d=f(c)?{...c}:{},u=d[o];if(_(u,t))return{installed:!0,changed:!1,configFile:n,serverName:o,command:[t,"mcp"],preservedJsonc:s};d[o]={type:"local",command:[t,"mcp"],enabled:!0};let l={...i,mcp:d};we(n,l);let m=F(n);if(!f(m.mcp)||!_(m.mcp[o],t))throw new Error("OpenCode MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:n,serverName:o,command:[t,"mcp"],preservedJsonc:s}}import{existsSync as be,mkdirSync as D,readFileSync as Ne,writeFileSync as B}from"node:fs";import{homedir as L}from"node:os";import{dirname as Y,join as v}from"node:path";function Ie(e){let n=[],t=/"((?:\\.|[^"\\])*)"|'([^']*)'/g,o;for(;o=t.exec(e);){let r=o[1]??o[2]??"";try{n.push(o[1]!==void 0?JSON.parse(`"${r}"`):r)}catch{n.push(r)}}return n}function H(e={}){let n=e.configFile??v(process.env.CODEX_HOME??v(L(),".codex"),"config.toml"),t=e.previousFile??v(L(),".config","toolnet-memory","codex-notify-previous.json");D(Y(n),{recursive:!0}),D(Y(t),{recursive:!0});let o=be(n)?Ne(n,"utf8"):"",r=e.binary??"toolnet-memory",s=`notify = [${JSON.stringify(r)}, "session:codex-notify"]`,i=o.split(`
699
+ `),c=i.findIndex(a=>/^\s*\[/.test(a));c<0&&(c=i.length);let d=-1,u=-1;for(let a=0;a<c;a+=1)if(/^\s*notify\s*=/.test(i[a])){if(d=a,u=a,i[a].includes("[")&&!i[a].includes("]"))for(;u+1<c&&(u+=1,!i[u].includes("]")););break}let l=[];if(d>=0){let a=i.slice(d,u+1).join(`
700
+ `);l=Ie(a),i.splice(d,u-d+1,s)}else c=i.findIndex(a=>/^\s*\[/.test(a)),c<0&&(c=i.length),i.splice(c,0,s);let m=l.length>=2&&l[l.length-1]==="session:codex-notify";return l.length>0&&!m&&B(t,JSON.stringify(l,null,2)+`
701
+ `,{encoding:"utf8",mode:384}),o=i.join(`
702
+ `),o.endsWith(`
703
+ `)||(o+=`
704
+ `),B(n,o,{encoding:"utf8",mode:384}),{configFile:n,previousFile:t,preservedPrevious:l.length>0&&!m}}import{existsSync as Te,mkdirSync as ke,readFileSync as Ee,writeFileSync as je}from"node:fs";import{homedir as Me}from"node:os";import{dirname as Ae,join as q}from"node:path";function Re(e){return`'${e.replace(/'/g,"'\\''")}'`}function G(e={}){let n=e.hooksFile??q(process.env.CODEX_HOME??q(Me(),".codex"),"hooks.json");ke(Ae(n),{recursive:!0});let t={};if(Te(n))try{t=JSON.parse(Ee(n,"utf8"))}catch(c){throw new Error(`Invalid existing Codex hooks.json: ${c instanceof Error?c.message:String(c)}`)}let o=t.hooks&&typeof t.hooks=="object"&&!Array.isArray(t.hooks)?t.hooks:{};t.hooks=o;let s=(Array.isArray(o.SessionStart)?o.SessionStart:[]).filter(c=>{try{return!JSON.stringify(c).includes("session:codex-context")}catch{return!0}}),i=e.binary??"toolnet-memory";return s.push({matcher:"startup|resume|clear|compact",hooks:[{type:"command",command:`${Re(i)} session:codex-context`,timeout:15,additionalContextLimit:1e3,statusMessage:"Loading ToolNet project continuity"}]}),o.SessionStart=s,je(n,JSON.stringify(t,null,2)+`
705
+ `,{encoding:"utf8",mode:384}),n}import{spawnSync as Fe}from"node:child_process";function S(e,n){return Fe(e,n,{encoding:"utf8",stdio:["ignore","pipe","pipe"]})}function U(e,n){let t=S(e,["mcp","get",n,"--json"]);if(t.status!==0||!t.stdout)return null;try{return JSON.parse(t.stdout)}catch{return null}}function X(e,n){return e.enabled!==!1&&e.transport?.type==="stdio"&&e.transport?.command===n&&Array.isArray(e.transport?.args)&&e.transport?.args.length===1&&e.transport.args[0]==="mcp"}function W(e={}){let n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=e.codexBinary??"codex",o=e.serverName??"toolnet-memory",r=U(t,o);if(r&&X(r,n))return{installed:!0,changed:!1,serverName:o,command:n,args:["mcp"]};if(r){let c=S(t,["mcp","remove",o]);if(c.status!==0)return{installed:!1,changed:!1,serverName:o,command:n,args:["mcp"],error:(c.stderr||c.stdout||"Unable to remove old ToolNet MCP configuration.").trim()}}let s=S(t,["mcp","add",o,"--",n,"mcp"]);if(s.status!==0)return{installed:!1,changed:!1,serverName:o,command:n,args:["mcp"],error:(s.stderr||s.stdout||"Unable to register ToolNet MCP.").trim()};let i=U(t,o);return!i||!X(i,n)?{installed:!1,changed:!0,serverName:o,command:n,args:["mcp"],error:"Codex accepted MCP registration but verification did not match expected ToolNet command."}:{installed:!0,changed:!0,serverName:o,command:n,args:["mcp"]}}function b(e){return _e("sh",["-lc",`command -v ${JSON.stringify(e)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function $e(){return b("agy")||O(w(C(),".gemini"))}function Pe(){return b("opencode")||O(w(C(),".config","opencode"))}function Je(){return b("codex")||O(process.env.CODEX_HOME??w(C(),".codex"))}function De(e={}){let n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=[];if(!(e.force===!0||$e()))t.push({agent:"agy",detected:!1,installed:!1,targets:[]});else try{let r=N({binary:n}),s=k({binary:n});t.push({agent:"agy",detected:!0,installed:!0,targets:[r,s.configFile]})}catch(r){t.push({agent:"agy",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||Pe()))t.push({agent:"opencode",detected:!1,installed:!1,targets:[]});else try{let r=R({binary:n}),s=J({binary:n});t.push({agent:"opencode",detected:!0,installed:!0,targets:[r,s.configFile,`mcp:${s.serverName}`]})}catch(r){t.push({agent:"opencode",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||Je()))t.push({agent:"codex",detected:!1,installed:!1,targets:[]});else try{let r=H({binary:n}),s=G({binary:n}),i=W({binary:n});if(!i.installed)throw new Error(i.error??"Codex MCP registration failed");let c=[r.configFile,s,`mcp:${i.serverName}`];r.preservedPrevious&&c.push(r.previousFile),t.push({agent:"codex",detected:!0,installed:!0,targets:c})}catch(r){t.push({agent:"codex",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}return t}function Be(e){console.log(""),console.log("ToolNet Memory AI Integrations"),console.log("=============================="),console.log("");for(let n of e){let t=n.agent==="agy"?"Agy / Antigravity":n.agent==="opencode"?"OpenCode":"Codex";if(!n.detected){console.log(`- ${t}: not detected`);continue}if(n.installed){console.log(`\u2713 ${t}: automatic memory enabled`);continue}console.log(`\u2717 ${t}: integration failed`),n.error&&console.log(` ${n.error}`)}console.log("")}async function Le(){let e=process.argv.slice(2),n=e.includes("--all"),t=e.includes("--json"),o=De({force:n});if(t){console.log(JSON.stringify(o,null,2));return}Be(o)}var Ye=process.argv[1]&&(process.argv[1].endsWith("auto-integrate.js")||process.argv[1].endsWith("auto-integrate.ts"));Ye&&Le().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});export{De as installAutoIntegrations};
@@ -1,59 +1,53 @@
1
- import{existsSync as ce,readFileSync as ue}from"node:fs";import{homedir as pe}from"node:os";import{join as le}from"node:path";function de(r){let e=r.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 fe(){let r=process.env.TOOLNET_GLOBAL_ENV??le(pe(),".config","toolnet-memory",".env");if(!ce(r))return;let e=ue(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.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]=de(n.slice(s+1)))}}fe();function y(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function S(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function _(){return{memory:{autoCapture:y(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:y(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:y(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:y(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:S(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:S(process.env.MEMORY_RERANK_TOP,10),finalContext:S(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:S(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:y(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:S(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as me}from"node:crypto";import{existsSync as T,mkdirSync as ge,readFileSync as he,renameSync as ye,writeFileSync as Se}from"node:fs";import{basename as ke,dirname as b,join as x,parse as B,resolve as k}from"node:path";var D=".toolnet",je="project.json";function ve(r){return me("sha256").update(r).digest("hex").slice(0,16)}function E(r){return x(r,D,je)}function be(r){return T(E(r))}function we(r,e){let t=k(r),n=B(t).root;for(;;){if(be(t))return t;if(t===n||e&&t===k(e))break;let s=b(t);if(s===t)break;t=s}return null}function xe(r){let e=k(r),t=B(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(o=>T(x(e,o))))return e;if(e===t)break;let s=b(e);if(s===e)break;e=s}return k(r)}function Pe(r){let e;try{e=JSON.parse(he(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=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:b(b(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,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 K(r,e){let t=x(r,D);ge(t,{recursive:!0});let n=E(r),s=`${n}.tmp-${process.pid}`;Se(s,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ye(s,n)}function W(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var w=class{detect(e=process.cwd()){let t=k(e),n=xe(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>T(x(n,m))),c=we(t,o?n:void 0);if(c){let m=E(c),i=Pe(m);return i.rootPath!==c&&(i.rootPath=c,i.updatedAt=new Date().toISOString(),K(c,i)),W(i,c)}let l=new Date().toISOString(),a=ke(n),p={version:1,id:ve(n),name:a,remote:a,rootPath:n,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return K(n,p),W(p,n)}};import{homedir as qe}from"node:os";import{join as Ye}from"node:path";import{DeleteObjectCommand as Oe,GetObjectCommand as Ie,HeadObjectCommand as Ae,ListObjectsV2Command as Te,PutObjectCommand as Ee,S3Client as Me}from"@aws-sdk/client-s3";import{getSignedUrl as Ce}from"@aws-sdk/s3-request-presigner";var P=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Me({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ee({Bucket:this.bucket,Key:e,Body:s,ContentType:n}))}async get(e){let t=await Ce(this.client,new Ie({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{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(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Ae({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Oe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let s=await this.client.send(new Te({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return t}};import{access as L,mkdir as Re,readFile as Ne,readdir as $e,rm as _e,stat as z,writeFile as Ke}from"node:fs/promises";import{dirname as We,join as Be,relative as F,resolve as De}from"node:path";var j=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return De(this.root,t)}async put(e,t){let n=this.path(e);await Re(We(n),{recursive:!0}),await Ke(n,t)}async get(e){try{return await Ne(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await L(this.path(e)),!0}catch{return!1}}async delete(e){await _e(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await L(t)}catch{return n}let s=async c=>{let l=await $e(c,{withFileTypes:!0});for(let a of l){let p=Be(c,a.name);if(a.isDirectory()){await s(p);continue}let m=await z(p);n.push({key:F(this.root,p),size:m.size,updatedAt:m.mtime.toISOString()})}},o=await z(t);return o.isDirectory()?await s(t):n.push({key:F(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),n}};import{DeleteObjectCommand as Le,GetObjectCommand as ze,HeadObjectCommand as Fe,ListObjectsV2Command as Ve,PutObjectCommand as Je,S3Client as Ue}from"@aws-sdk/client-s3";import{getSignedUrl as He}from"@aws-sdk/s3-request-presigner";var v=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Ue({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Je({Bucket:this.bucket,Key:e,Body:s,ContentType:n}))}async get(e){let t=await He(this.client,new ze({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{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(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Fe({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Le({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let s=await this.client.send(new Ve({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return t}};function M(r,e){return console.warn(e),new j(r)}function V(r){let e=r.localRoot??Ye(qe(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new v({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):M(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new v({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):M(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new P({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):M(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new j(e)}function Ge(r){return new Promise(e=>setTimeout(e,r))}async function J(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let c=1;c<=t;c++)try{return await r()}catch(l){if(o=l,c>=t)break;let a=Math.min(s,n*2**(c-1)),p=Math.floor(Math.random()*Math.max(1,a*.2));await Ge(a+p)}throw o}var Qe=new Set(["put","get","getText","delete","list"]);function U(r,e={}){return new Proxy(r,{get(t,n){let s=Reflect.get(t,n,t);return typeof s!="function"?s:Qe.has(n)?(...o)=>J(()=>Promise.resolve(s.apply(t,o)),e):s.bind(t)}})}function H(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function q(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var O=class{constructor(e,t,n,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=H(s??n),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),n=t,s=await this.provider.getText(e);if(s){let c;try{c=JSON.parse(s)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}if(typeof c.id=="string"&&c.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${c.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof c.createdAt=="string"&&(n=c.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:t};await this.provider.put(e,JSON.stringify(o,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=q(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{createHash as Xe}from"node:crypto";import{dirname as Ze}from"node:path";import{mkdirSync as et,readFileSync as wn,renameSync as tt,writeFileSync as rt}from"node:fs";function f(r){return Xe("sha256").update(r).digest("hex")}function h(r,e){et(Ze(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;rt(t,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),tt(t,r)}async function C(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}import{existsSync as Q,mkdirSync as st,readFileSync as ot,statSync as Y,writeFileSync as it}from"node:fs";import{dirname as at,join as ct}from"node:path";var G=64*1024,ut=`# ToolNet Project Operating Manual
1
+ import*as p from"fs";import*as u from"path";function w(e){return e?Math.ceil(e.length/3.5):0}function B(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 Y(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}
6
5
 
7
- This file contains persistent instructions for AI agents working on this project.
6
+ `,d=w(m),f=w(a.content),h=d+f;if(i+h<=r)s.push(m+a.content),i+=h;else{let S=r-i-d;if(S>50){let g=B(a.content,S);s.push(m+g),i=r,c=!0}else c=!0;break}}return c&&s.push(`
7
+ ${n}
8
+ `),s.join(`
8
9
 
9
- ## Critical Rules
10
+ ---
10
11
 
11
- <!--
12
- Examples:
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 Y(r,{maxTokens:800})}import{existsSync as M,mkdirSync as ke,readFileSync as v,renameSync as Me,writeFileSync as ve}from"node:fs";import{dirname as je,join as _}from"node:path";import{createHash as V}from"node:crypto";function k(e){return V("sha256").update(e).digest("hex")}function U(e){return _(e.rootPath,".toolnet","context","handoff.md")}function G(e){return _(e.rootPath,".toolnet","context","handoff.json")}function J(e){let t=U(e);if(!M(t))return null;try{let r=v(t,"utf8").trim();if(!r)return null;let n=new Date(0).toISOString(),o=G(e);if(M(o))try{let s=JSON.parse(v(o,"utf8"));typeof s.generatedAt=="string"&&(n=s.generatedAt)}catch{}return{version:1,projectId:e.id,projectName:e.name,text:r,digest:k(r),generatedAt:n}}catch{return null}}function j(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)}
13
13
 
14
- - [enforce] Never edit production files directly.
15
- - [enforce] Edit source only in /path/to/source.
16
- - [enforce] Deploy only with ./deploy.sh --apply
17
- -->
14
+ [Fast handoff truncated]`),["[TOOLNET FAST HANDOFF]","",`Project: ${e.name}`,`Updated: ${r.generatedAt}`,"",n].join(`
15
+ `)}var O="memory_agent_ask";function I(){return`
16
+ [TOOLNET MEMORY AGENT]
18
17
 
19
- ## Workflow
18
+ Tool:
19
+ - ${O}
20
20
 
21
- <!--
22
- Describe the correct working process.
23
- -->
21
+ If the user asks to resume previous work and the fast context
22
+ is insufficient, call ${O} before guessing.
24
23
 
25
- ## Architecture
24
+ Use:
25
+ - mode="local" for current task, last file, blocker or next action.
26
+ - mode="ai" for ambiguous or combined continuity questions.
26
27
 
27
- <!--
28
- Important architecture conventions.
29
- -->
28
+ Current repository evidence overrides stale memory.
29
+ `.trim()}function W(e){let t=u.resolve(e),r=u.parse(t).root;for(;t!==r;){let n=u.join(t,".toolnet");if(p.existsSync(n)&&p.statSync(n).isDirectory())return t;t=u.dirname(t)}return null}function P(e){try{return p.existsSync(e)?p.readFileSync(e,"utf-8").trim():null}catch{return null}}function N(e){return e.split(`
30
+ `).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(`
31
+ `)}function D(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(p.existsSync(n)){let g=JSON.parse(p.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=P(s)||"",a=P(i)||"";c=N(c),a=N(a);let m=`[TOOLNET PROJECT CONTEXT]
30
32
 
31
- ## Verification
33
+ Project: ${o}
34
+ Root: ${r}
32
35
 
33
- <!--
34
- Tests / QA required after changes.
35
- -->
36
+ `,d=C(c,a),f=j({id:"",name:o,rootPath:r},1600),h=f?`
36
37
 
37
- ## Known Gotchas
38
+ ${f}
39
+ `:"",S=`
38
40
 
39
- <!--
40
- Things an AI agent should always remember.
41
- -->
41
+ ${I()}
42
42
 
43
- ## Preferences
43
+ Forbidden At Startup:
44
+ - Do not run session:agy-recover, handoff:latest, or brief automatically.
45
+ - Do not perform deep recovery merely because an agent starts.
46
+ - If the user asks to resume previous work and fast context is insufficient,
47
+ use memory_agent_ask before guessing.
48
+ `;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,`
49
+ `).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 E,mkdirSync as ne,readFileSync as oe,renameSync as se,writeFileSync as ie}from"node:fs";import{basename as ce,dirname as x,join as A,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 R(e){return A(e,z,ae)}function me(e){return E(R(e))}function fe(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 pe(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=>E(A(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 F(e,t){let r=A(e,z);ne(r,{recursive:!0});let n=R(e),o=`${n}.tmp-${process.pid}`;ie(o,JSON.stringify(t,null,2)+`
50
+ `,{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=pe(r),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>E(A(n,d))),i=fe(r,s?n:void 0);if(i){let d=R(i),f=de(d);return f.rootPath!==i&&(f.rootPath=i,f.updatedAt=new Date().toISOString(),F(i,f)),L(f,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 F(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 H=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<=H?e:`${e.slice(0,H)}
44
51
 
45
- <!--
46
- - [advisory] Prefer small focused files.
47
- -->
48
- `;function I(r){return ct(r.rootPath,".toolnet","PROJECT.md")}function pt(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function lt(r){let e=[],t=new Set,n=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=n.exec(r);){let o=s[1].toLowerCase(),c=pt(s[2]);if(!c)continue;let l=`${o}:${c.toLowerCase()}`;t.has(l)||(t.add(l),e.push({id:f(l).slice(0,24),mode:o,text:c,source:"manual"}))}return e}function dt(r){let e=I(r);return Q(e)||(st(at(e),{recursive:!0}),it(e,ut,{encoding:"utf8",mode:384})),e}function R(r,e=!1){let t=e?dt(r):I(r);if(!Q(t))return null;if(Y(t).size>G)throw new Error(`PROJECT.md exceeds ${G} bytes`);let s=ot(t,"utf8");return{path:t,content:s,digest:f(s),rules:lt(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(Y(t).mtimeMs).toISOString()}}async function X(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function Z(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function N(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function d(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function ft(r){let e=[],t=!1;for(let n of r.split(/\r?\n/u)){let s=n.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let o=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||o.startsWith("- [enforce]")||o.startsWith("* [enforce]")||o.startsWith("- [advisory]")||o.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(d(s,280)),e.length>=16))break}return e}function mt(r){let e=[],t=[];for(let n of r.split(/\\r?\\n/u)){let s=n.trim(),o=s.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(p=>o.startsWith(p));if(!l)continue;let a=s.slice(l.length).trim();a&&(l.includes("enforce")?e.push(a):t.push(a))}return{enforce:e,advisory:t}}function gt(r,e){let t=[];for(let n of r){let s=[...t,n].join(`
49
- `);if(N(s)<=e){t.push(n);continue}let o=N(t.join(`
50
- `)),c=Math.max(0,e-o);if(c>=16){let l=Math.floor(c*3.2),a=d(n,l);a&&t.push(a)}break}return t.join(`
51
- `).trim()}async function ee(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=R(r.project,!1),n=t?.content??"";n||(n=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=mt(n),o=t?t.rules.filter(u=>u.mode==="enforce").map(u=>u.text):s.enforce,c=t?t.rules.filter(u=>u.mode==="advisory").map(u=>u.text):s.advisory,l=n?ft(n):[],a=await C(r.project,r.storage),p=await Z(r.project,r.storage),m=await X(r.project,r.storage),i=[];if(i.push("[TOOLNET PROJECT CONTEXT]"),i.push(`Project: ${r.project.name}`),i.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),n&&i.push(`Full operating manual: ${I(r.project)}`),o.length){i.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let u of o.slice(0,24))i.push(`- [ENFORCE] ${d(u,240)}`)}if(c.length){i.push("","PROJECT PREFERENCES");for(let u of c.slice(0,10))i.push(`- ${d(u,220)}`)}if(p&&(p.mission&&i.push("","MISSION",d(p.mission.value,420)),p.activeObjective&&i.push("","CURRENT OBJECTIVE",d(p.activeObjective.value,420)),p.why&&i.push("","WHY THIS WORK MATTERS",d(p.why.value,420)),p.desiredOutcome&&i.push("","DESIRED OUTCOME",d(p.desiredOutcome.value,420)),p.planRationale&&i.push("","WHY THIS APPROACH",d(p.planRationale.value,420))),a){if(i.push("","ACTIVE WORK"),a.goal&&i.push(`Goal: ${d(a.goal,320)}`),a.plan&&i.push(`Plan: ${d(a.plan,320)}`),i.push(`Progress: phases ${a.progress.phasesCompleted}/${a.progress.phasesTotal}; tasks ${a.progress.tasksCompleted}/${a.progress.tasksTotal}; blocked ${a.progress.blocked}`),a.currentPhase&&i.push(`Current phase: ${a.currentPhase.title} [${a.currentPhase.status}]`),a.currentPhase&&p){let u=p.phases.find(g=>g.order===a.currentPhase?.order);u&&(u.objective&&i.push(`Phase objective: ${d(u.objective.value,340)}`),u.why?i.push(`Why this phase: ${d(u.why.value,340)}`):i.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),u.deliverable&&i.push(`Deliverable: ${d(u.deliverable.value,340)}`),u.dependencies.length&&i.push(`Depends on: ${u.dependencies.slice(0,4).map(g=>d(g.value,180)).join("; ")}`),u.acceptanceCriteria.length&&(i.push("","DEFINITION OF DONE"),u.acceptanceCriteria.slice(0,6).forEach(g=>{i.push(`- ${d(g.value,260)}`)})),u.openQuestions.length&&(i.push("","OPEN QUESTIONS FOR CURRENT PHASE"),u.openQuestions.slice(0,4).forEach(g=>{i.push(`- ${d(g.value,260)}`)})))}a.currentTask&&i.push(`Current task: ${a.currentTask.title} [${a.currentTask.status}]`),a.nextActions.length&&(i.push("","NEXT ACTIONS"),a.nextActions.slice(0,6).forEach((u,g)=>{i.push(`${g+1}. ${d(u,260)}`)})),a.blockers.length&&(i.push("","BLOCKERS"),a.blockers.slice(0,5).forEach(u=>{i.push(`- ${d(u,260)}`)})),a.warnings.length&&(i.push("","ATTENTION"),a.warnings.slice(-5).forEach(u=>{i.push(`- ${d(u,260)}`)})),a.decisions.length&&(i.push("","RECENT DECISIONS"),a.decisions.slice(-5).forEach(u=>{i.push(`- ${d(u,260)}`)})),a.lastSession&&i.push("",`Last work session: ${a.lastSession.agent} / ${a.lastSession.nativeSessionId}`)}if(p&&p.openQuestions.length&&(i.push("","UNRESOLVED QUESTIONS"),p.openQuestions.slice(0,5).forEach(u=>{i.push(`- ${d(u.value,260)}`)})),m&&i.push(`Latest handoff: ${m.reason} / ${m.sourceSession.agent}`),l.length){i.push("","OPERATING NOTES");for(let u of l)i.push(`- ${u}`)}i.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let $=gt(i,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:$,estimatedTokens:N($),maxTokens:e,hasManual:!!n,hasWorkState:!!a,hasHandoff:!!m,generatedAt:new Date().toISOString()}}import{existsSync as ht,mkdirSync as yt,readFileSync as St,writeFileSync as kt}from"node:fs";import{dirname as jt,join as re}from"node:path";function A(r){return r?Math.ceil(r.length/3.5):0}function te(r,e){if(!r)return"";if(A(r)<=e)return r;let n=Math.floor(e*3.5),s=r.slice(0,n),o=s.lastIndexOf("."),c=s.lastIndexOf(`
52
- `),l=Math.max(o,c);return l>n*.7?s.slice(0,l+1):s}function ne(r){return re(r.rootPath,".toolnet","context","startup.md")}function vt(r){return re(r.rootPath,".toolnet","context","startup.json")}function se(r,e){let t=ne(r);yt(jt(t),{recursive:!0}),kt(t,e.text.endsWith(`
53
- `)?e.text:e.text+`
54
- `,{encoding:"utf8",mode:384}),h(vt(r),e)}async function bt(r,e,t=800){let s=(await ee({project:r,storage:e,maxTokens:t})).text;A(s)>t&&(s=te(s,t),s+=`
55
-
56
- [Context trimmed by ToolNet Memory token budget]
57
- `);let c={version:1,projectId:r.id,projectName:r.name,text:s,digest:f(s),estimatedTokens:A(s),generatedAt:new Date().toISOString()};return se(r,c),await e.put(`projects/${r.id}/context/startup.md`,c.text+`
58
- `,"text/markdown"),await e.put(`projects/${r.id}/context/startup.json`,JSON.stringify(c,null,2)+`
59
- `,"application/json"),c}async function oe(r,e,t=900){try{let s=await e.getText(`projects/${r.id}/context/startup.md`);if(s&&s.trim()){let o=s.trim(),c={version:1,projectId:r.id,projectName:r.name,text:o,digest:f(o),estimatedTokens:Math.ceil(o.length/3.5),generatedAt:new Date().toISOString()};return se(r,c),c}}catch{}let n=ne(r);if(ht(n))try{let s=St(n,"utf8").trim();if(s)return{version:1,projectId:r.id,projectName:r.name,text:s,digest:f(s),estimatedTokens:Math.ceil(s.length/3.5),generatedAt:new Date().toISOString()}}catch{}try{return await bt(r,e,t)}catch{return null}}async function ie(r){let e=await oe(r.project,r.storage,900);return e?.text?{hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:e.text}}:{}}import{existsSync as wt}from"node:fs";import{dirname as xt,join as Pt,parse as Ot,resolve as It}from"node:path";function ae(r){let e=It(r),t=Ot(e).root;for(;;){if(wt(Pt(e,".toolnet","project.json")))return new w().detect(e);if(e===t)break;let n=xt(e);if(n===e)break;e=n}return null}async function At(){let r="";for await(let e of process.stdin)r+=e.toString();if(!r.trim())return{};try{return JSON.parse(r)}catch{return{}}}async function Tt(){let r=await At();if(r.hook_event_name!=="SessionStart"){process.stdout.write("{}");return}let e=typeof r.cwd=="string"?r.cwd:"";if(!e){process.stdout.write("{}");return}let t=ae(e);if(!t){process.stdout.write("{}");return}try{let n=_(),s=U(V({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:2}),o=new O(s,t.id,t.name,t.remote??t.name),c=await ie({project:t,storage:o});process.stdout.write(JSON.stringify(c))}catch{process.stdout.write("{}")}}Tt().catch(()=>{process.stdout.write("{}"),process.exitCode=0});
52
+ [ToolNet startup context truncated]`}function Ae(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}
53
+ `)}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=D({projectPath:r});if(!o?.trim()){l();return}let s=Te(o),i={hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s}};Ae(e,r,s.length),process.stdout.write(JSON.stringify(i))}catch{l()}}we().catch(()=>{l(),process.exitCode=0});