toolnet-memory 0.3.3 → 0.3.5

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/bundle/init.js CHANGED
@@ -1,11 +1,11 @@
1
- import{existsSync as ze,statSync as En}from"node:fs";import{resolve as Tn,join as jn}from"node:path";import{existsSync as Ke,readFileSync as Ue}from"node:fs";import{homedir as Ve}from"node:os";import{join as Ge}from"node:path";function We(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 qe(){let e=process.env.TOOLNET_GLOBAL_ENV??Ge(Ve(),".config","toolnet-memory",".env");if(!Ke(e))return;let t=Ue(e,"utf8");for(let n of t.split(/\r?\n/)){let o=n.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=We(o.slice(s+1)))}}qe();import{createHash as Xe}from"node:crypto";import{existsSync as T,mkdirSync as Qe,readFileSync as Ze,renameSync as et,writeFileSync as tt}from"node:fs";import{basename as nt,dirname as w,join as O,parse as V,resolve as h}from"node:path";var G=".toolnet",ot="project.json";function rt(e){return Xe("sha256").update(e).digest("hex").slice(0,16)}function j(e){return O(e,G,ot)}function st(e){return T(j(e))}function it(e,t){let n=h(e),o=V(n).root;for(;;){if(st(n))return n;if(n===o||t&&n===h(t))break;let s=w(n);if(s===n)break;n=s}return null}function ct(e){let t=h(e),n=V(t).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>T(O(t,i))))return t;if(t===n)break;let s=w(t);if(s===t)break;t=s}return h(e)}function at(e){let t;try{t=JSON.parse(Ze(e,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${e}: ${s instanceof Error?s.message:String(s)}`)}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 o=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:w(w(e)),createdAt:typeof n.createdAt=="string"?n.createdAt:o,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:o,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 K(e,t){let n=O(e,G);Qe(n,{recursive:!0});let o=j(e),s=`${o}.tmp-${process.pid}`;tt(s,JSON.stringify(t,null,2)+`
3
- `,{encoding:"utf8",mode:384}),et(s,o)}function U(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 C=class{detect(t=process.cwd()){let n=h(t),o=ct(n),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>T(O(o,u))),r=it(n,i?o:void 0);if(r){let u=j(r),p=at(u);return p.rootPath!==r&&(p.rootPath=r,p.updatedAt=new Date().toISOString(),K(r,p)),U(p,r)}let c=new Date().toISOString(),l=nt(o),a={version:1,id:rt(o),name:l,remote:l,rootPath:o,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return K(o,a),U(a,o)}};var W=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],m={clear:"\r\x1B[2K",cyan:"\x1B[36m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",dim:"\x1B[2m",reset:"\x1B[0m"};function q(e){let t=Date.now()-e;return t<1e3?`${t}ms`:t<1e4?`${(t/1e3).toFixed(1)}s`:`${Math.round(t/1e3)}s`}var R=class{stream;enabled;interactive;color;intervalMs;label;frame=0;startedAt=0;timer;active=!1;constructor(t,n={}){this.label=t,this.stream=n.stream??process.stderr,this.enabled=n.enabled??!0,this.interactive=n.interactive??this.stream.isTTY===!0,this.color=n.color??(this.interactive&&process.env.NO_COLOR===void 0),this.intervalMs=Math.max(40,n.intervalMs??80)}start(){return!this.enabled||this.active?this:(this.active=!0,this.startedAt=Date.now(),this.interactive?(this.render(),this.timer=setInterval(()=>{this.frame=(this.frame+1)%W.length,this.render()},this.intervalMs),this.timer.unref?.(),this):(this.stream.write(`\u2192 ${this.label}
4
- `),this))}update(t){return this.label=t,this.enabled&&this.active&&this.interactive&&this.render(),this}succeed(t){this.finish("\u2713",t??this.label,m.green)}fail(t){this.finish("\u2717",t??this.label,m.red)}warn(t){this.finish("!",t??this.label,m.yellow)}stop(){this.active&&(this.timer&&(clearInterval(this.timer),this.timer=void 0),this.enabled&&this.interactive&&this.stream.write(m.clear),this.active=!1)}render(){if(!this.enabled||!this.active||!this.interactive)return;let t=W[this.frame],n=this.color?`${m.cyan}${t}${m.reset}`:t,o=q(this.startedAt),s=this.color?`${m.dim}${o}${m.reset}`:o;this.stream.write(`${m.clear}${n} ${this.label} ${s}`)}finish(t,n,o){if(!this.enabled){this.active=!1;return}this.startedAt||(this.startedAt=Date.now()),this.timer&&(clearInterval(this.timer),this.timer=void 0);let s=q(this.startedAt),i=this.color?`${o}${t}${m.reset}`:t,r=this.color?`${m.dim}${s}${m.reset}`:s;this.interactive?this.stream.write(`${m.clear}${i} ${n} ${r}
1
+ import{existsSync as Ue,statSync as kn}from"node:fs";import{resolve as Rn,join as jn}from"node:path";import{existsSync as Ke,readFileSync as Ve}from"node:fs";import{homedir as We}from"node:os";import{join as Ge}from"node:path";function qe(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 Qe(){let e=process.env.TOOLNET_GLOBAL_ENV??Ge(We(),".config","toolnet-memory",".env");if(!Ke(e))return;let t=Ve(e,"utf8");for(let n of t.split(/\r?\n/)){let o=n.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=qe(o.slice(s+1)))}}Qe();import{createHash as Xe}from"node:crypto";import{existsSync as k,mkdirSync as Ze,readFileSync as et,renameSync as tt,writeFileSync as nt}from"node:fs";import{basename as ot,dirname as w,join as C,parse as V,resolve as h}from"node:path";var W=".toolnet",rt="project.json";function st(e){return Xe("sha256").update(e).digest("hex").slice(0,16)}function R(e){return C(e,W,rt)}function it(e){return k(R(e))}function at(e,t){let n=h(e),o=V(n).root;for(;;){if(it(n))return n;if(n===o||t&&n===h(t))break;let s=w(n);if(s===n)break;n=s}return null}function ct(e){let t=h(e),n=V(t).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>k(C(t,i))))return t;if(t===n)break;let s=w(t);if(s===t)break;t=s}return h(e)}function lt(e){let t;try{t=JSON.parse(et(e,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${e}: ${s instanceof Error?s.message:String(s)}`)}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 o=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:w(w(e)),createdAt:typeof n.createdAt=="string"?n.createdAt:o,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:o,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 U(e,t){let n=C(e,W);Ze(n,{recursive:!0});let o=R(e),s=`${o}.tmp-${process.pid}`;nt(s,JSON.stringify(t,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),tt(s,o)}function K(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 O=class{detect(t=process.cwd()){let n=h(t),o=ct(n),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>k(C(o,u))),r=at(n,i?o:void 0);if(r){let u=R(r),p=lt(u);return p.rootPath!==r&&(p.rootPath=r,p.updatedAt=new Date().toISOString(),U(r,p)),K(p,r)}let a=new Date().toISOString(),l=ot(o),c={version:1,id:st(o),name:l,remote:l,rootPath:o,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return U(o,c),K(c,o)}};var G=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],m={clear:"\r\x1B[2K",cyan:"\x1B[36m",green:"\x1B[32m",red:"\x1B[31m",yellow:"\x1B[33m",amber:"\x1B[38;5;214m",dim:"\x1B[2m",reset:"\x1B[0m"};function q(e,t=16){let o=Math.max(1,t-4+1),s=e%o;return"\u2500".repeat(s)+"\u2501".repeat(4)+"\u2500".repeat(Math.max(0,t-s-4))}function Q(e){let t=Date.now()-e;return t<1e3?`${t}ms`:t<1e4?`${(t/1e3).toFixed(1)}s`:`${Math.round(t/1e3)}s`}var j=class{stream;enabled;interactive;color;intervalMs;display;label;frame=0;startedAt=0;timer;active=!1;constructor(t,n={}){this.label=t,this.stream=n.stream??process.stderr,this.enabled=n.enabled??!0,this.interactive=n.interactive??this.stream.isTTY===!0,this.color=n.color??(this.interactive&&process.env.NO_COLOR===void 0),this.intervalMs=Math.max(40,n.intervalMs??80),this.display=n.display??"spinner"}start(){return!this.enabled||this.active?this:(this.active=!0,this.startedAt=Date.now(),this.interactive?(this.render(),this.timer=setInterval(()=>{this.frame=(this.frame+1)%1e4,this.render()},this.intervalMs),this.timer.unref?.(),this):(this.stream.write(`\u2192 ${this.label}
4
+ `),this))}update(t){return this.label=t,this.enabled&&this.active&&this.interactive&&this.render(),this}succeed(t){this.finish("\u2713",t??this.label,m.green)}fail(t){this.finish("\u2717",t??this.label,m.red)}warn(t){this.finish("!",t??this.label,m.yellow)}stop(){this.active&&(this.timer&&(clearInterval(this.timer),this.timer=void 0),this.enabled&&this.interactive&&this.stream.write(m.clear),this.active=!1)}render(){if(!this.enabled||!this.active||!this.interactive)return;let t=G[this.frame%G.length],n=this.display==="bar"?this.color?`${m.amber}${q(this.frame)}${m.reset}`:q(this.frame):this.color?`${m.cyan}${t}${m.reset}`:t,o=Q(this.startedAt),s=this.color?`${m.dim}${o}${m.reset}`:o;this.stream.write(`${m.clear}${n} ${this.label} ${s}`)}finish(t,n,o){if(!this.enabled){this.active=!1;return}this.startedAt||(this.startedAt=Date.now()),this.timer&&(clearInterval(this.timer),this.timer=void 0);let s=Q(this.startedAt),i=this.color?`${o}${t}${m.reset}`:t,r=this.color?`${m.dim}${s}${m.reset}`:s;this.interactive?this.stream.write(`${m.clear}${i} ${n} ${r}
5
5
  `):this.stream.write(`${i} ${n} (${s})
6
- `),this.active=!1}};async function N(e,t,n={}){let o=new R(e,n).start();try{let s=await t();return o.succeed(),s}catch(s){throw o.fail(),s}}import{existsSync as dt}from"node:fs";import{homedir as mt}from"node:os";import{join as pt}from"node:path";import{spawnSync as gt}from"node:child_process";import{homedir as lt}from"node:os";import{join as f}from"node:path";function X(e={}){return f(e.home??lt(),".gemini")}function _(e={}){return f(X(e),"config")}function M(e={}){return f(_(e),"mcp_config.json")}function A(e={}){return f(_(e),"hooks.json")}function Q(e={}){return f(X(e),"antigravity-cli")}function Z(e="toolnet-memory",t={}){return f(Q(t),"plugins",e)}function ee(e={}){return[Q(e),_(e)]}import{homedir as ut}from"node:os";import{join as v}from"node:path";function g(e={}){let t=e.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return t?v(t,"opencode"):v(e.home??ut(),".config","opencode")}function te(e={}){return v(g(e),"opencode.json")}function ne(e={}){return v(g(e),"plugins")}function oe(e={}){return v(g(e),"AGENTS.md")}import{homedir as re}from"node:os";import{join as P}from"node:path";function F(e={}){return P(e.home??re(),".claude")}function se(e={}){return P(F(e),"settings.json")}function ie(e={}){return P(e.home??re(),".claude.json")}function ft(e){return gt("sh",["-lc",`command -v ${JSON.stringify(e)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function k(e){let t=e.commandExists(e.command),n=e.configPaths.filter(i=>dt(i)),o=n.length>0,s=[];t&&s.push(`command:${e.command}`);for(let i of n)s.push(`config:${i}`);return{agent:e.agent,detected:t||o,commandDetected:t,configDetected:o,evidence:s}}function ce(e={}){let t=e.home??mt(),n=e.commandExists??ft,o=e.codexHome??process.env.CODEX_HOME??pt(t,".codex");return[k({agent:"agy",command:"agy",commandExists:n,configPaths:ee({home:t})}),k({agent:"opencode",command:"opencode",commandExists:n,configPaths:[g({home:t,xdgConfigHome:e.xdgConfigHome})]}),k({agent:"claude",command:"claude",commandExists:n,configPaths:[F({home:t})]}),k({agent:"codex",command:"codex",commandExists:n,configPaths:[o]})]}import{existsSync as E,mkdirSync as pe,readFileSync as ge,renameSync as jt,writeFileSync as Rt}from"node:fs";import{dirname as Nt,join as I}from"node:path";import{existsSync as yt,mkdirSync as ht,readFileSync as vt,renameSync as bt,rmSync as xt,writeFileSync as St}from"node:fs";import{dirname as wt}from"node:path";function Ct(e){return`'${e.replace(/'/g,"'\\''")}'`}function ae(e={}){let t=e.hooksFile??A();ht(wt(t),{recursive:!0,mode:448});let n={};if(yt(t)){let r;try{r=JSON.parse(vt(t,"utf8"))}catch(c){throw new Error(`Invalid existing Agy hooks.json: ${c instanceof Error?c.message:String(c)}`)}if(typeof r!="object"||r===null||Array.isArray(r))throw new Error("Invalid existing Agy hooks.json: root must be a JSON object.");n=r}let o=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`${Ct(o)} session:agy-hook`;n["toolnet-memory"]={enabled:!0,PreToolUse:[{matcher:"view_file|list_dir|find_by_name|grep_search|run_command",hooks:[{type:"command",command:`${s} pre-tool`,timeout:5}]}],PreInvocation:[{type:"command",command:`${s} pre`,timeout:15}],PostInvocation:[{type:"command",command:`${s} post`,timeout:15}],Stop:[{type:"command",command:`${s} stop`,timeout:30}]};let i=`${t}.tmp-${process.pid}-${Date.now()}`;try{St(i,JSON.stringify(n,null,2)+`
7
- `,{encoding:"utf8",mode:384}),bt(i,t)}finally{xt(i,{force:!0})}return t}import{existsSync as Ot,mkdirSync as Mt,readFileSync as At,renameSync as kt,writeFileSync as It}from"node:fs";import{dirname as Et}from"node:path";function b(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Tt(e,t){Mt(Et(e),{recursive:!0,mode:448});let n=`${e}.tmp-${process.pid}-${Date.now()}`;It(n,`${JSON.stringify(t,null,2)}
8
- `,{encoding:"utf8",mode:384}),kt(n,e)}function le(e){if(!Ot(e))return{};let t=At(e,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(o){throw new Error(`Invalid existing Agy MCP config: ${o instanceof Error?o.message:String(o)}`)}if(!b(n))throw new Error("Invalid existing Agy MCP config: root must be a JSON object.");return n}function ue(e,t){return b(e)?e.command===t&&Array.isArray(e.args)&&e.args.length===1&&e.args[0]==="mcp":!1}function de(e={}){let t=e.configFile??M(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",s=le(t),i=s.mcpServers;if(i!==void 0&&!b(i))throw new Error("Invalid existing Agy MCP config: mcpServers must be an object.");let r=b(i)?{...i}:{},c=r[o];if(ue(c,n))return{installed:!0,changed:!1,configFile:t,serverName:o,command:n,args:["mcp"]};r[o]={command:n,args:["mcp"]};let l={...s,mcpServers:r};Tt(t,l);let u=le(t).mcpServers;if(!b(u)||!ue(u[o],n))throw new Error("Agy MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:t,serverName:o,command:n,args:["mcp"]}}var _t=`# ToolNet Memory Continuity
6
+ `),this.active=!1}};async function N(e,t,n={}){let o=new j(e,n).start();try{let s=await t();return o.succeed(),s}catch(s){throw o.fail(),s}}import{existsSync as mt}from"node:fs";import{homedir as pt}from"node:os";import{join as gt}from"node:path";import{spawnSync as ft}from"node:child_process";import{homedir as ut}from"node:os";import{join as f}from"node:path";function X(e={}){return f(e.home??ut(),".gemini")}function _(e={}){return f(X(e),"config")}function M(e={}){return f(_(e),"mcp_config.json")}function I(e={}){return f(_(e),"hooks.json")}function Z(e={}){return f(X(e),"antigravity-cli")}function ee(e="toolnet-memory",t={}){return f(Z(t),"plugins",e)}function te(e={}){return[Z(e),_(e)]}import{homedir as dt}from"node:os";import{join as v}from"node:path";function g(e={}){let t=e.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return t?v(t,"opencode"):v(e.home??dt(),".config","opencode")}function ne(e={}){return v(g(e),"opencode.json")}function oe(e={}){return v(g(e),"plugins")}function re(e={}){return v(g(e),"AGENTS.md")}import{homedir as se}from"node:os";import{join as P}from"node:path";function F(e={}){return P(e.home??se(),".claude")}function ie(e={}){return P(F(e),"settings.json")}function ae(e={}){return P(e.home??se(),".claude.json")}function yt(e){return ft("sh",["-lc",`command -v ${JSON.stringify(e)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function A(e){let t=e.commandExists(e.command),n=e.configPaths.filter(i=>mt(i)),o=n.length>0,s=[];t&&s.push(`command:${e.command}`);for(let i of n)s.push(`config:${i}`);return{agent:e.agent,detected:t||o,commandDetected:t,configDetected:o,evidence:s}}function ce(e={}){let t=e.home??pt(),n=e.commandExists??yt,o=e.codexHome??process.env.CODEX_HOME??gt(t,".codex");return[A({agent:"agy",command:"agy",commandExists:n,configPaths:te({home:t})}),A({agent:"opencode",command:"opencode",commandExists:n,configPaths:[g({home:t,xdgConfigHome:e.xdgConfigHome})]}),A({agent:"claude",command:"claude",commandExists:n,configPaths:[F({home:t})]}),A({agent:"codex",command:"codex",commandExists:n,configPaths:[o]})]}import{existsSync as T,mkdirSync as ge,readFileSync as fe,renameSync as jt,writeFileSync as Nt}from"node:fs";import{dirname as _t,join as E}from"node:path";import{existsSync as ht,mkdirSync as vt,readFileSync as bt,renameSync as xt,rmSync as St,writeFileSync as wt}from"node:fs";import{dirname as Ot}from"node:path";function Ct(e){return`'${e.replace(/'/g,"'\\''")}'`}function le(e={}){let t=e.hooksFile??I();vt(Ot(t),{recursive:!0,mode:448});let n={};if(ht(t)){let r;try{r=JSON.parse(bt(t,"utf8"))}catch(a){throw new Error(`Invalid existing Agy hooks.json: ${a instanceof Error?a.message:String(a)}`)}if(typeof r!="object"||r===null||Array.isArray(r))throw new Error("Invalid existing Agy hooks.json: root must be a JSON object.");n=r}let o=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`${Ct(o)} session:agy-hook`;n["toolnet-memory"]={enabled:!0,PreToolUse:[{matcher:"view_file|list_dir|find_by_name|grep_search|run_command",hooks:[{type:"command",command:`${s} pre-tool`,timeout:5}]}],PreInvocation:[{type:"command",command:`${s} pre`,timeout:15}],PostInvocation:[{type:"command",command:`${s} post`,timeout:15}],Stop:[{type:"command",command:`${s} stop`,timeout:30}]};let i=`${t}.tmp-${process.pid}-${Date.now()}`;try{wt(i,JSON.stringify(n,null,2)+`
7
+ `,{encoding:"utf8",mode:384}),xt(i,t)}finally{St(i,{force:!0})}return t}import{existsSync as Mt,mkdirSync as It,readFileSync as At,renameSync as Et,writeFileSync as Tt}from"node:fs";import{dirname as kt}from"node:path";function b(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Rt(e,t){It(kt(e),{recursive:!0,mode:448});let n=`${e}.tmp-${process.pid}-${Date.now()}`;Tt(n,`${JSON.stringify(t,null,2)}
8
+ `,{encoding:"utf8",mode:384}),Et(n,e)}function ue(e){if(!Mt(e))return{};let t=At(e,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(o){throw new Error(`Invalid existing Agy MCP config: ${o instanceof Error?o.message:String(o)}`)}if(!b(n))throw new Error("Invalid existing Agy MCP config: root must be a JSON object.");return n}function de(e,t){return b(e)?e.command===t&&Array.isArray(e.args)&&e.args.length===1&&e.args[0]==="mcp":!1}function me(e={}){let t=e.configFile??M(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",s=ue(t),i=s.mcpServers;if(i!==void 0&&!b(i))throw new Error("Invalid existing Agy MCP config: mcpServers must be an object.");let r=b(i)?{...i}:{},a=r[o];if(de(a,n))return{installed:!0,changed:!1,configFile:t,serverName:o,command:n,args:["mcp"]};r[o]={command:n,args:["mcp"]};let l={...s,mcpServers:r};Rt(t,l);let u=ue(t).mcpServers;if(!b(u)||!de(u[o],n))throw new Error("Agy MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:t,serverName:o,command:n,args:["mcp"]}}var Pt=`# ToolNet Memory Continuity
9
9
 
10
10
  ToolNet Memory is the authoritative continuity layer for previous project work.
11
11
 
@@ -46,15 +46,15 @@ Use \`mode="ai"\` only when continuity is ambiguous or requires synthesis.
46
46
  Current repository evidence overrides stale memory after ToolNet has restored the working context.
47
47
 
48
48
  Do not ask the user to repeat context already available through ToolNet Memory.
49
- `;function fe(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function D(e,t){pe(Nt(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;Rt(n,t,{encoding:"utf8",mode:384}),jt(n,e)}function me(e,t){E(e)&&ge(e,"utf8")===t||D(e,t)}function ye(e){if(!E(e))return{};let t=ge(e,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(o){throw new Error(`Invalid legacy Antigravity config ${e}: ${o instanceof Error?o.message:String(o)}`)}if(!fe(n))throw new Error(`Invalid legacy Antigravity config ${e}: root must be object`);return n}function Pt(e,t){if(!E(e))return!1;let n=ye(e);if(!fe(n.mcpServers)||!Object.prototype.hasOwnProperty.call(n.mcpServers,t))return!1;let o={...n.mcpServers};return delete o[t],D(e,`${JSON.stringify({...n,mcpServers:o},null,2)}
50
- `),!0}function Ft(e){if(!E(e))return!1;let t=ye(e);if(!Object.prototype.hasOwnProperty.call(t,"toolnet-memory"))return!1;let n={...t};return delete n["toolnet-memory"],D(e,`${JSON.stringify(n,null,2)}
51
- `),!0}function he(e={}){let t=e.pluginName??"toolnet-memory",n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.pluginRoot??Z(t),s=I(o,"plugin.json"),i=I(o,"mcp_config.json"),r=I(o,"hooks.json"),c=I(o,"rules","toolnet-memory-continuity.md");pe(o,{recursive:!0,mode:448}),me(s,`${JSON.stringify({$schema:"https://antigravity.google/schemas/v1/plugin.json",name:t,description:"Persistent project continuity and memory for Antigravity coding sessions."},null,2)}
52
- `),de({configFile:i,binary:n,serverName:"toolnet-memory"}),ae({hooksFile:r,binary:n}),me(c,`${_t.trim()}
53
- `);let l=e.legacyMcpFile??M(),a=e.legacyHooksFile??A(),u=[];return l!==i&&Pt(l,"toolnet-memory")&&u.push(l),a!==r&&Ft(a)&&u.push(a),{installed:!0,pluginRoot:o,files:[s,i,r,c],migratedLegacy:u}}import{existsSync as $t,mkdirSync as xe,readFileSync as Lt,writeFileSync as Se}from"node:fs";import{join as Jt}from"node:path";var Dt="memory_agent_ask";function ve(){return`
49
+ `;function ye(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function D(e,t){ge(_t(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;Nt(n,t,{encoding:"utf8",mode:384}),jt(n,e)}function pe(e,t){T(e)&&fe(e,"utf8")===t||D(e,t)}function he(e){if(!T(e))return{};let t=fe(e,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(o){throw new Error(`Invalid legacy Antigravity config ${e}: ${o instanceof Error?o.message:String(o)}`)}if(!ye(n))throw new Error(`Invalid legacy Antigravity config ${e}: root must be object`);return n}function Ft(e,t){if(!T(e))return!1;let n=he(e);if(!ye(n.mcpServers)||!Object.prototype.hasOwnProperty.call(n.mcpServers,t))return!1;let o={...n.mcpServers};return delete o[t],D(e,`${JSON.stringify({...n,mcpServers:o},null,2)}
50
+ `),!0}function Dt(e){if(!T(e))return!1;let t=he(e);if(!Object.prototype.hasOwnProperty.call(t,"toolnet-memory"))return!1;let n={...t};return delete n["toolnet-memory"],D(e,`${JSON.stringify(n,null,2)}
51
+ `),!0}function ve(e={}){let t=e.pluginName??"toolnet-memory",n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.pluginRoot??ee(t),s=E(o,"plugin.json"),i=E(o,"mcp_config.json"),r=E(o,"hooks.json"),a=E(o,"rules","toolnet-memory-continuity.md");ge(o,{recursive:!0,mode:448}),pe(s,`${JSON.stringify({$schema:"https://antigravity.google/schemas/v1/plugin.json",name:t,description:"Persistent project continuity and memory for Antigravity coding sessions."},null,2)}
52
+ `),me({configFile:i,binary:n,serverName:"toolnet-memory"}),le({hooksFile:r,binary:n}),pe(a,`${Pt.trim()}
53
+ `);let l=e.legacyMcpFile??M(),c=e.legacyHooksFile??I(),u=[];return l!==i&&Ft(l,"toolnet-memory")&&u.push(l),c!==r&&Dt(c)&&u.push(c),{installed:!0,pluginRoot:o,files:[s,i,r,a],migratedLegacy:u}}import{existsSync as Lt,mkdirSync as Se,readFileSync as Jt,writeFileSync as we}from"node:fs";import{join as Bt}from"node:path";var $t="memory_agent_ask";function be(){return`
54
54
  [TOOLNET MEMORY AGENT]
55
55
 
56
56
  Tool available:
57
- - ${Dt}
57
+ - ${$t}
58
58
 
59
59
  Use it automatically BEFORE guessing when:
60
60
 
@@ -101,7 +101,7 @@ Rules:
101
101
  - After receiving the ToolNet answer, continue the task
102
102
  instead of asking the user to repeat known context.
103
103
  - If ToolNet says information is not recorded, say so.
104
- `.trim()}var be="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",$="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function Yt(){let e=oe();xe(g(),{recursive:!0});let t=`${be}
104
+ `.trim()}var xe="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",$="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function Ht(){let e=re();Se(g(),{recursive:!0});let t=`${xe}
105
105
  ## ToolNet Memory
106
106
 
107
107
  ToolNet Memory is available for projects that already contain a valid \`.toolnet/project.json\`.
@@ -117,12 +117,12 @@ Rules:
117
117
  7. Current repository evidence has priority over stale memory when they conflict.
118
118
 
119
119
 
120
- ${ve()}
120
+ ${be()}
121
121
 
122
- ${$}`,n=$t(e)?Lt(e,"utf8"):"",o=n.indexOf(be),s=n.indexOf($);return o>=0&&s>=o?n=n.slice(0,o)+t+n.slice(s+$.length):(n=n.trimEnd(),n&&(n+=`
122
+ ${$}`,n=Lt(e)?Jt(e,"utf8"):"",o=n.indexOf(xe),s=n.indexOf($);return o>=0&&s>=o?n=n.slice(0,o)+t+n.slice(s+$.length):(n=n.trimEnd(),n&&(n+=`
123
123
 
124
- `),n+=t),Se(e,n.trimEnd()+`
125
- `,{encoding:"utf8",mode:384}),e}function we(e={}){let t=e.directory??ne();xe(t,{recursive:!0}),Yt();let n=Jt(t,"toolnet-memory.js"),o=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`
124
+ `),n+=t),we(e,n.trimEnd()+`
125
+ `,{encoding:"utf8",mode:384}),e}function Oe(e={}){let t=e.directory??oe();Se(t,{recursive:!0}),Ht();let n=Bt(t,"toolnet-memory.js"),o=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",s=`
126
126
  // Generated by ToolNet Memory.
127
127
  // OpenCode integration:
128
128
  // - project gated
@@ -142,22 +142,52 @@ const CONTEXT_MAX_TOKENS = 700
142
142
 
143
143
  const CONTEXT_CACHE_MS = 5000
144
144
 
145
- const PERIODIC_SYNC_MS = 30000
145
+ const LOCAL_CAPTURE_MS = 15000
146
146
 
147
- const SYNC_TIMEOUT_MS = 15000
147
+ const REMOTE_SYNC_MS = 60000
148
148
 
149
- const STATUS_FILE = path.join(
149
+ const EVENT_CAPTURE_DEBOUNCE_MS = 1200
150
+
151
+ const CAPTURE_TIMEOUT_MS = 20000
152
+
153
+ const REMOTE_TIMEOUT_MS = 120000
154
+
155
+ const GLOBAL_STATUS_FILE = path.join(
150
156
  os.homedir(),
151
157
  ".config",
152
158
  "toolnet-memory",
153
159
  "opencode-sync-status.json"
154
160
  )
155
161
 
162
+ function projectStatusFile(
163
+ data
164
+ ) {
165
+ if (
166
+ typeof data?.projectRoot ===
167
+ "string" &&
168
+ data.projectRoot.length > 0
169
+ ) {
170
+ return path.join(
171
+ data.projectRoot,
172
+ ".toolnet",
173
+ "runtime",
174
+ "opencode-status.json"
175
+ )
176
+ }
177
+
178
+ return GLOBAL_STATUS_FILE
179
+ }
180
+
156
181
  function writeStatus(data) {
157
182
  try {
183
+ const statusFile =
184
+ projectStatusFile(
185
+ data
186
+ )
187
+
158
188
  fs.mkdirSync(
159
189
  path.dirname(
160
- STATUS_FILE
190
+ statusFile
161
191
  ),
162
192
  {
163
193
  recursive: true,
@@ -165,7 +195,7 @@ function writeStatus(data) {
165
195
  )
166
196
 
167
197
  fs.writeFileSync(
168
- STATUS_FILE,
198
+ statusFile,
169
199
  JSON.stringify(
170
200
  {
171
201
  timestamp:
@@ -292,7 +322,7 @@ async function runWithTimeout(
292
322
  {
293
323
  stdout = "ignore",
294
324
  timeout =
295
- SYNC_TIMEOUT_MS,
325
+ REMOTE_TIMEOUT_MS,
296
326
  } = {}
297
327
  ) {
298
328
  const child =
@@ -394,14 +424,67 @@ export const ToolNetMemoryPlugin =
394
424
  let lastSessionId =
395
425
  null
396
426
 
397
- let syncChain =
427
+ /*
428
+ * Two independent lanes:
429
+ *
430
+ * captureChain:
431
+ * OpenCode DB -> local fsync WAL -> current work
432
+ *
433
+ * remoteInFlight:
434
+ * WAL -> Hugging Face / S3
435
+ *
436
+ * A slow remote backend must never block local capture.
437
+ */
438
+ let captureChain =
398
439
  Promise.resolve()
399
440
 
441
+ let remoteInFlight =
442
+ null
443
+
444
+ let debounceTimer =
445
+ null
446
+
400
447
  let contextCache = {
401
448
  value: "",
402
449
  expiresAt: 0,
403
450
  }
404
451
 
452
+ /*
453
+ * Compact startup context is injected once
454
+ * per native OpenCode session.
455
+ *
456
+ * Deep history is retrieved through
457
+ * memory_agent_ask / MCP on demand.
458
+ */
459
+ const injectedSessions =
460
+ new Set()
461
+
462
+ function contextSessionKey(
463
+ input
464
+ ) {
465
+ const candidates = [
466
+ input?.sessionID,
467
+ input?.sessionId,
468
+ input?.session?.id,
469
+ input?.info?.id,
470
+ lastSessionId,
471
+ ]
472
+
473
+ const sessionId =
474
+ candidates.find(
475
+ value =>
476
+ typeof value ===
477
+ "string" &&
478
+ value.length > 0
479
+ )
480
+
481
+ return sessionId
482
+ ? "session:" +
483
+ sessionId
484
+ : "project:" +
485
+ projectRoot
486
+ }
487
+
405
488
  async function readContext() {
406
489
  const now =
407
490
  Date.now()
@@ -473,8 +556,13 @@ export const ToolNetMemoryPlugin =
473
556
 
474
557
  async function syncNow(
475
558
  sessionId,
476
- flag,
477
- reason
559
+ {
560
+ flag = null,
561
+ reason = "unknown",
562
+ localOnly = false,
563
+ timeout =
564
+ REMOTE_TIMEOUT_MS,
565
+ } = {}
478
566
  ) {
479
567
  if (!sessionId) {
480
568
  return
@@ -494,9 +582,18 @@ export const ToolNetMemoryPlugin =
494
582
  )
495
583
  }
496
584
 
585
+ if (localOnly) {
586
+ args.push(
587
+ "--local-only"
588
+ )
589
+ }
590
+
497
591
  try {
498
592
  await runWithTimeout(
499
- args
593
+ args,
594
+ {
595
+ timeout,
596
+ }
500
597
  )
501
598
 
502
599
  writeStatus({
@@ -504,8 +601,14 @@ export const ToolNetMemoryPlugin =
504
601
  projectRoot,
505
602
  sessionId,
506
603
  reason,
604
+ mode:
605
+ localOnly
606
+ ? "local"
607
+ : "remote",
507
608
  state:
508
- "sync-success",
609
+ localOnly
610
+ ? "capture-success"
611
+ : "sync-success",
509
612
  })
510
613
  } catch (error) {
511
614
  writeStatus({
@@ -513,8 +616,14 @@ export const ToolNetMemoryPlugin =
513
616
  projectRoot,
514
617
  sessionId,
515
618
  reason,
619
+ mode:
620
+ localOnly
621
+ ? "local"
622
+ : "remote",
516
623
  state:
517
- "sync-failed",
624
+ localOnly
625
+ ? "capture-failed"
626
+ : "sync-failed",
518
627
  error:
519
628
  error instanceof
520
629
  Error
@@ -528,20 +637,24 @@ export const ToolNetMemoryPlugin =
528
637
  }
529
638
  }
530
639
 
531
- function queueSync(
640
+ function queueCapture(
532
641
  sessionId,
533
642
  flag,
534
643
  reason
535
644
  ) {
536
645
  if (!sessionId) {
537
- return syncChain
646
+ return captureChain
538
647
  }
539
648
 
540
649
  lastSessionId =
541
650
  sessionId
542
651
 
543
- syncChain =
544
- syncChain
652
+ /*
653
+ * Local captures are serialized with each other,
654
+ * but completely independent from remote sync.
655
+ */
656
+ captureChain =
657
+ captureChain
545
658
  .catch(
546
659
  () =>
547
660
  undefined
@@ -550,46 +663,162 @@ export const ToolNetMemoryPlugin =
550
663
  () =>
551
664
  syncNow(
552
665
  sessionId,
553
- flag,
554
- reason
666
+ {
667
+ flag,
668
+ reason,
669
+ localOnly: true,
670
+ timeout:
671
+ CAPTURE_TIMEOUT_MS,
672
+ }
555
673
  )
556
674
  )
675
+ .catch(
676
+ () =>
677
+ undefined
678
+ )
679
+
680
+ return captureChain
681
+ }
682
+
683
+ function queueRemote(
684
+ sessionId,
685
+ flag,
686
+ reason
687
+ ) {
688
+ if (!sessionId) {
689
+ return Promise.resolve()
690
+ }
691
+
692
+ lastSessionId =
693
+ sessionId
694
+
695
+ /*
696
+ * Never build an endless remote backlog.
697
+ * One remote flush is enough because WAL keeps
698
+ * every pending local event until acknowledged.
699
+ */
700
+ if (remoteInFlight) {
701
+ return remoteInFlight
702
+ }
703
+
704
+ remoteInFlight =
705
+ syncNow(
706
+ sessionId,
707
+ {
708
+ flag,
709
+ reason,
710
+ localOnly: false,
711
+ timeout:
712
+ REMOTE_TIMEOUT_MS,
713
+ }
714
+ )
715
+ .catch(
716
+ () =>
717
+ undefined
718
+ )
719
+ .finally(
720
+ () => {
721
+ remoteInFlight =
722
+ null
723
+ }
724
+ )
725
+
726
+ return remoteInFlight
727
+ }
728
+
729
+ function scheduleCapture(
730
+ sessionId,
731
+ reason
732
+ ) {
733
+ if (!sessionId) {
734
+ return
735
+ }
736
+
737
+ if (debounceTimer) {
738
+ clearTimeout(
739
+ debounceTimer
740
+ )
741
+ }
742
+
743
+ debounceTimer =
744
+ setTimeout(
745
+ () => {
746
+ debounceTimer =
747
+ null
748
+
749
+ void queueCapture(
750
+ sessionId,
751
+ null,
752
+ reason
753
+ )
754
+ },
755
+ EVENT_CAPTURE_DEBOUNCE_MS
756
+ )
557
757
 
558
- return syncChain
758
+ if (
759
+ typeof debounceTimer.unref ===
760
+ "function"
761
+ ) {
762
+ debounceTimer.unref()
763
+ }
559
764
  }
560
765
 
561
766
  /*
562
- * Periodic durability checkpoint.
767
+ * Crash-safe LOCAL checkpoint.
563
768
  *
564
- * This is intentionally independent
565
- * from session.idle/dispose because
566
- * abrupt SSH/process termination may
567
- * skip shutdown hooks.
769
+ * Fast lane:
770
+ * OpenCode DB -> fsync WAL -> current work.
568
771
  *
569
- * unref() prevents the timer itself
570
- * from keeping OpenCode alive.
772
+ * No network dependency.
571
773
  */
572
- const periodic =
774
+ const localPeriodic =
573
775
  setInterval(
574
776
  () => {
575
777
  if (
576
778
  lastSessionId
577
779
  ) {
578
- void queueSync(
780
+ void queueCapture(
579
781
  lastSessionId,
580
782
  null,
581
- "periodic"
783
+ "periodic-local"
582
784
  )
583
785
  }
584
786
  },
585
- PERIODIC_SYNC_MS
787
+ LOCAL_CAPTURE_MS
586
788
  )
587
789
 
588
- if (
589
- typeof periodic.unref ===
590
- "function"
790
+ /*
791
+ * Remote durability is deliberately slower
792
+ * and independent from the local lane.
793
+ */
794
+ const remotePeriodic =
795
+ setInterval(
796
+ () => {
797
+ if (
798
+ lastSessionId
799
+ ) {
800
+ void queueRemote(
801
+ lastSessionId,
802
+ null,
803
+ "periodic-remote"
804
+ )
805
+ }
806
+ },
807
+ REMOTE_SYNC_MS
808
+ )
809
+
810
+ for (
811
+ const timer of [
812
+ localPeriodic,
813
+ remotePeriodic,
814
+ ]
591
815
  ) {
592
- periodic.unref()
816
+ if (
817
+ typeof timer.unref ===
818
+ "function"
819
+ ) {
820
+ timer.unref()
821
+ }
593
822
  }
594
823
 
595
824
  return {
@@ -606,14 +835,39 @@ export const ToolNetMemoryPlugin =
606
835
  sessionId
607
836
  }
608
837
 
838
+ const terminalEvent =
839
+ event.type ===
840
+ "session.idle" ||
841
+ event.type ===
842
+ "session.compacted" ||
843
+ event.type ===
844
+ "session.error"
845
+
846
+ if (
847
+ sessionId &&
848
+ !terminalEvent
849
+ ) {
850
+ scheduleCapture(
851
+ sessionId,
852
+ "event:" +
853
+ event.type
854
+ )
855
+ }
856
+
609
857
  if (
610
858
  event.type ===
611
859
  "session.idle"
612
860
  ) {
613
- await queueSync(
861
+ await queueCapture(
614
862
  sessionId,
615
863
  "--idle",
616
- "session.idle"
864
+ "session.idle:capture"
865
+ )
866
+
867
+ void queueRemote(
868
+ sessionId,
869
+ null,
870
+ "session.idle:remote"
617
871
  )
618
872
 
619
873
  return
@@ -623,10 +877,16 @@ export const ToolNetMemoryPlugin =
623
877
  event.type ===
624
878
  "session.compacted"
625
879
  ) {
626
- await queueSync(
880
+ await queueCapture(
627
881
  sessionId,
628
882
  "--compacted",
629
- "session.compacted"
883
+ "session.compacted:capture"
884
+ )
885
+
886
+ void queueRemote(
887
+ sessionId,
888
+ null,
889
+ "session.compacted:remote"
630
890
  )
631
891
 
632
892
  contextCache = {
@@ -641,10 +901,16 @@ export const ToolNetMemoryPlugin =
641
901
  event.type ===
642
902
  "session.error"
643
903
  ) {
644
- await queueSync(
904
+ await queueCapture(
645
905
  sessionId,
646
906
  "--error",
647
- "session.error"
907
+ "session.error:capture"
908
+ )
909
+
910
+ void queueRemote(
911
+ sessionId,
912
+ null,
913
+ "session.error:remote"
648
914
  )
649
915
 
650
916
  return
@@ -660,9 +926,26 @@ export const ToolNetMemoryPlugin =
660
926
  */
661
927
  "experimental.chat.system.transform":
662
928
  async (
663
- _input,
929
+ input,
664
930
  output
665
931
  ) => {
932
+ const injectionKey =
933
+ contextSessionKey(
934
+ input
935
+ )
936
+
937
+ /*
938
+ * Never inject ToolNet context on
939
+ * every model turn.
940
+ */
941
+ if (
942
+ injectedSessions.has(
943
+ injectionKey
944
+ )
945
+ ) {
946
+ return
947
+ }
948
+
666
949
  const context =
667
950
  await readContext()
668
951
 
@@ -679,6 +962,10 @@ export const ToolNetMemoryPlugin =
679
962
  context
680
963
  )
681
964
 
965
+ injectedSessions.add(
966
+ injectionKey
967
+ )
968
+
682
969
  return
683
970
  }
684
971
 
@@ -688,8 +975,14 @@ export const ToolNetMemoryPlugin =
688
975
  ) {
689
976
  output.system =
690
977
  output.system
691
- ? \`\${output.system}\\n\\n\${context}\`
978
+ ? output.system +
979
+ "\\n\\n" +
980
+ context
692
981
  : context
982
+
983
+ injectedSessions.add(
984
+ injectionKey
985
+ )
693
986
  }
694
987
  },
695
988
 
@@ -725,39 +1018,52 @@ export const ToolNetMemoryPlugin =
725
1018
  */
726
1019
  dispose: async () => {
727
1020
  clearInterval(
728
- periodic
1021
+ localPeriodic
1022
+ )
1023
+
1024
+ clearInterval(
1025
+ remotePeriodic
729
1026
  )
730
1027
 
1028
+ if (debounceTimer) {
1029
+ clearTimeout(
1030
+ debounceTimer
1031
+ )
1032
+ }
1033
+
1034
+ /*
1035
+ * On a clean exit we only REQUIRE the
1036
+ * fast local fsync checkpoint.
1037
+ *
1038
+ * Never hold OpenCode shutdown hostage
1039
+ * to a slow remote backend.
1040
+ */
731
1041
  if (
732
1042
  lastSessionId
733
1043
  ) {
734
- try {
735
- await queueSync(
736
- lastSessionId,
737
- "--idle",
738
- "dispose"
739
- )
740
- } catch {
741
- // Status already recorded.
742
- }
1044
+ await queueCapture(
1045
+ lastSessionId,
1046
+ "--idle",
1047
+ "dispose:capture"
1048
+ )
743
1049
  }
744
1050
 
745
1051
  try {
746
- await syncChain
1052
+ await captureChain
747
1053
  } catch {
748
- // Do not block OpenCode shutdown.
1054
+ // Fail open.
749
1055
  }
750
1056
  },
751
1057
  }
752
1058
  }
753
- `;return Se(n,s.trimStart(),{encoding:"utf8",mode:384}),n}import{existsSync as Me,mkdirSync as Ht,readFileSync as Bt,renameSync as zt,writeFileSync as Kt}from"node:fs";import{dirname as Ae,join as Ut}from"node:path";function y(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Vt(e,t){Ht(Ae(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;Kt(n,`${JSON.stringify(t,null,2)}
754
- `,{encoding:"utf8",mode:384}),zt(n,e)}function Ce(e){if(!Me(e))return{};let t=Bt(e,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(o){throw new Error(`Invalid existing OpenCode opencode.json: ${o instanceof Error?o.message:String(o)}`)}if(!y(n))throw new Error("Invalid existing OpenCode opencode.json: root must be a JSON object.");return n}function Oe(e,t){if(!y(e))return!1;let n=e.command;return e.type==="local"&&e.enabled!==!1&&Array.isArray(n)&&n.length===2&&n[0]===t&&n[1]==="mcp"}function Gt(e,t){let n=e.mcpServers;if(!y(n)||!Object.prototype.hasOwnProperty.call(n,t))return{root:e,changed:!1};let o={...n};return delete o[t],{root:{...e,mcpServers:o},changed:!0}}function ke(e={}){let t=e.configFile??te(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",s=Ut(Ae(t),"opencode.jsonc"),i=Me(s)?s:void 0,r=Ce(t),c=Gt(r,o),l=c.root,a=l.mcp;if(a!==void 0&&!y(a))throw new Error("Invalid existing OpenCode config: mcp must be an object.");let u=y(a)?{...a}:{},p=u[o];if(Oe(p,n)&&!c.changed)return{installed:!0,changed:!1,configFile:t,serverName:o,command:[n,"mcp"],preservedJsonc:i};u[o]={type:"local",command:[n,"mcp"],enabled:!0};let d={...l,mcp:u};Vt(t,d);let z=Ce(t);if(!y(z.mcp)||!Oe(z.mcp[o],n))throw new Error("OpenCode MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:t,serverName:o,command:[n,"mcp"],preservedJsonc:i}}import{existsSync as Wt,mkdirSync as Ie,readFileSync as qt,writeFileSync as Ee}from"node:fs";import{homedir as Te}from"node:os";import{dirname as je,join as L}from"node:path";function Xt(e){let t=[],n=/"((?:\\.|[^"\\])*)"|'([^']*)'/g,o;for(;o=n.exec(e);){let s=o[1]??o[2]??"";try{t.push(o[1]!==void 0?JSON.parse(`"${s}"`):s)}catch{t.push(s)}}return t}function Re(e={}){let t=e.configFile??L(process.env.CODEX_HOME??L(Te(),".codex"),"config.toml"),n=e.previousFile??L(Te(),".config","toolnet-memory","codex-notify-previous.json");Ie(je(t),{recursive:!0}),Ie(je(n),{recursive:!0});let o=Wt(t)?qt(t,"utf8"):"",s=e.binary??"toolnet-memory",i=`notify = [${JSON.stringify(s)}, "session:codex-notify"]`,r=o.split(`
755
- `),c=r.findIndex(d=>/^\s*\[/.test(d));c<0&&(c=r.length);let l=-1,a=-1;for(let d=0;d<c;d+=1)if(/^\s*notify\s*=/.test(r[d])){if(l=d,a=d,r[d].includes("[")&&!r[d].includes("]"))for(;a+1<c&&(a+=1,!r[a].includes("]")););break}let u=[];if(l>=0){let d=r.slice(l,a+1).join(`
756
- `);u=Xt(d),r.splice(l,a-l+1,i)}else c=r.findIndex(d=>/^\s*\[/.test(d)),c<0&&(c=r.length),r.splice(c,0,i);let p=u.length>=2&&u[u.length-1]==="session:codex-notify";return u.length>0&&!p&&Ee(n,JSON.stringify(u,null,2)+`
1059
+ `;return we(n,s.trimStart(),{encoding:"utf8",mode:384}),n}import{existsSync as Ie,mkdirSync as Yt,readFileSync as zt,renameSync as Ut,writeFileSync as Kt}from"node:fs";import{dirname as Ae,join as Vt}from"node:path";function y(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Wt(e,t){Yt(Ae(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;Kt(n,`${JSON.stringify(t,null,2)}
1060
+ `,{encoding:"utf8",mode:384}),Ut(n,e)}function Ce(e){if(!Ie(e))return{};let t=zt(e,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(o){throw new Error(`Invalid existing OpenCode opencode.json: ${o instanceof Error?o.message:String(o)}`)}if(!y(n))throw new Error("Invalid existing OpenCode opencode.json: root must be a JSON object.");return n}function Me(e,t){if(!y(e))return!1;let n=e.command;return e.type==="local"&&e.enabled!==!1&&Array.isArray(n)&&n.length===2&&n[0]===t&&n[1]==="mcp"}function Gt(e,t){let n=e.mcpServers;if(!y(n)||!Object.prototype.hasOwnProperty.call(n,t))return{root:e,changed:!1};let o={...n};return delete o[t],{root:{...e,mcpServers:o},changed:!0}}function Ee(e={}){let t=e.configFile??ne(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",s=Vt(Ae(t),"opencode.jsonc"),i=Ie(s)?s:void 0,r=Ce(t),a=Gt(r,o),l=a.root,c=l.mcp;if(c!==void 0&&!y(c))throw new Error("Invalid existing OpenCode config: mcp must be an object.");let u=y(c)?{...c}:{},p=u[o];if(Me(p,n)&&!a.changed)return{installed:!0,changed:!1,configFile:t,serverName:o,command:[n,"mcp"],preservedJsonc:i};u[o]={type:"local",command:[n,"mcp"],enabled:!0};let d={...l,mcp:u};Wt(t,d);let z=Ce(t);if(!y(z.mcp)||!Me(z.mcp[o],n))throw new Error("OpenCode MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:t,serverName:o,command:[n,"mcp"],preservedJsonc:i}}import{existsSync as qt,mkdirSync as Te,readFileSync as Qt,writeFileSync as ke}from"node:fs";import{homedir as Re}from"node:os";import{dirname as je,join as L}from"node:path";function Xt(e){let t=[],n=/"((?:\\.|[^"\\])*)"|'([^']*)'/g,o;for(;o=n.exec(e);){let s=o[1]??o[2]??"";try{t.push(o[1]!==void 0?JSON.parse(`"${s}"`):s)}catch{t.push(s)}}return t}function Ne(e={}){let t=e.configFile??L(process.env.CODEX_HOME??L(Re(),".codex"),"config.toml"),n=e.previousFile??L(Re(),".config","toolnet-memory","codex-notify-previous.json");Te(je(t),{recursive:!0}),Te(je(n),{recursive:!0});let o=qt(t)?Qt(t,"utf8"):"",s=e.binary??"toolnet-memory",i=`notify = [${JSON.stringify(s)}, "session:codex-notify"]`,r=o.split(`
1061
+ `),a=r.findIndex(d=>/^\s*\[/.test(d));a<0&&(a=r.length);let l=-1,c=-1;for(let d=0;d<a;d+=1)if(/^\s*notify\s*=/.test(r[d])){if(l=d,c=d,r[d].includes("[")&&!r[d].includes("]"))for(;c+1<a&&(c+=1,!r[c].includes("]")););break}let u=[];if(l>=0){let d=r.slice(l,c+1).join(`
1062
+ `);u=Xt(d),r.splice(l,c-l+1,i)}else a=r.findIndex(d=>/^\s*\[/.test(d)),a<0&&(a=r.length),r.splice(a,0,i);let p=u.length>=2&&u[u.length-1]==="session:codex-notify";return u.length>0&&!p&&ke(n,JSON.stringify(u,null,2)+`
757
1063
  `,{encoding:"utf8",mode:384}),o=r.join(`
758
1064
  `),o.endsWith(`
759
1065
  `)||(o+=`
760
- `),Ee(t,o,{encoding:"utf8",mode:384}),{configFile:t,previousFile:n,preservedPrevious:u.length>0&&!p}}import{existsSync as Qt,mkdirSync as Zt,readFileSync as en,writeFileSync as tn}from"node:fs";import{homedir as nn}from"node:os";import{dirname as on,join as Ne}from"node:path";function rn(e){return`'${e.replace(/'/g,"'\\''")}'`}function _e(e={}){let t=e.hooksFile??Ne(process.env.CODEX_HOME??Ne(nn(),".codex"),"hooks.json");Zt(on(t),{recursive:!0});let n={};if(Qt(t))try{n=JSON.parse(en(t,"utf8"))}catch(c){throw new Error(`Invalid existing Codex hooks.json: ${c instanceof Error?c.message:String(c)}`)}let o=n.hooks&&typeof n.hooks=="object"&&!Array.isArray(n.hooks)?n.hooks:{};n.hooks=o;let i=(Array.isArray(o.SessionStart)?o.SessionStart:[]).filter(c=>{try{return!JSON.stringify(c).includes("session:codex-context")}catch{return!0}}),r=e.binary??"toolnet-memory";return i.push({matcher:"startup|resume|clear|compact",hooks:[{type:"command",command:`${rn(r)} session:codex-context`,timeout:15,additionalContextLimit:1e3,statusMessage:"Loading ToolNet project continuity"}]}),o.SessionStart=i,tn(t,JSON.stringify(n,null,2)+`
761
- `,{encoding:"utf8",mode:384}),t}import{spawnSync as sn}from"node:child_process";function J(e,t){return sn(e,t,{encoding:"utf8",stdio:["ignore","pipe","pipe"]})}function Pe(e,t){let n=J(e,["mcp","get",t,"--json"]);if(n.status!==0||!n.stdout)return null;try{return JSON.parse(n.stdout)}catch{return null}}function Fe(e,t){return e.enabled!==!1&&e.transport?.type==="stdio"&&e.transport?.command===t&&Array.isArray(e.transport?.args)&&e.transport?.args.length===1&&e.transport.args[0]==="mcp"}function De(e={}){let t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=e.codexBinary??"codex",o=e.serverName??"toolnet-memory",s=Pe(n,o);if(s&&Fe(s,t))return{installed:!0,changed:!1,serverName:o,command:t,args:["mcp"]};if(s){let c=J(n,["mcp","remove",o]);if(c.status!==0)return{installed:!1,changed:!1,serverName:o,command:t,args:["mcp"],error:(c.stderr||c.stdout||"Unable to remove old ToolNet MCP configuration.").trim()}}let i=J(n,["mcp","add",o,"--",t,"mcp"]);if(i.status!==0)return{installed:!1,changed:!1,serverName:o,command:t,args:["mcp"],error:(i.stderr||i.stdout||"Unable to register ToolNet MCP.").trim()};let r=Pe(n,o);return!r||!Fe(r,t)?{installed:!1,changed:!0,serverName:o,command:t,args:["mcp"],error:"Codex accepted MCP registration but verification did not match expected ToolNet command."}:{installed:!0,changed:!0,serverName:o,command:t,args:["mcp"]}}import{existsSync as cn,mkdirSync as an,readFileSync as ln,renameSync as un,rmSync as dn,writeFileSync as mn}from"node:fs";import{dirname as pn}from"node:path";function x(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function gn(e){return/^[A-Za-z0-9_./:-]+$/u.test(e)?e:`'${e.replace(/'/gu,"'\\''")}'`}function fn(e){if(!cn(e))return{};let t;try{t=JSON.parse(ln(e,"utf8"))}catch(n){throw new Error(`Invalid existing Claude settings.json: ${n instanceof Error?n.message:String(n)}`)}if(!x(t))throw new Error("Invalid existing Claude settings.json: root must be a JSON object.");return t}function Y(e){if(e===void 0)return[];if(!Array.isArray(e))throw new Error("Invalid existing Claude settings.json: hook event must be an array.");let t=[];for(let n of e){if(!x(n)){t.push(n);continue}let o=n.hooks;if(!Array.isArray(o)){t.push(n);continue}let s=o.filter(i=>{if(!x(i))return!0;let r=i.command;return!(typeof r=="string"&&r.includes("session:claude-hook"))});s.length!==0&&t.push({...n,hooks:s})}return t}function H(e){return{type:"command",command:e,timeout:10}}function yn(e,t){an(pn(e),{recursive:!0,mode:448});let n=`${e}.toolnet-${process.pid}-${Date.now()}.tmp`;try{mn(n,JSON.stringify(t,null,2)+`
762
- `,{encoding:"utf8",mode:384}),un(n,e)}finally{dn(n,{force:!0})}}function $e(e={}){let t=e.settingsFile??se(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=fn(t),s=o.hooks;if(s!==void 0&&!x(s))throw new Error("Invalid existing Claude settings.json: hooks must be an object.");let i=x(s)?{...s}:{},r=`${gn(n)} session:claude-hook`,c=Y(i.SessionStart);c.push({matcher:"startup|resume|clear|compact",hooks:[H(r)]}),i.SessionStart=c;let l=Y(i.PostToolUse);l.push({matcher:"Edit|Write",hooks:[H(r)]}),i.PostToolUse=l;let a=Y(i.Stop);a.push({hooks:[H(r)]}),i.Stop=a;let u={...o,hooks:i},p=JSON.stringify(o),d=JSON.stringify(u);return p===d?{settingsFile:t,changed:!1}:(yn(t,u),{settingsFile:t,changed:!0})}import{existsSync as hn,mkdirSync as vn,readFileSync as bn,renameSync as xn,rmSync as Sn,writeFileSync as wn}from"node:fs";import{dirname as Cn}from"node:path";function S(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Le(e){if(!hn(e))return{};let t;try{t=JSON.parse(bn(e,"utf8"))}catch(n){throw new Error(`Invalid existing Claude Code config: ${n instanceof Error?n.message:String(n)}`)}if(!S(t))throw new Error("Invalid existing Claude Code config: root must be a JSON object.");return t}function Je(e,t){if(!S(e))return!1;let n=e.args;return e.type==="stdio"&&e.command===t&&Array.isArray(n)&&n.length===1&&n[0]==="mcp"}function On(e,t){vn(Cn(e),{recursive:!0});let n=`${e}.toolnet-${process.pid}-${Date.now()}.tmp`;try{wn(n,JSON.stringify(t,null,2)+`
763
- `,{encoding:"utf8",mode:384}),xn(n,e)}finally{Sn(n,{force:!0})}}function Ye(e={}){let t=e.stateFile??ie(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",s=Le(t),i=s.mcpServers;if(i!==void 0&&!S(i))throw new Error("Invalid existing Claude Code config: mcpServers must be an object.");let r=S(i)?{...i}:{},c=r[o];if(Je(c,n))return{installed:!0,changed:!1,configFile:t,serverName:o,command:[n,"mcp"],repaired:!1};let l=c!==void 0;r[o]={type:"stdio",command:n,args:["mcp"]},On(t,{...s,mcpServers:r});let u=Le(t).mcpServers;if(!S(u)||!Je(u[o],n))throw new Error("Claude Code MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:t,serverName:o,command:[n,"mcp"],repaired:l}}function He(e={}){let t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=$e({binary:t,settingsFile:e.settingsFile}),o=Ye({binary:t,stateFile:e.stateFile});return{hooks:n,mcp:o,files:[n.settingsFile,o.configFile]}}function Be(){return ce()}function B(e={}){let t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=[],o=Be(),s=new Map(o.map(i=>[i.agent,i.detected]));if(!(e.force===!0||s.get("agy")===!0))n.push({agent:"agy",detected:!1,installed:!1,targets:[]});else try{let r=he({binary:t});n.push({agent:"agy",detected:!0,installed:!0,targets:r.files})}catch(r){n.push({agent:"agy",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||s.get("opencode")===!0))n.push({agent:"opencode",detected:!1,installed:!1,targets:[]});else try{let r=we({binary:t}),c=ke({binary:t});n.push({agent:"opencode",detected:!0,installed:!0,targets:[r,c.configFile,`mcp:${c.serverName}`]})}catch(r){n.push({agent:"opencode",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||s.get("claude")===!0))n.push({agent:"claude",detected:!1,installed:!1,targets:[]});else try{let r=He({binary:t});n.push({agent:"claude",detected:!0,installed:!0,targets:[r.hooks.settingsFile,r.mcp.configFile,`mcp:${r.mcp.serverName}`]})}catch(r){n.push({agent:"claude",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||s.get("codex")===!0))n.push({agent:"codex",detected:!1,installed:!1,targets:[]});else try{let r=Re({binary:t}),c=_e({binary:t}),l=De({binary:t});if(!l.installed)throw new Error(l.error??"Codex MCP registration failed");let a=[r.configFile,c,`mcp:${l.serverName}`];r.preservedPrevious&&a.push(r.previousFile),n.push({agent:"codex",detected:!0,installed:!0,targets:a})}catch(r){n.push({agent:"codex",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}return n}function Mn(e){console.log(""),console.log("ToolNet Memory Integration Detection"),console.log("===================================="),console.log("");for(let t of e){let n=t.agent==="agy"?"Agy / Antigravity":t.agent==="opencode"?"OpenCode":t.agent==="claude"?"Claude Code":"Codex";if(!t.detected){console.log(`\u25CB ${n}: not detected`);continue}console.log(`\u2713 ${n}: detected`);for(let o of t.evidence)console.log(` ${o}`)}console.log("")}function An(e){console.log(""),console.log("ToolNet Memory AI Integrations"),console.log("=============================="),console.log("");for(let t of e){let n=t.agent==="agy"?"Agy / Antigravity":t.agent==="opencode"?"OpenCode":"Codex";if(!t.detected){console.log(`- ${n}: not detected`);continue}if(t.installed){console.log(`\u2713 ${n}: automatic memory enabled`);continue}console.log(`\u2717 ${n}: integration failed`),t.error&&console.log(` ${t.error}`)}console.log("")}async function kn(){let e=process.argv.slice(2),t=e.includes("--all"),n=e.includes("--json");if(e.includes("--detect-only")){let i=Be();if(n){console.log(JSON.stringify(i,null,2));return}Mn(i);return}let s=B({force:t});if(n){console.log(JSON.stringify(s,null,2));return}An(s)}var In=process.argv[1]&&(process.argv[1].endsWith("auto-integrate.js")||process.argv[1].endsWith("auto-integrate.ts"));In&&kn().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});function Rn(e=process.cwd()){let t=Tn(e);if(!ze(t))throw new Error(`Project path does not exist: ${t}`);if(!En(t).isDirectory())throw new Error(`Project path is not a directory: ${t}`);let n=new C().detect(t),o=jn(n.rootPath,".toolnet","project.json");if(!ze(o))throw new Error(`ToolNet project initialization failed: ${o} was not created`);return{initialized:!0,project:{id:n.id,name:n.name,remote:n.remote,rootPath:n.rootPath},manifestFile:o}}function Nn(e,t){let n=e.indexOf(t);return n>=0?e[n+1]:void 0}async function _n(){let e=process.argv.slice(2),t=e.includes("--json"),n=!e.includes("--no-integrate"),o=Nn(e,"--project"),s=e.find((l,a)=>!l.startsWith("-")&&(a===0||e[a-1]!=="--project")),i=o??s??process.cwd(),r=await N("Initializing ToolNet project",()=>Rn(i),{enabled:!t}),c=[];if(n&&(c=await N("Detecting AI coding agents",()=>B(),{enabled:!t})),t){console.log(JSON.stringify({...r,integrations:c},null,2));return}if(console.log(""),console.log("ToolNet Memory"),console.log("=============="),console.log(""),console.log("\u2713 Project initialized"),console.log(""),console.log(`Project: ${r.project.name}`),console.log(`ID: ${r.project.id}`),console.log(`Root: ${r.project.rootPath}`),console.log(`Manifest: ${r.manifestFile}`),console.log(""),n){console.log("AI integrations:");let l=c.filter(a=>a.detected&&a.installed);if(!l.length)console.log(" \u25CB No supported coding agent detected");else for(let a of l){let u=a.agent==="agy"?"Agy / Antigravity":a.agent==="opencode"?"OpenCode":"Codex";console.log(` \u2713 ${u}`)}console.log("")}console.log("Next: toolnet-memory doctor"),console.log("")}var Pn=process.argv[1]?.endsWith("/init.js")||process.argv[1]?.endsWith("/init.ts");Pn&&_n().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});export{Rn as initializeToolNetProject};
1066
+ `),ke(t,o,{encoding:"utf8",mode:384}),{configFile:t,previousFile:n,preservedPrevious:u.length>0&&!p}}import{existsSync as Zt,mkdirSync as en,readFileSync as tn,writeFileSync as nn}from"node:fs";import{homedir as on}from"node:os";import{dirname as rn,join as _e}from"node:path";function sn(e){return`'${e.replace(/'/g,"'\\''")}'`}function Pe(e={}){let t=e.hooksFile??_e(process.env.CODEX_HOME??_e(on(),".codex"),"hooks.json");en(rn(t),{recursive:!0});let n={};if(Zt(t))try{n=JSON.parse(tn(t,"utf8"))}catch(a){throw new Error(`Invalid existing Codex hooks.json: ${a instanceof Error?a.message:String(a)}`)}let o=n.hooks&&typeof n.hooks=="object"&&!Array.isArray(n.hooks)?n.hooks:{};n.hooks=o;let i=(Array.isArray(o.SessionStart)?o.SessionStart:[]).filter(a=>{try{return!JSON.stringify(a).includes("session:codex-context")}catch{return!0}}),r=e.binary??"toolnet-memory";return i.push({matcher:"startup|resume|clear|compact",hooks:[{type:"command",command:`${sn(r)} session:codex-context`,timeout:15,additionalContextLimit:1e3,statusMessage:"Loading ToolNet project continuity"}]}),o.SessionStart=i,nn(t,JSON.stringify(n,null,2)+`
1067
+ `,{encoding:"utf8",mode:384}),t}import{spawnSync as an}from"node:child_process";function J(e,t){return an(e,t,{encoding:"utf8",stdio:["ignore","pipe","pipe"]})}function Fe(e,t){let n=J(e,["mcp","get",t,"--json"]);if(n.status!==0||!n.stdout)return null;try{return JSON.parse(n.stdout)}catch{return null}}function De(e,t){return e.enabled!==!1&&e.transport?.type==="stdio"&&e.transport?.command===t&&Array.isArray(e.transport?.args)&&e.transport?.args.length===1&&e.transport.args[0]==="mcp"}function $e(e={}){let t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=e.codexBinary??"codex",o=e.serverName??"toolnet-memory",s=Fe(n,o);if(s&&De(s,t))return{installed:!0,changed:!1,serverName:o,command:t,args:["mcp"]};if(s){let a=J(n,["mcp","remove",o]);if(a.status!==0)return{installed:!1,changed:!1,serverName:o,command:t,args:["mcp"],error:(a.stderr||a.stdout||"Unable to remove old ToolNet MCP configuration.").trim()}}let i=J(n,["mcp","add",o,"--",t,"mcp"]);if(i.status!==0)return{installed:!1,changed:!1,serverName:o,command:t,args:["mcp"],error:(i.stderr||i.stdout||"Unable to register ToolNet MCP.").trim()};let r=Fe(n,o);return!r||!De(r,t)?{installed:!1,changed:!0,serverName:o,command:t,args:["mcp"],error:"Codex accepted MCP registration but verification did not match expected ToolNet command."}:{installed:!0,changed:!0,serverName:o,command:t,args:["mcp"]}}import{existsSync as cn,mkdirSync as ln,readFileSync as un,renameSync as dn,rmSync as mn,writeFileSync as pn}from"node:fs";import{dirname as gn}from"node:path";function x(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function fn(e){return/^[A-Za-z0-9_./:-]+$/u.test(e)?e:`'${e.replace(/'/gu,"'\\''")}'`}function yn(e){if(!cn(e))return{};let t;try{t=JSON.parse(un(e,"utf8"))}catch(n){throw new Error(`Invalid existing Claude settings.json: ${n instanceof Error?n.message:String(n)}`)}if(!x(t))throw new Error("Invalid existing Claude settings.json: root must be a JSON object.");return t}function B(e){if(e===void 0)return[];if(!Array.isArray(e))throw new Error("Invalid existing Claude settings.json: hook event must be an array.");let t=[];for(let n of e){if(!x(n)){t.push(n);continue}let o=n.hooks;if(!Array.isArray(o)){t.push(n);continue}let s=o.filter(i=>{if(!x(i))return!0;let r=i.command;return!(typeof r=="string"&&r.includes("session:claude-hook"))});s.length!==0&&t.push({...n,hooks:s})}return t}function H(e){return{type:"command",command:e,timeout:10}}function hn(e,t){ln(gn(e),{recursive:!0,mode:448});let n=`${e}.toolnet-${process.pid}-${Date.now()}.tmp`;try{pn(n,JSON.stringify(t,null,2)+`
1068
+ `,{encoding:"utf8",mode:384}),dn(n,e)}finally{mn(n,{force:!0})}}function Le(e={}){let t=e.settingsFile??ie(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=yn(t),s=o.hooks;if(s!==void 0&&!x(s))throw new Error("Invalid existing Claude settings.json: hooks must be an object.");let i=x(s)?{...s}:{},r=`${fn(n)} session:claude-hook`,a=B(i.SessionStart);a.push({matcher:"startup|resume|clear|compact",hooks:[H(r)]}),i.SessionStart=a;let l=B(i.PostToolUse);l.push({matcher:"Edit|Write",hooks:[H(r)]}),i.PostToolUse=l;let c=B(i.Stop);c.push({hooks:[H(r)]}),i.Stop=c;let u={...o,hooks:i},p=JSON.stringify(o),d=JSON.stringify(u);return p===d?{settingsFile:t,changed:!1}:(hn(t,u),{settingsFile:t,changed:!0})}import{existsSync as vn,mkdirSync as bn,readFileSync as xn,renameSync as Sn,rmSync as wn,writeFileSync as On}from"node:fs";import{dirname as Cn}from"node:path";function S(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Je(e){if(!vn(e))return{};let t;try{t=JSON.parse(xn(e,"utf8"))}catch(n){throw new Error(`Invalid existing Claude Code config: ${n instanceof Error?n.message:String(n)}`)}if(!S(t))throw new Error("Invalid existing Claude Code config: root must be a JSON object.");return t}function Be(e,t){if(!S(e))return!1;let n=e.args;return e.type==="stdio"&&e.command===t&&Array.isArray(n)&&n.length===1&&n[0]==="mcp"}function Mn(e,t){bn(Cn(e),{recursive:!0});let n=`${e}.toolnet-${process.pid}-${Date.now()}.tmp`;try{On(n,JSON.stringify(t,null,2)+`
1069
+ `,{encoding:"utf8",mode:384}),Sn(n,e)}finally{wn(n,{force:!0})}}function He(e={}){let t=e.stateFile??ae(),n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",s=Je(t),i=s.mcpServers;if(i!==void 0&&!S(i))throw new Error("Invalid existing Claude Code config: mcpServers must be an object.");let r=S(i)?{...i}:{},a=r[o];if(Be(a,n))return{installed:!0,changed:!1,configFile:t,serverName:o,command:[n,"mcp"],repaired:!1};let l=a!==void 0;r[o]={type:"stdio",command:n,args:["mcp"]},Mn(t,{...s,mcpServers:r});let u=Je(t).mcpServers;if(!S(u)||!Be(u[o],n))throw new Error("Claude Code MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:t,serverName:o,command:[n,"mcp"],repaired:l}}function Ye(e={}){let t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=Le({binary:t,settingsFile:e.settingsFile}),o=He({binary:t,stateFile:e.stateFile});return{hooks:n,mcp:o,files:[n.settingsFile,o.configFile]}}function ze(){return ce()}function Y(e={}){let t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=[],o=ze(),s=new Map(o.map(i=>[i.agent,i.detected]));if(!(e.force===!0||s.get("agy")===!0))n.push({agent:"agy",detected:!1,installed:!1,targets:[]});else try{let r=ve({binary:t});n.push({agent:"agy",detected:!0,installed:!0,targets:r.files})}catch(r){n.push({agent:"agy",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||s.get("opencode")===!0))n.push({agent:"opencode",detected:!1,installed:!1,targets:[]});else try{let r=Oe({binary:t}),a=Ee({binary:t});n.push({agent:"opencode",detected:!0,installed:!0,targets:[r,a.configFile,`mcp:${a.serverName}`]})}catch(r){n.push({agent:"opencode",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||s.get("claude")===!0))n.push({agent:"claude",detected:!1,installed:!1,targets:[]});else try{let r=Ye({binary:t});n.push({agent:"claude",detected:!0,installed:!0,targets:[r.hooks.settingsFile,r.mcp.configFile,`mcp:${r.mcp.serverName}`]})}catch(r){n.push({agent:"claude",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||s.get("codex")===!0))n.push({agent:"codex",detected:!1,installed:!1,targets:[]});else try{let r=Ne({binary:t}),a=Pe({binary:t}),l=$e({binary:t});if(!l.installed)throw new Error(l.error??"Codex MCP registration failed");let c=[r.configFile,a,`mcp:${l.serverName}`];r.preservedPrevious&&c.push(r.previousFile),n.push({agent:"codex",detected:!0,installed:!0,targets:c})}catch(r){n.push({agent:"codex",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}return n}function In(e){console.log(""),console.log("ToolNet Memory Integration Detection"),console.log("===================================="),console.log("");for(let t of e){let n=t.agent==="agy"?"Agy / Antigravity":t.agent==="opencode"?"OpenCode":t.agent==="claude"?"Claude Code":"Codex";if(!t.detected){console.log(`\u25CB ${n}: not detected`);continue}console.log(`\u2713 ${n}: detected`);for(let o of t.evidence)console.log(` ${o}`)}console.log("")}function An(e){console.log(""),console.log("ToolNet Memory AI Integrations"),console.log("=============================="),console.log("");for(let t of e){let n=t.agent==="agy"?"Agy / Antigravity":t.agent==="opencode"?"OpenCode":"Codex";if(!t.detected){console.log(`- ${n}: not detected`);continue}if(t.installed){console.log(`\u2713 ${n}: automatic memory enabled`);continue}console.log(`\u2717 ${n}: integration failed`),t.error&&console.log(` ${t.error}`)}console.log("")}async function En(){let e=process.argv.slice(2),t=e.includes("--all"),n=e.includes("--json");if(e.includes("--detect-only")){let i=ze();if(n){console.log(JSON.stringify(i,null,2));return}In(i);return}let s=Y({force:t});if(n){console.log(JSON.stringify(s,null,2));return}An(s)}var Tn=process.argv[1]&&(process.argv[1].endsWith("auto-integrate.js")||process.argv[1].endsWith("auto-integrate.ts"));Tn&&En().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});function Nn(e=process.cwd()){let t=Rn(e);if(!Ue(t))throw new Error(`Project path does not exist: ${t}`);if(!kn(t).isDirectory())throw new Error(`Project path is not a directory: ${t}`);let n=new O().detect(t),o=jn(n.rootPath,".toolnet","project.json");if(!Ue(o))throw new Error(`ToolNet project initialization failed: ${o} was not created`);return{initialized:!0,project:{id:n.id,name:n.name,remote:n.remote,rootPath:n.rootPath},manifestFile:o}}function _n(e,t){let n=e.indexOf(t);return n>=0?e[n+1]:void 0}async function Pn(){let e=process.argv.slice(2),t=e.includes("--json"),n=!e.includes("--no-integrate"),o=_n(e,"--project"),s=e.find((l,c)=>!l.startsWith("-")&&(c===0||e[c-1]!=="--project")),i=o??s??process.cwd(),r=await N("Initializing ToolNet project",()=>Nn(i),{enabled:!t}),a=[];if(n&&(a=await N("Detecting AI coding agents",()=>Y(),{enabled:!t})),t){console.log(JSON.stringify({...r,integrations:a},null,2));return}if(console.log(""),console.log("ToolNet Memory"),console.log("=============="),console.log(""),console.log("\u2713 Project initialized"),console.log(""),console.log(`Project: ${r.project.name}`),console.log(`ID: ${r.project.id}`),console.log(`Root: ${r.project.rootPath}`),console.log(`Manifest: ${r.manifestFile}`),console.log(""),n){console.log("AI integrations:");let l=a.filter(c=>c.detected&&c.installed);if(!l.length)console.log(" \u25CB No supported coding agent detected");else for(let c of l){let u=c.agent==="agy"?"Agy / Antigravity":c.agent==="opencode"?"OpenCode":"Codex";console.log(` \u2713 ${u}`)}console.log("")}console.log("Next: toolnet-memory doctor"),console.log("")}var Fn=process.argv[1]?.endsWith("/init.js")||process.argv[1]?.endsWith("/init.ts");Fn&&Pn().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});export{Nn as initializeToolNetProject};