toolnet-memory 0.3.14 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.env.example +0 -1
  2. package/.release-target +1 -1
  3. package/README.md +182 -6
  4. package/bin/toolnet-memory +5 -0
  5. package/bundle/agy-hook.js +71 -71
  6. package/bundle/agy.js +65 -65
  7. package/bundle/api.js +15 -15
  8. package/bundle/auto-integrate.js +28 -28
  9. package/bundle/background-refresh.js +7 -7
  10. package/bundle/claude-hook.js +51 -50
  11. package/bundle/codex-context.js +29 -28
  12. package/bundle/codex.js +77 -77
  13. package/bundle/context-runtime.js +44 -43
  14. package/bundle/context.js +15 -15
  15. package/bundle/continuity-certify.js +13 -13
  16. package/bundle/copilot-hook.js +88 -86
  17. package/bundle/copilot.js +4 -4
  18. package/bundle/cursor-hook.js +88 -86
  19. package/bundle/cursor.js +4 -4
  20. package/bundle/doctor.js +4 -4
  21. package/bundle/full-index.js +21 -21
  22. package/bundle/gc.js +3 -0
  23. package/bundle/graph-index.js +4 -4
  24. package/bundle/graph-ui.js +3 -3
  25. package/bundle/grok-hook.js +64 -63
  26. package/bundle/grok.js +5 -5
  27. package/bundle/handoff-refresh.js +10 -10
  28. package/bundle/help-cli.js +3 -3
  29. package/bundle/impact.js +4 -4
  30. package/bundle/incremental.js +5 -4
  31. package/bundle/init.js +38 -37
  32. package/bundle/integration-status.js +4 -4
  33. package/bundle/kiro-hook.js +93 -92
  34. package/bundle/learner.js +6 -6
  35. package/bundle/mcp.js +17 -17
  36. package/bundle/memory-agent.js +7 -7
  37. package/bundle/memory-query.js +7 -7
  38. package/bundle/opencode.js +84 -84
  39. package/bundle/project-manual.js +7 -7
  40. package/bundle/recovery-certify.js +15 -15
  41. package/bundle/runtime.js +13 -12
  42. package/bundle/semantic.js +5 -5
  43. package/bundle/snapshot.js +4 -4
  44. package/bundle/status-cli.js +4 -4
  45. package/bundle/toolnet-cli.js +60 -60
  46. package/bundle/work-continuity.js +7 -7
  47. package/package.json +21 -3
  48. package/release-manifest.json +104 -3
package/bundle/cursor.js CHANGED
@@ -1,6 +1,6 @@
1
- import{homedir as jo}from"node:os";import{join as m,resolve as bo}from"node:path";function z(o={}){return o.cursorHome??m(o.home??jo(),".cursor")}function k(o={}){return m(z(o),"mcp.json")}function h(o={}){return m(z(o),"hooks.json")}function J(o){return m(bo(o),".cursor")}function O(o){return m(J(o),"mcp.json")}function x(o){return m(J(o),"hooks.json")}function So(o){return m(J(o),"rules")}function E(o){return m(So(o),"toolnet-memory.mdc")}import{existsSync as Co,mkdirSync as Fo,readFileSync as Io,renameSync as vo,rmSync as Po,writeFileSync as wo}from"node:fs";import{dirname as Ro}from"node:path";function b(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function $(o,e){if(!Co(o))return{};let t=Io(o,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(r){throw new Error(`Invalid existing ${e} hooks file: ${r instanceof Error?r.message:String(r)}`)}if(!b(n))throw new Error(`Invalid existing ${e} hooks file: root must be a JSON object.`);return n}function Q(o,e){Fo(Ro(o),{recursive:!0,mode:448});let t=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{wo(t,`${JSON.stringify(e,null,2)}
2
- `,{encoding:"utf8",mode:384}),vo(t,o)}finally{Po(t,{force:!0})}}function D(o){return/^[A-Za-z0-9_./:-]+$/u.test(o)?o:`'${o.replace(/'/gu,"'\\''")}'`}var P=[["sessionStart",10],["beforeSubmitPrompt",10],["preToolUse",10],["postToolUse",15],["afterAgentResponse",15],["stop",30]];function V(o){return b(o)&&typeof o.command=="string"&&o.command.includes("session:cursor-hook")}function Oo(o,e,t){let r={type:"command",command:`TOOLNET_HOOK_EVENT=${D(o)} ${D(e)} session:cursor-hook`,timeout:t};return o==="preToolUse"&&(r.matcher=".*"),r}function _(o={}){let e=o.hooksFile??h(),t=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=$(e,"Cursor");if(n.version!==void 0&&n.version!==1)throw new Error(`Unsupported existing Cursor hooks version: ${String(n.version)}`);let r=n.hooks;if(r!==void 0&&!b(r))throw new Error("Invalid existing Cursor hooks file: hooks must be an object.");let s=b(r)?{...r}:{};for(let[c,a]of P){let g=s[c];if(g!==void 0&&!Array.isArray(g))throw new Error(`Invalid existing Cursor hooks file: hooks.${c} must be an array.`);let f=Array.isArray(g)?g.filter(p=>!V(p)):[];s[c]=[...f,Oo(c,t,a)]}let i={...n,version:1,hooks:s};if(JSON.stringify(n)===JSON.stringify(i))return{hooksFile:e,changed:!1,hookCount:P.length};Q(e,i);let u=$(e,"Cursor");if(u.version!==1||!b(u.hooks))throw new Error("Cursor hooks were written but verification failed.");let l=0;for(let[c]of P){let a=u.hooks[c];if(!Array.isArray(a))throw new Error("Cursor hooks were written but verification failed.");l+=a.filter(V).length}if(l!==P.length)throw new Error("Cursor hooks were written but verification failed.");return{hooksFile:e,changed:!0,hookCount:P.length}}import{existsSync as xo,mkdirSync as Eo,readFileSync as Ao,renameSync as Ho,rmSync as Mo,writeFileSync as No}from"node:fs";import{dirname as To}from"node:path";function S(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function q(o,e){if(!xo(o))return{};let t=Ao(o,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(r){throw new Error(`Invalid existing ${e} MCP config: ${r instanceof Error?r.message:String(r)}`)}if(!S(n))throw new Error(`Invalid existing ${e} MCP config: root must be a JSON object.`);return n}function Z(o,e){Eo(To(o),{recursive:!0,mode:448});let t=`${o}.tmp-${process.pid}-${Date.now()}`;try{No(t,`${JSON.stringify(e,null,2)}
3
- `,{encoding:"utf8",mode:384}),Ho(t,o)}finally{Mo(t,{force:!0})}}function oo(o,e){return S(o)?(o.type===void 0||o.type==="stdio")&&o.command===e&&Array.isArray(o.args)&&o.args.length===1&&o.args[0]==="mcp":!1}function G(o={}){let e=o.configFile??k(),t=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=o.serverName??"toolnet-memory",r=q(e,"Cursor"),s=r.mcpServers;if(s!==void 0&&!S(s))throw new Error("Invalid existing Cursor MCP config: mcpServers must be an object.");let i=S(s)?{...s}:{};if(oo(i[n],t))return{installed:!0,changed:!1,configFile:e,serverName:n,command:t,args:["mcp"]};i[n]={type:"stdio",command:t,args:["mcp"]},Z(e,{...r,mcpServers:i});let l=q(e,"Cursor").mcpServers;if(!S(l)||!oo(l[n],t))throw new Error("Cursor MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:e,serverName:n,command:t,args:["mcp"]}}import{mkdirSync as Jo,readFileSync as eo,renameSync as $o,rmSync as Do,writeFileSync as _o}from"node:fs";import{dirname as qo}from"node:path";var w=`---
1
+ import{homedir as ho}from"node:os";import{join as m,resolve as bo}from"node:path";function Y(o={}){return o.cursorHome??m(o.home??ho(),".cursor")}function k(o={}){return m(Y(o),"mcp.json")}function y(o={}){return m(Y(o),"hooks.json")}function T(o){return m(bo(o),".cursor")}function O(o){return m(T(o),"mcp.json")}function x(o){return m(T(o),"hooks.json")}function So(o){return m(T(o),"rules")}function E(o){return m(So(o),"toolnet-memory.mdc")}import{existsSync as Io,mkdirSync as Co,readFileSync as Ro,renameSync as Fo,rmSync as vo,writeFileSync as Po}from"node:fs";import{dirname as wo}from"node:path";function b(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function J(o,e){if(!Io(o))return{};let t=Ro(o,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(r){throw new Error(`Invalid existing ${e} hooks file: ${r instanceof Error?r.message:String(r)}`)}if(!b(n))throw new Error(`Invalid existing ${e} hooks file: root must be a JSON object.`);return n}function X(o,e){Co(wo(o),{recursive:!0,mode:448});let t=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{Po(t,`${JSON.stringify(e,null,2)}
2
+ `,{encoding:"utf8",mode:384}),Fo(t,o)}finally{vo(t,{force:!0})}}function D(o){return/^[A-Za-z0-9_./:-]+$/u.test(o)?o:`'${o.replace(/'/gu,"'\\''")}'`}var v=[["sessionStart",10],["beforeSubmitPrompt",10],["preToolUse",10],["postToolUse",15],["afterAgentResponse",15],["stop",30]];function Q(o){return b(o)&&typeof o.command=="string"&&o.command.includes("session:cursor-hook")}function Oo(o,e,t){let r={type:"command",command:`TOOLNET_HOOK_EVENT=${D(o)} ${D(e)} session:cursor-hook`,timeout:t};return o==="preToolUse"&&(r.matcher=".*"),r}function $(o={}){let e=o.hooksFile??y(),t=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=J(e,"Cursor");if(n.version!==void 0&&n.version!==1)throw new Error(`Unsupported existing Cursor hooks version: ${String(n.version)}`);let r=n.hooks;if(r!==void 0&&!b(r))throw new Error("Invalid existing Cursor hooks file: hooks must be an object.");let i=b(r)?{...r}:{};for(let[c,a]of v){let p=i[c];if(p!==void 0&&!Array.isArray(p))throw new Error(`Invalid existing Cursor hooks file: hooks.${c} must be an array.`);let f=Array.isArray(p)?p.filter(g=>!Q(g)):[];i[c]=[...f,Oo(c,t,a)]}let s={...n,version:1,hooks:i};if(JSON.stringify(n)===JSON.stringify(s))return{hooksFile:e,changed:!1,hookCount:v.length};X(e,s);let u=J(e,"Cursor");if(u.version!==1||!b(u.hooks))throw new Error("Cursor hooks were written but verification failed.");let l=0;for(let[c]of v){let a=u.hooks[c];if(!Array.isArray(a))throw new Error("Cursor hooks were written but verification failed.");l+=a.filter(Q).length}if(l!==v.length)throw new Error("Cursor hooks were written but verification failed.");return{hooksFile:e,changed:!0,hookCount:v.length}}import{existsSync as xo,mkdirSync as Eo,readFileSync as Ao,renameSync as Ho,rmSync as Mo,writeFileSync as No}from"node:fs";import{dirname as _o}from"node:path";function S(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function q(o,e){if(!xo(o))return{};let t=Ao(o,"utf8").trim();if(!t)return{};let n;try{n=JSON.parse(t)}catch(r){throw new Error(`Invalid existing ${e} MCP config: ${r instanceof Error?r.message:String(r)}`)}if(!S(n))throw new Error(`Invalid existing ${e} MCP config: root must be a JSON object.`);return n}function Z(o,e){Eo(_o(o),{recursive:!0,mode:448});let t=`${o}.tmp-${process.pid}-${Date.now()}`;try{No(t,`${JSON.stringify(e,null,2)}
3
+ `,{encoding:"utf8",mode:384}),Ho(t,o)}finally{Mo(t,{force:!0})}}function oo(o,e){return S(o)?(o.type===void 0||o.type==="stdio")&&o.command===e&&Array.isArray(o.args)&&o.args.length===1&&o.args[0]==="mcp":!1}function U(o={}){let e=o.configFile??k(),t=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=o.serverName??"toolnet-memory",r=q(e,"Cursor"),i=r.mcpServers;if(i!==void 0&&!S(i))throw new Error("Invalid existing Cursor MCP config: mcpServers must be an object.");let s=S(i)?{...i}:{};if(oo(s[n],t))return{installed:!0,changed:!1,configFile:e,serverName:n,command:t,args:["mcp"]};s[n]={type:"stdio",command:t,args:["mcp"]},Z(e,{...r,mcpServers:s});let l=q(e,"Cursor").mcpServers;if(!S(l)||!oo(l[n],t))throw new Error("Cursor MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:e,serverName:n,command:t,args:["mcp"]}}import{mkdirSync as To,readFileSync as eo,renameSync as Jo,rmSync as Do,writeFileSync as $o}from"node:fs";import{dirname as qo}from"node:path";var P=`---
4
4
  description: ToolNet Memory project continuity and safety rules
5
5
  alwaysApply: true
6
6
  ---
@@ -27,4 +27,4 @@ Use ToolNet Memory as the continuity source for this project.
27
27
  - Do not ask the user to repeat project context that ToolNet already provides.
28
28
 
29
29
  Current repository evidence overrides stale memory.
30
- `;function Go(o,e){Jo(qo(o),{recursive:!0,mode:448});let t=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{_o(t,e,{encoding:"utf8",mode:384}),$o(t,o)}finally{Do(t,{force:!0})}}function to(o){let e=o.ruleFile??E(o.projectRoot);try{if(eo(e,"utf8")===w)return{ruleFile:e,changed:!1}}catch{}if(Go(e,w),eo(e,"utf8")!==w)throw new Error("Cursor ToolNet project rule was written but verification failed.");return{ruleFile:e,changed:!0}}import{spawnSync as Uo}from"node:child_process";import{existsSync as C,statSync as Lo}from"node:fs";import{dirname as Bo,join as Ko,parse as Wo,resolve as L}from"node:path";function ro(o){let e=L(o);if(!C(e))throw new Error(`Project path does not exist: ${e}`);if(!Lo(e).isDirectory())throw new Error(`Project path is not a directory: ${e}`);return e}function A(o){return Ko(o,".toolnet","project.json")}function Xo(o){let e=L(o),t=Wo(e).root;for(;;){if(C(A(e)))return e;if(e===t)return;let n=Bo(e);if(n===e)return;e=n}}function U(o){let e=Uo("git",["rev-parse","--show-toplevel"],{cwd:o,encoding:"utf8",timeout:5e3});if(e.status!==0)return;let t=e.stdout.trim();return t?L(t):void 0}function F(o={}){let e=ro(o.cwd??process.cwd());if(o.project){let r=ro(o.project),s=A(r),i=U(r);return{root:r,source:"explicit",eligible:!0,toolnetProject:C(s),manifestFile:C(s)?s:void 0,gitRoot:i}}let t=Xo(e);if(t){let r=A(t);return{root:t,source:"toolnet",eligible:!0,toolnetProject:!0,manifestFile:r,gitRoot:U(t)}}let n=U(e);if(n){let r=A(n);return{root:n,source:"git",eligible:!0,toolnetProject:C(r),manifestFile:C(r)?r:void 0,gitRoot:n}}return{root:e,source:"cwd",eligible:!1,toolnetProject:!1}}function co(o,e={}){let t=[],n=o.indexOf("--scope");if(n>=0){let s=o[n+1];if(s!=="global"&&s!=="project"&&s!=="both")throw new Error(`Invalid --scope value: ${String(s)}`);t.push(s)}o.includes("--global")&&t.push("global"),o.includes("--both")&&t.push("both");let r=Array.from(new Set(t));if(r.length>1)throw new Error(`Conflicting integration scopes: ${r.join(", ")}`);return r[0]??e.defaultScope??"global"}function no(o,e){return{install:o,effective:e}}function d(o,e){return{surface:o,global:no(e.globalInstall,e.effective==="global"||e.effective==="both"),project:no(e.projectInstall,e.effective==="project"||e.effective==="both"),effective:e.effective,risk:e.risk??"none",dedupeRequired:e.dedupeRequired??!1,trustRequired:e.trustRequired??e.projectInstall,note:e.note}}function Yo(o){return{mcp:d("mcp",{globalInstall:!0,projectInstall:!1,effective:"global"}),hooks:d("hooks",{globalInstall:!0,projectInstall:!1,effective:"global"}),work:d("work",{globalInstall:o==="grok",projectInstall:!1,effective:o==="grok"?"global":"none",note:o==="grok"?"Grok supports a global ToolNet continuity skill.":"Cursor/Copilot work instructions remain project-scoped."})}}function so(o){return{mcp:d("mcp",{globalInstall:!1,projectInstall:!0,effective:"project",trustRequired:!0}),hooks:d("hooks",{globalInstall:!1,projectInstall:!0,effective:"project",trustRequired:!0}),work:d("work",{globalInstall:!1,projectInstall:!0,effective:"project",trustRequired:!1,note:o==="cursor"?"Use .cursor/rules/toolnet-memory.mdc.":o==="copilot"?"Use .github/instructions/toolnet-memory.instructions.md.":"Use .grok/skills/toolnet-continuity/SKILL.md."})}}function io(o){return{mcp:d("mcp",{globalInstall:!0,projectInstall:!0,effective:"project",risk:o==="cursor"?"precedence-unverified":"shadowed-global",trustRequired:!0,note:o==="cursor"?"Project ToolNet MCP is the intended effective definition; native same-name precedence must be E2E certified before release.":"Global remains useful outside the project; same-name project definition wins inside the project."}),hooks:d("hooks",{globalInstall:!0,projectInstall:!0,effective:"both",risk:"additive-duplicate",dedupeRequired:!0,trustRequired:!0,note:"Global and project hook sources can both execute for the same native event."}),work:d("work",{globalInstall:o==="grok",projectInstall:!0,effective:"project",risk:o==="grok"?"shadowed-global":"none",trustRequired:!1,note:o==="cursor"?"Project rule is authoritative.":o==="copilot"?"Project instruction is authoritative.":"Project skill shadows the same-name global skill inside the project."})}}function H(o){let{agent:e,scope:t,project:n}=o;return(t==="project"||t==="both")&&(!n||!n.eligible)?{agent:e,requestedScope:t,project:n,surfaces:t==="both"?io(e):so(e),canInstall:!1,reason:"Project scope requires an explicit project, existing ToolNet project, or Git repository root."}:{agent:e,requestedScope:t,project:n,surfaces:t==="global"?Yo(e):t==="project"?so(e):io(e),canInstall:!0}}function lo(o){return!!(o?.mcp?.changed||o?.hooks?.changed||o?.rule?.changed)}function uo(o={}){let e=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.scope??"global",n=t==="global"?void 0:F({project:o.projectRoot}),r=H({agent:"cursor",scope:t,project:n});if(!r.canInstall)throw new Error(r.reason??"Cursor project integration scope cannot be resolved.");let s,i;if((r.surfaces.mcp.global.install||r.surfaces.hooks.global.install||r.surfaces.work.global.install)&&(s={},r.surfaces.mcp.global.install&&(s.mcp=G({binary:e,configFile:o.configFile??k()})),r.surfaces.hooks.global.install&&(s.hooks=_({binary:e,hooksFile:o.hooksFile??h()}))),r.surfaces.mcp.project.install||r.surfaces.hooks.project.install||r.surfaces.work.project.install){if(!n?.eligible)throw new Error("Cursor project integration requires an eligible project root.");i={},r.surfaces.mcp.project.install&&(i.mcp=G({binary:e,configFile:o.projectConfigFile??O(n.root)})),r.surfaces.hooks.project.install&&(i.hooks=_({binary:e,hooksFile:o.projectHooksFile??x(n.root)})),r.surfaces.work.project.install&&(i.rule=to({projectRoot:n.root,ruleFile:o.projectRuleFile}))}let u=i?.mcp??s?.mcp,l=i?.hooks??s?.hooks;if(!u||!l)throw new Error("Cursor integration did not produce an effective MCP/hooks installation.");let c=Array.from(new Set([s?.mcp?.configFile,s?.hooks?.hooksFile,s?.rule?.ruleFile,i?.mcp?.configFile,i?.hooks?.hooksFile,i?.rule?.ruleFile].filter(a=>typeof a=="string")));return{installed:!0,changed:lo(s)||lo(i),scope:t,plan:r,project:n,global:s,projectScope:i,mcp:u,hooks:l,rule:i?.rule,files:c}}import{existsSync as Y,readFileSync as ne}from"node:fs";import{existsSync as I,readFileSync as W}from"node:fs";import{homedir as zo}from"node:os";import{join as M,resolve as Ye}from"node:path";function ao(o={}){return o.copilotHome??process.env.COPILOT_HOME??M(o.home??zo(),".copilot")}function go(o={}){return M(ao(o),"mcp-config.json")}function Qo(o={}){return M(ao(o),"hooks")}function fo(o={}){return M(Qo(o),"toolnet-memory.json")}import{homedir as Vo}from"node:os";import{join as j,resolve as Ze}from"node:path";function B(o={}){return o.grokHome??process.env.GROK_HOME??j(o.home??Vo(),".grok")}function po(o={}){return j(B(o),"config.toml")}function Zo(o={}){return j(B(o),"hooks")}function mo(o={}){return j(Zo(o),"toolnet-memory.json")}function oe(o={}){return j(B(o),"skills")}function ee(o={}){return j(oe(o),"toolnet-continuity")}function ko(o={}){return j(ee(o),"SKILL.md")}function y(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function R(o){if(!I(o))return{};try{let e=JSON.parse(W(o,"utf8"));return y(e)?{value:e}:{error:"root must be a JSON object"}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}function ho(o,e){if(!o||!y(o.mcpServers))return!1;let t=o.mcpServers["toolnet-memory"];return!y(t)||typeof t.command!="string"||!t.command.trim()||!Array.isArray(t.args)||t.args.length!==1||t.args[0]!=="mcp"?!1:!e||Array.isArray(t.tools)&&t.tools.includes("*")}function yo(o,e,t){if(!o||!y(o.hooks))return[];let n=o.hooks;return e.filter(r=>{let s=n[r];return Array.isArray(s)&&s.some(i=>y(i)&&(typeof i.command=="string"&&i.command.includes(t)||typeof i.bash=="string"&&i.bash.includes(t)))})}function te(o,e){if(!o||!y(o.hooks))return[];let t=o.hooks;return e.filter(n=>{let r=t[n];return Array.isArray(r)&&r.some(s=>!y(s)||!Array.isArray(s.hooks)?!1:s.hooks.some(i=>y(i)&&typeof i.command=="string"&&i.command.includes("session:grok-hook")))})}function re(o){if(!I(o))return!1;let e=W(o,"utf8"),t=/\[mcp_servers\.(?:"toolnet-memory"|'toolnet-memory'|toolnet-memory)\]/,n=e.search(t);if(n<0)return!1;let r=e.slice(n),s=r.slice(1).search(/\n\s*\[[^\]]+\]/),i=s>=0?r.slice(0,s+1):r;return/command\s*=\s*"[^"]+"/.test(i)&&/args\s*=\s*\[\s*"mcp"\s*\]/.test(i)&&!/enabled\s*=\s*false/.test(i)}function K(o){let e=[];o.mcpError&&e.push(`MCP config: ${o.mcpError}`),o.hookError&&e.push(`Hooks config: ${o.hookError}`);let t=o.mcpConfigured&&o.hooksConfigured&&(o.skill?.configured??!0),n=I(o.configFile)||I(o.hooksFile)||(o.skill?I(o.skill.skillFile):!1),r=e.length>0?"invalid":t?"ready":n?"partial":"not-installed";return{installed:t,state:r,mcp:{configured:o.mcpConfigured,configFile:o.configFile,error:o.mcpError},hooks:{configured:o.hooksConfigured,hooksFile:o.hooksFile,events:o.events,error:o.hookError},skill:o.skill,errors:e}}function X(o,e={}){if(o==="cursor"){let c=["sessionStart","beforeSubmitPrompt","preToolUse","postToolUse","afterAgentResponse","stop"],a=e.configFile??k(),g=e.hooksFile??h(),f=R(a),p=R(g),v=p.error?[]:yo(p.value,c,"session:cursor-hook");return K({mcpConfigured:!f.error&&ho(f.value,!1),configFile:a,mcpError:f.error,hooksConfigured:c.every(T=>v.includes(T)),hooksFile:g,events:v,hookError:p.error})}if(o==="copilot"){let c=["sessionStart","userPromptSubmitted","userPromptTransformed","preToolUse","postToolUse","agentStop"],a=e.configFile??go(),g=e.hooksFile??fo(),f=R(a),p=R(g),v=p.error?[]:yo(p.value,c,"session:copilot-hook");return K({mcpConfigured:!f.error&&ho(f.value,!0),configFile:a,mcpError:f.error,hooksConfigured:c.every(T=>v.includes(T)),hooksFile:g,events:v,hookError:p.error})}let t=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"],n=e.configFile??po(),r=e.hooksFile??mo(),s=e.skillFile??ko(),i=R(r),u=i.error?[]:te(i.value,t),l=I(s)&&W(s,"utf8").includes("memory_agent_ask");return K({mcpConfigured:re(n),configFile:n,hooksConfigured:t.every(c=>u.includes(c)),hooksFile:r,events:u,hookError:i.error,skill:{configured:l,skillFile:s}})}function se(o){let e=!1;try{e=ne(o,"utf8")===w}catch{e=!1}return{configured:e,ruleFile:o}}function ie(o,e,t){return e.some(r=>r?.state==="invalid")?"invalid":o?"ready":e.some(r=>r&&(r.state==="partial"||r.state==="ready"||Y(r.mcp.configFile)||Y(r.hooks.hooksFile)))||!!(t&&Y(t.ruleFile))?"partial":"not-installed"}function N(o={}){let e=o.scope??"global",t=e==="global"?void 0:F({project:o.projectRoot}),n=H({agent:"cursor",scope:e,project:t}),r=e==="global"||e==="both"?X("cursor",{configFile:o.globalConfigFile??k(),hooksFile:o.globalHooksFile??h()}):void 0,s;if((e==="project"||e==="both")&&t?.eligible){let a=se(o.projectRuleFile??E(t.root));s={...X("cursor",{configFile:o.projectConfigFile??O(t.root),hooksFile:o.projectHooksFile??x(t.root)}),rule:a}}let i=e==="project"?!0:r?.installed===!0,u=e==="global"?!0:s?.installed===!0&&s.rule.configured===!0,l=n.canInstall&&i&&u,c=[];return!n.canInstall&&n.reason&&c.push(n.reason),e==="both"&&(c.push("Global + project Cursor hooks are additive; ToolNet runtime dedupe is required and enabled."),c.push("Cursor same-name global/project MCP precedence remains marked for native E2E certification.")),{installed:l,state:ie(l,[r,s],s?.rule),requestedScope:e,plan:n,project:t,global:r,projectScope:s,dedupeReady:!0,trustRequired:e==="project"||e==="both",warnings:c}}function ce(o,e){let t=o.indexOf(e);return t>=0?o[t+1]:void 0}function le(){let o=process.argv.slice(2);return o[0]==="install"?o.slice(1):o}function ue(o,e){let t=N({scope:o,projectRoot:e});console.log("Cursor CLI Integration"),console.log("======================"),console.log(""),console.log(`State : ${t.state}`),console.log(`Scope : ${t.requestedScope}`),t.global&&(console.log(""),console.log("Global"),console.log(` MCP : ${t.global.mcp.configured?"ready":"missing"} \u2014 ${t.global.mcp.configFile}`),console.log(` Hooks : ${t.global.hooks.configured?"ready":"missing"} \u2014 ${t.global.hooks.hooksFile}`)),t.projectScope&&(console.log(""),console.log("Project"),console.log(` Root : ${t.project?.root??"-"}`),console.log(` MCP : ${t.projectScope.mcp.configured?"ready":"missing"} \u2014 ${t.projectScope.mcp.configFile}`),console.log(` Hooks : ${t.projectScope.hooks.configured?"ready":"missing"} \u2014 ${t.projectScope.hooks.hooksFile}`),console.log(` Rule : ${t.projectScope.rule.configured?"ready":"missing"} \u2014 ${t.projectScope.rule.ruleFile}`),console.log(` Trust : ${t.trustRequired?"required":"n/a"}`)),console.log(""),console.log(`Dedupe: ${t.dedupeReady?"ready":"missing"}`);for(let n of t.warnings)console.log(`Note : ${n}`);console.log(""),t.installed||(process.exitCode=1)}function ae(){let o=le(),e=o.includes("--json"),t=o.includes("--status")||o[0]==="status",n=co(o),r=ce(o,"--project"),s=n==="global"?void 0:F({project:r});if(t){let l=N({scope:n,projectRoot:s?.root});if(e){console.log(JSON.stringify(l,null,2)),l.installed||(process.exitCode=1);return}ue(n,s?.root);return}let i=uo({scope:n,projectRoot:s?.root}),u=N({scope:n,projectRoot:s?.root});if(!u.installed)throw new Error(`Cursor integration installation did not verify successfully (state=${u.state}).`);if(e){console.log(JSON.stringify({installed:!0,changed:i.changed,scope:i.scope,files:i.files,status:u},null,2));return}console.log("\u2705 Cursor CLI integration installed"),console.log(`Scope: ${n}`);for(let l of i.files)console.log(`File: ${l}`);n==="both"&&(console.log("Hook dedupe: enabled"),console.log("Project trust: required by Cursor")),console.log("Server: toolnet-memory")}try{ae()}catch(o){console.error(o instanceof Error?o.message:String(o)),process.exitCode=1}
30
+ `;function Uo(o,e){To(qo(o),{recursive:!0,mode:448});let t=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{$o(t,e,{encoding:"utf8",mode:384}),Jo(t,o)}finally{Do(t,{force:!0})}}function to(o){let e=o.ruleFile??E(o.projectRoot);try{if(eo(e,"utf8")===P)return{ruleFile:e,changed:!1}}catch{}if(Uo(e,P),eo(e,"utf8")!==P)throw new Error("Cursor ToolNet project rule was written but verification failed.");return{ruleFile:e,changed:!0}}import{spawnSync as Lo}from"node:child_process";import{existsSync as I,statSync as Go}from"node:fs";import{dirname as Ko,join as Wo,parse as Bo,resolve as G}from"node:path";function ro(o){let e=G(o);if(!I(e))throw new Error(`Project path does not exist: ${e}`);if(!Go(e).isDirectory())throw new Error(`Project path is not a directory: ${e}`);return e}function A(o){return Wo(o,".toolnet","project.json")}function Vo(o){let e=G(o),t=Bo(e).root;for(;;){if(I(A(e)))return e;if(e===t)return;let n=Ko(e);if(n===e)return;e=n}}function L(o){let e=Lo("git",["rev-parse","--show-toplevel"],{cwd:o,encoding:"utf8",timeout:5e3});if(e.status!==0)return;let t=e.stdout.trim();return t?G(t):void 0}function C(o={}){let e=ro(o.cwd??process.cwd());if(o.project){let r=ro(o.project),i=A(r),s=L(r);return{root:r,source:"explicit",eligible:!0,toolnetProject:I(i),manifestFile:I(i)?i:void 0,gitRoot:s}}let t=Vo(e);if(t){let r=A(t);return{root:t,source:"toolnet",eligible:!0,toolnetProject:!0,manifestFile:r,gitRoot:L(t)}}let n=L(e);if(n){let r=A(n);return{root:n,source:"git",eligible:!0,toolnetProject:I(r),manifestFile:I(r)?r:void 0,gitRoot:n}}return{root:e,source:"cwd",eligible:!1,toolnetProject:!1}}function co(o,e={}){let t=[],n=o.indexOf("--scope");if(n>=0){let i=o[n+1];if(i!=="global"&&i!=="project"&&i!=="both")throw new Error(`Invalid --scope value: ${String(i)}`);t.push(i)}o.includes("--global")&&t.push("global"),o.includes("--both")&&t.push("both");let r=Array.from(new Set(t));if(r.length>1)throw new Error(`Conflicting integration scopes: ${r.join(", ")}`);return r[0]??e.defaultScope??"global"}function no(o,e){return{install:o,effective:e}}function d(o,e){return{surface:o,global:no(e.globalInstall,e.effective==="global"||e.effective==="both"),project:no(e.projectInstall,e.effective==="project"||e.effective==="both"),effective:e.effective,risk:e.risk??"none",dedupeRequired:e.dedupeRequired??!1,trustRequired:e.trustRequired??e.projectInstall,note:e.note}}function zo(o){return{mcp:d("mcp",{globalInstall:!0,projectInstall:!1,effective:"global"}),hooks:d("hooks",{globalInstall:!0,projectInstall:!1,effective:"global"}),work:d("work",{globalInstall:o==="grok",projectInstall:!1,effective:o==="grok"?"global":"none",note:o==="grok"?"Grok supports a global ToolNet continuity skill.":"Cursor/Copilot work instructions remain project-scoped."})}}function io(o){return{mcp:d("mcp",{globalInstall:!1,projectInstall:!0,effective:"project",trustRequired:!0}),hooks:d("hooks",{globalInstall:!1,projectInstall:!0,effective:"project",trustRequired:!0}),work:d("work",{globalInstall:!1,projectInstall:!0,effective:"project",trustRequired:!1,note:o==="cursor"?"Use .cursor/rules/toolnet-memory.mdc.":o==="copilot"?"Use .github/instructions/toolnet-memory.instructions.md.":"Use .grok/skills/toolnet-continuity/SKILL.md."})}}function so(o){return{mcp:d("mcp",{globalInstall:!0,projectInstall:!0,effective:"project",risk:o==="cursor"?"precedence-unverified":"shadowed-global",trustRequired:!0,note:o==="cursor"?"Project ToolNet MCP is the intended effective definition; native same-name precedence must be E2E certified before release.":"Global remains useful outside the project; same-name project definition wins inside the project."}),hooks:d("hooks",{globalInstall:!0,projectInstall:!0,effective:"both",risk:"additive-duplicate",dedupeRequired:!0,trustRequired:!0,note:"Global and project hook sources can both execute for the same native event."}),work:d("work",{globalInstall:o==="grok",projectInstall:!0,effective:"project",risk:o==="grok"?"shadowed-global":"none",trustRequired:!1,note:o==="cursor"?"Project rule is authoritative.":o==="copilot"?"Project instruction is authoritative.":"Project skill shadows the same-name global skill inside the project."})}}function H(o){let{agent:e,scope:t,project:n}=o;return(t==="project"||t==="both")&&(!n||!n.eligible)?{agent:e,requestedScope:t,project:n,surfaces:t==="both"?so(e):io(e),canInstall:!1,reason:"Project scope requires an explicit project, existing ToolNet project, or Git repository root."}:{agent:e,requestedScope:t,project:n,surfaces:t==="global"?zo(e):t==="project"?io(e):so(e),canInstall:!0}}function lo(o){return!!(o?.mcp?.changed||o?.hooks?.changed||o?.rule?.changed)}function uo(o={}){let e=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.scope??"global",n=t==="global"?void 0:C({project:o.projectRoot}),r=H({agent:"cursor",scope:t,project:n});if(!r.canInstall)throw new Error(r.reason??"Cursor project integration scope cannot be resolved.");let i,s;if((r.surfaces.mcp.global.install||r.surfaces.hooks.global.install||r.surfaces.work.global.install)&&(i={},r.surfaces.mcp.global.install&&(i.mcp=U({binary:e,configFile:o.configFile??k()})),r.surfaces.hooks.global.install&&(i.hooks=$({binary:e,hooksFile:o.hooksFile??y()}))),r.surfaces.mcp.project.install||r.surfaces.hooks.project.install||r.surfaces.work.project.install){if(!n?.eligible)throw new Error("Cursor project integration requires an eligible project root.");s={},r.surfaces.mcp.project.install&&(s.mcp=U({binary:e,configFile:o.projectConfigFile??O(n.root)})),r.surfaces.hooks.project.install&&(s.hooks=$({binary:e,hooksFile:o.projectHooksFile??x(n.root)})),r.surfaces.work.project.install&&(s.rule=to({projectRoot:n.root,ruleFile:o.projectRuleFile}))}let u=s?.mcp??i?.mcp,l=s?.hooks??i?.hooks;if(!u||!l)throw new Error("Cursor integration did not produce an effective MCP/hooks installation.");let c=Array.from(new Set([i?.mcp?.configFile,i?.hooks?.hooksFile,i?.rule?.ruleFile,s?.mcp?.configFile,s?.hooks?.hooksFile,s?.rule?.ruleFile].filter(a=>typeof a=="string")));return{installed:!0,changed:lo(i)||lo(s),scope:t,plan:r,project:n,global:i,projectScope:s,mcp:u,hooks:l,rule:s?.rule,files:c}}import{existsSync as z,readFileSync as ne}from"node:fs";import{existsSync as R,readFileSync as B}from"node:fs";import{homedir as Yo}from"node:os";import{join as M,resolve as ze}from"node:path";function ao(o={}){return o.copilotHome??process.env.COPILOT_HOME??M(o.home??Yo(),".copilot")}function po(o={}){return M(ao(o),"mcp-config.json")}function Xo(o={}){return M(ao(o),"hooks")}function fo(o={}){return M(Xo(o),"toolnet-memory.json")}import{homedir as Qo}from"node:os";import{join as h,resolve as Ze}from"node:path";function K(o={}){return o.grokHome??process.env.GROK_HOME??h(o.home??Qo(),".grok")}function go(o={}){return h(K(o),"config.toml")}function Zo(o={}){return h(K(o),"hooks")}function mo(o={}){return h(Zo(o),"toolnet-memory.json")}function oe(o={}){return h(K(o),"skills")}function ee(o={}){return h(oe(o),"toolnet-continuity")}function ko(o={}){return h(ee(o),"SKILL.md")}function j(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function w(o){if(!R(o))return{};try{let e=JSON.parse(B(o,"utf8"));return j(e)?{value:e}:{error:"root must be a JSON object"}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}function yo(o,e){if(!o||!j(o.mcpServers))return!1;let t=o.mcpServers["toolnet-memory"];return!j(t)||typeof t.command!="string"||!t.command.trim()||!Array.isArray(t.args)||t.args.length!==1||t.args[0]!=="mcp"?!1:!e||Array.isArray(t.tools)&&t.tools.includes("*")}function jo(o,e,t){if(!o||!j(o.hooks))return[];let n=o.hooks;return e.filter(r=>{let i=n[r];return Array.isArray(i)&&i.some(s=>j(s)&&(typeof s.command=="string"&&s.command.includes(t)||typeof s.bash=="string"&&s.bash.includes(t)))})}function te(o,e){if(!o||!j(o.hooks))return[];let t=o.hooks;return e.filter(n=>{let r=t[n];return Array.isArray(r)&&r.some(i=>!j(i)||!Array.isArray(i.hooks)?!1:i.hooks.some(s=>j(s)&&typeof s.command=="string"&&s.command.includes("session:grok-hook")))})}function re(o){if(!R(o))return!1;let e=B(o,"utf8"),t=/\[mcp_servers\.(?:"toolnet-memory"|'toolnet-memory'|toolnet-memory)\]/,n=e.search(t);if(n<0)return!1;let r=e.slice(n),i=r.slice(1).search(/\n\s*\[[^\]]+\]/),s=i>=0?r.slice(0,i+1):r;return/command\s*=\s*"[^"]+"/.test(s)&&/args\s*=\s*\[\s*"mcp"\s*\]/.test(s)&&!/enabled\s*=\s*false/.test(s)}function W(o){let e=[];o.mcpError&&e.push(`MCP config: ${o.mcpError}`),o.hookError&&e.push(`Hooks config: ${o.hookError}`);let t=o.mcpConfigured&&o.hooksConfigured&&(o.skill?.configured??!0),n=R(o.configFile)||R(o.hooksFile)||(o.skill?R(o.skill.skillFile):!1),r=e.length>0?"invalid":t?"ready":n?"partial":"not-installed";return{installed:t,state:r,mcp:{configured:o.mcpConfigured,configFile:o.configFile,error:o.mcpError},hooks:{configured:o.hooksConfigured,hooksFile:o.hooksFile,events:o.events,error:o.hookError},skill:o.skill,errors:e}}function V(o,e={}){if(o==="cursor"){let c=["sessionStart","beforeSubmitPrompt","preToolUse","postToolUse","afterAgentResponse","stop"],a=e.configFile??k(),p=e.hooksFile??y(),f=w(a),g=w(p),F=g.error?[]:jo(g.value,c,"session:cursor-hook");return W({mcpConfigured:!f.error&&yo(f.value,!1),configFile:a,mcpError:f.error,hooksConfigured:c.every(_=>F.includes(_)),hooksFile:p,events:F,hookError:g.error})}if(o==="copilot"){let c=["sessionStart","userPromptSubmitted","userPromptTransformed","preToolUse","postToolUse","agentStop"],a=e.configFile??po(),p=e.hooksFile??fo(),f=w(a),g=w(p),F=g.error?[]:jo(g.value,c,"session:copilot-hook");return W({mcpConfigured:!f.error&&yo(f.value,!0),configFile:a,mcpError:f.error,hooksConfigured:c.every(_=>F.includes(_)),hooksFile:p,events:F,hookError:g.error})}let t=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"],n=e.configFile??go(),r=e.hooksFile??mo(),i=e.skillFile??ko(),s=w(r),u=s.error?[]:te(s.value,t),l=R(i)&&B(i,"utf8").includes("memory_agent_ask");return W({mcpConfigured:re(n),configFile:n,hooksConfigured:t.every(c=>u.includes(c)),hooksFile:r,events:u,hookError:s.error,skill:{configured:l,skillFile:i}})}function ie(o){let e=!1;try{e=ne(o,"utf8")===P}catch{e=!1}return{configured:e,ruleFile:o}}function se(o,e,t){return e.some(r=>r?.state==="invalid")?"invalid":o?"ready":e.some(r=>r&&(r.state==="partial"||r.state==="ready"||z(r.mcp.configFile)||z(r.hooks.hooksFile)))||!!(t&&z(t.ruleFile))?"partial":"not-installed"}function N(o={}){let e=o.scope??"global",t=e==="global"?void 0:C({project:o.projectRoot}),n=H({agent:"cursor",scope:e,project:t}),r=e==="global"||e==="both"?V("cursor",{configFile:o.globalConfigFile??k(),hooksFile:o.globalHooksFile??y()}):void 0,i;if((e==="project"||e==="both")&&t?.eligible){let a=ie(o.projectRuleFile??E(t.root));i={...V("cursor",{configFile:o.projectConfigFile??O(t.root),hooksFile:o.projectHooksFile??x(t.root)}),rule:a}}let s=e==="project"?!0:r?.installed===!0,u=e==="global"?!0:i?.installed===!0&&i.rule.configured===!0,l=n.canInstall&&s&&u,c=[];return!n.canInstall&&n.reason&&c.push(n.reason),e==="both"&&(c.push("Global + project Cursor hooks are additive; ToolNet runtime dedupe is required and enabled."),c.push("Cursor same-name global/project MCP precedence remains marked for native E2E certification.")),{installed:l,state:se(l,[r,i],i?.rule),requestedScope:e,plan:n,project:t,global:r,projectScope:i,dedupeReady:!0,trustRequired:e==="project"||e==="both",warnings:c}}function ce(o,e){let t=o.indexOf(e);return t>=0?o[t+1]:void 0}function le(){let o=process.argv.slice(2);return o[0]==="install"?o.slice(1):o}function ue(o,e){let t=N({scope:o,projectRoot:e});console.log("Cursor CLI Integration"),console.log("======================"),console.log(""),console.log(`State : ${t.state}`),console.log(`Scope : ${t.requestedScope}`),t.global&&(console.log(""),console.log("Global"),console.log(` MCP : ${t.global.mcp.configured?"ready":"missing"} \u2014 ${t.global.mcp.configFile}`),console.log(` Hooks : ${t.global.hooks.configured?"ready":"missing"} \u2014 ${t.global.hooks.hooksFile}`)),t.projectScope&&(console.log(""),console.log("Project"),console.log(` Root : ${t.project?.root??"-"}`),console.log(` MCP : ${t.projectScope.mcp.configured?"ready":"missing"} \u2014 ${t.projectScope.mcp.configFile}`),console.log(` Hooks : ${t.projectScope.hooks.configured?"ready":"missing"} \u2014 ${t.projectScope.hooks.hooksFile}`),console.log(` Rule : ${t.projectScope.rule.configured?"ready":"missing"} \u2014 ${t.projectScope.rule.ruleFile}`),console.log(` Trust : ${t.trustRequired?"required":"n/a"}`)),console.log(""),console.log(`Dedupe: ${t.dedupeReady?"ready":"missing"}`);for(let n of t.warnings)console.log(`Note : ${n}`);console.log(""),t.installed||(process.exitCode=1)}function ae(){let o=le(),e=o.includes("--json"),t=o.includes("--status")||o[0]==="status",n=co(o),r=ce(o,"--project"),i=n==="global"?void 0:C({project:r});if(t){let l=N({scope:n,projectRoot:i?.root});if(e){console.log(JSON.stringify(l,null,2)),l.installed||(process.exitCode=1);return}ue(n,i?.root);return}let s=uo({scope:n,projectRoot:i?.root}),u=N({scope:n,projectRoot:i?.root});if(!u.installed)throw new Error(`Cursor integration installation did not verify successfully (state=${u.state}).`);if(e){console.log(JSON.stringify({installed:!0,changed:s.changed,scope:s.scope,files:s.files,status:u},null,2));return}console.log("\u2705 Cursor CLI integration installed"),console.log(`Scope: ${n}`);for(let l of s.files)console.log(`File: ${l}`);n==="both"&&(console.log("Hook dedupe: enabled"),console.log("Project trust: required by Cursor")),console.log("Server: toolnet-memory")}try{ae()}catch(o){console.error(o instanceof Error?o.message:String(o)),process.exitCode=1}
package/bundle/doctor.js CHANGED
@@ -1,4 +1,4 @@
1
- import"dotenv/config";import{existsSync as ce,readFileSync as ue}from"node:fs";import{homedir as de}from"node:os";import{join as le}from"node:path";function pe(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 me(){let r=process.env.TOOLNET_GLOBAL_ENV??le(de(),".config","toolnet-memory",".env");if(!ce(r))return;let e=ue(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let i=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=pe(o.slice(n+1)))}}me();function f(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function y(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function L(){return{memory:{autoCapture:f(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:f(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:f(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:f(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:y(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:y(process.env.MEMORY_RERANK_TOP,10),finalContext:y(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:y(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:f(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:y(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ge}from"node:crypto";import{existsSync as O,mkdirSync as fe,readFileSync as ye,renameSync as he,writeFileSync as Se}from"node:fs";import{basename as ke,dirname as w,join as j,parse as V,resolve as h}from"node:path";var z=".toolnet",ve="project.json";function we(r){return ge("sha256").update(r).digest("hex").slice(0,16)}function _(r){return j(r,z,ve)}function be(r){return O(_(r))}function je(r,e){let t=h(r),o=V(t).root;for(;;){if(be(t))return t;if(t===o||e&&t===h(e))break;let n=w(t);if(n===t)break;t=n}return null}function xe(r){let e=h(r),t=V(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>O(j(e,i))))return e;if(e===t)break;let n=w(e);if(n===e)break;e=n}return h(r)}function Ae(r){let e;try{e=JSON.parse(ye(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}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 o=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:w(w(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,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 F(r,e){let t=j(r,z);fe(t,{recursive:!0});let o=_(r),n=`${o}.tmp-${process.pid}`;Se(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),he(n,o)}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 b=class{detect(e=process.cwd()){let t=h(e),o=xe(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>O(j(o,p))),s=je(t,i?o:void 0);if(s){let p=_(s),c=Ae(p);return c.rootPath!==s&&(c.rootPath=s,c.updatedAt=new Date().toISOString(),F(s,c)),W(c,s)}let a=new Date().toISOString(),u=ke(o),d={version:1,id:we(o),name:u,remote:u,rootPath:o,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return F(o,d),W(d,o)}};import{homedir as Ye}from"node:os";import{join as Ge}from"node:path";import{DeleteObjectCommand as Me,GetObjectCommand as Ce,HeadObjectCommand as Re,ListObjectsV2Command as Pe,PutObjectCommand as Ee,S3Client as $e}from"@aws-sdk/client-s3";import{getSignedUrl as Te}from"@aws-sdk/s3-request-presigner";var x=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new $e({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,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ee({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Te(this.client,new Ce({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.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 Re({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 Me({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Pe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as B,mkdir as Ie,readFile as Oe,readdir as _e,rm as Ne,stat as H,writeFile as Ke}from"node:fs/promises";import{dirname as De,join as Le,relative as U,resolve as Fe}from"node:path";var S=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Fe(this.root,t)}async put(e,t){let o=this.path(e);await Ie(De(o),{recursive:!0}),await Ke(o,t)}async get(e){try{return await Oe(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 B(this.path(e)),!0}catch{return!1}}async delete(e){await Ne(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await B(t)}catch{return o}let n=async s=>{let a=await _e(s,{withFileTypes:!0});for(let u of a){let d=Le(s,u.name);if(u.isDirectory()){await n(d);continue}let p=await H(d);o.push({key:U(this.root,d),size:p.size,updatedAt:p.mtime.toISOString()})}},i=await H(t);return i.isDirectory()?await n(t):o.push({key:U(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as We,GetObjectCommand as Ve,HeadObjectCommand as ze,ListObjectsV2Command as Be,PutObjectCommand as He,S3Client as Ue}from"@aws-sdk/client-s3";import{getSignedUrl as Je}from"@aws-sdk/s3-request-presigner";var k=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,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new He({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Je(this.client,new Ve({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`${this.name} download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.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 ze({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 We({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Be({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};function N(r,e){return console.warn(e),new S(r)}function J(r){let e=r.localRoot??Ge(Ye(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new k({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):N(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 k({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):N(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 x({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):N(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new S(e)}var A=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};var M=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let o=JSON.parse(t);if(o.version!==1||o.projectId!==e||!Array.isArray(o.records))throw new Error("Invalid vector snapshot");return o}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var C=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var R=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var P=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function qe(r){return new Promise(e=>setTimeout(e,r))}async function Y(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let s=1;s<=t;s++)try{return await r()}catch(a){if(i=a,s>=t)break;let u=Math.min(n,o*2**(s-1)),d=Math.floor(Math.random()*Math.max(1,u*.2));await qe(u+d)}throw i}var Qe=new Set(["put","get","getText","delete","list"]);function G(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:Qe.has(o)?(...i)=>Y(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}function q(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 o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var E=class{constructor(e,t,o,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=q(n??o),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(),o=t,n=await this.provider.getText(e);if(n){let s;try{s=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof s.id=="string"&&s.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${s.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof s.createdAt=="string"&&(o=s.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(i,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,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}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))}};var Ze=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],$=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),i=n.replace(/[:.]/g,"-"),s=this.projectPrefix(e),a=this.snapshotPrefix(e,i),u=[];for(let p of Ze){let c=`${s}/${p}`,m=await this.storage.get(c);m&&(await this.storage.put(`${a}/${p}`,m,"application/json"),u.push(p))}if(u.length===0)return null;let d={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:u,metadata:o};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(d,null,2),"application/json"),d}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(s=>s.key.endsWith("/snapshot.json")),i=[];for(let s of n){let a=await this.storage.getText(s.key);if(a)try{i.push(JSON.parse(a))}catch{}}return i.sort((s,a)=>a.createdAt.localeCompare(s.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let i=JSON.parse(n);if(i.projectId!==e)throw new Error("Snapshot project mismatch");let s=this.projectPrefix(e),a=[];for(let u of i.objects){let d=await this.storage.get(`${o}/${u}`);d&&(await this.storage.put(`${s}/${u}`,d,"application/json"),a.push(u))}return{restored:a}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let i of n)await this.storage.delete(i.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),i=0;for(let s of n)await this.remove(e,s.id),i++;return i}};function K(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function Z(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?K(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?K(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?K(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: Hugging Face S3 storage credentials incomplete"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Xe}from"node:crypto";var T=class{constructor(e){this.storage=e}storage;async run(){let e=`_health/production-${Xe()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}return{ok:o,storage:{ok:o,provider:this.storage.name},embedding:null}}};import{existsSync as oe,readFileSync as nt,readdirSync as ee}from"node:fs";import{join as v}from"node:path";var po=new Int32Array(new SharedArrayBuffer(4));import{closeSync as ho,existsSync as et,fsyncSync as So,mkdirSync as ko,openSync as vo,readFileSync as tt,renameSync as wo,writeFileSync as bo}from"node:fs";import{dirname as xo,join as rt}from"node:path";function ot(r){return rt(r.rootPath,".toolnet","work","current.json")}function X(r){let e=ot(r);if(!et(e))return null;try{let t=JSON.parse(tt(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ne(r){if(!oe(r))return null;try{return JSON.parse(nt(r,"utf8"))}catch{return null}}function te(r,e){if(!oe(r))return[];let t=[];for(let o of ee(r,{withFileTypes:!0})){if(!o.isDirectory())continue;let n=v(r,o.name);for(let i of ee(n,{withFileTypes:!0})){if(!i.isDirectory())continue;let s=ne(v(n,i.name,"state.json"));s&&s.version===1&&s.projectId===e.id&&t.push(s)}}return t}function st(r){let e=v(r.rootPath,".toolnet","runtime","sources"),t=v(r.rootPath,".toolnet","sessions"),o=te(e,r),n=te(t,r),i=new Map;for(let s of n)i.set(`${s.agent}:${s.nativeSessionId}`,s);for(let s of o)i.set(`${s.agent}:${s.nativeSessionId}`,s);return Array.from(i.values())}function re(r){return r.filter(e=>!!e).sort().at(-1)}function it(r){let e=ne(v(r.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==r.rootPath?null:e}function se(r){let e=st(r),o=[...e].sort((c,m)=>(c.lastLocalEventAt??c.updatedAt).localeCompare(m.lastLocalEventAt??m.updatedAt)).at(-1),n=Array.from(new Set(e.map(c=>c.agent))).sort(),i=e.reduce((c,m)=>c+Math.max(0,m.lastSequence-m.lastRemoteSequence),0),s=it(r),a=s?.state==="capture-failed",u=s?.state==="sync-failed",d;a?d="degraded":i>0||u?d="pending":e.length>0?d="healthy":d="unknown";let p=X(r);return{ok:d!=="degraded",agents:n,sessions:e.length,latestAgent:o?.agent,latestSessionId:o?.nativeSessionId,lastCaptureAt:re(e.map(c=>c.lastLocalEventAt??c.updatedAt)),lastFlushAt:re(e.map(c=>c.lastRemoteAt)),pendingWal:i,currentTask:p?.currentTask?.title,currentFile:p?.activeFiles?.at(-1)??p?.filesTouched.at(-1),syncHealth:d,opencode:s?{state:s.state,reason:s.reason,timestamp:s.timestamp,error:s.error}:void 0}}function ae(){return process.argv.includes("--json")}function at(r){let e=process.stdout.isTTY===!0&&process.env.TERM!=="dumb"&&process.env.NO_COLOR===void 0,t=(l,D)=>e?`\x1B[${l}m${D}\x1B[0m`:D,o=l=>t("38;5;82",l),n=l=>t("38;5;51",l),i=l=>t("38;5;214",l),s=l=>t("38;5;196",l),a=l=>t("38;5;255",l),u=l=>t("2",l),d=l=>t("1",l),p=u("\u2502"),c=u("\u251C");if(console.log(""),console.log(`${n("\u25C7")} ${d(a("ToolNet Memory Doctor"))}`),console.log(""),r.project&&console.log(`${o("\u25C6")} Project ${a(r.project)}`),console.log(p),r.storage){let l=typeof r.storage.provider=="string"?` \u2014 ${r.storage.provider}`:"";r.storage.ok?console.log(`${c} ${o("\u25C6")} Storage${l}`):console.log(`${c} ${s("\u2717")} Storage${l}`)}if((r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(p),console.log(`${n("\u25C7")} ${a("Project data")}`),r.memory!==void 0&&console.log(`${c} ${u("Memories")} ${a(String(r.memory))}`),r.graphSymbols!==void 0&&console.log(`${c} ${u("Graph symbols")} ${a(String(r.graphSymbols))}`),r.graphEdges!==void 0&&console.log(`${c} ${u("Graph edges")} ${a(String(r.graphEdges))}`),r.memoryVectors!==void 0&&console.log(`${c} ${u("Memory vectors")} ${a(String(r.memoryVectors))}`),r.codeChunks!==void 0&&console.log(`${c} ${u("Code chunks")} ${a(String(r.codeChunks))}`),r.codeVectors!==void 0&&console.log(`${c} ${u("Code vectors")} ${a(String(r.codeVectors))}`),r.snapshots!==void 0&&console.log(`${c} ${u("Snapshots")} ${a(String(r.snapshots))}`)),r.capture){console.log(p),console.log(`${n("\u25C7")} ${a("Session continuity")}`),console.log(`${c} ${u("Agents")} ${a(r.capture.agents.length?r.capture.agents.join(", "):"none")}`),r.capture.latestAgent&&console.log(`${c} ${u("Latest agent")} ${a(String(r.capture.latestAgent))}`),r.capture.currentTask&&console.log(`${c} ${u("Current task")} ${a(r.capture.currentTask)}`),r.capture.currentFile&&console.log(`${c} ${u("Current file")} ${a(r.capture.currentFile)}`),r.capture.lastCaptureAt&&console.log(`${c} ${u("Last capture")} ${a(r.capture.lastCaptureAt)}`),r.capture.lastFlushAt&&console.log(`${c} ${u("Last flush")} ${a(r.capture.lastFlushAt)}`),console.log(`${c} ${u("Pending WAL")} ${a(String(r.capture.pendingWal))}`);let l=r.capture.syncHealth==="healthy"?o(r.capture.syncHealth):r.capture.syncHealth==="degraded"?s(r.capture.syncHealth):i(r.capture.syncHealth);console.log(`${c} ${u("Sync health")} ${l}`)}let m=r.config?.errors??[];if(m.length>0){console.log(p),console.log(`${s("\u2717")} ${a("Configuration required")}`);for(let l of m)console.log(`${c} ${s("\u2022")} ${l}`)}let I=[...r.config?.warnings??[],...r.warnings??[]],g=[...new Set(I)];if(g.length>0){console.log(p),console.log(`${i("\u25C7")} ${a("Warnings")}`);for(let l of g)console.log(`${c} ${i("!")} ${l}`)}console.log(p),r.ok?console.log(`${o("\u2514 \u25C6")} ${d(a("ToolNet Memory is ready"))}`):(console.log(`${s("\u2514 \u2717")} ${d(a("ToolNet Memory requires attention"))}`),m.length>0&&console.log(u(" Run: toolnet-memory setup"))),console.log("")}function ie(r){ae()?console.log(JSON.stringify(r,null,2)):at(r)}async function ct(){let r=Z();if(!r.ok){let l={ok:!1,config:r,warnings:r.warnings};ie(l),process.exitCode=1;return}let e=L(),t=new b().detect(),o=G(J({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=new E(o,t.id,t.name,t.remote??t.name),i=await new T(o).run(),s=await new A(n).load(t.id),a=await new C(n).load(t.id),u=await new M(n).load(t.id),d=await new R(n).load(t.id),p=await new P(n).load(t.id),c=await new $(n).list(t.id),m=se(t),I=m.syncHealth==="degraded"?[`Session capture degraded${m.opencode?.error?`: ${m.opencode.error}`:""}`]:[],g={ok:i.ok&&m.ok,project:t.name,storage:i.storage,memory:s.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:u?.records.length??0,codeChunks:d?.chunks.length??0,codeVectors:p?.records.length??0,snapshots:c.length,capture:m,warnings:[...r.warnings,...I]};ie(g),process.exitCode=g.ok?0:1}ct().catch(r=>{let e=r instanceof Error?r.message:String(r);ae()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
1
+ import"dotenv/config";import{existsSync as Ae,readFileSync as Me}from"node:fs";import{homedir as Ce}from"node:os";import{join as Re}from"node:path";function Pe(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 Ee(){let r=process.env.TOOLNET_GLOBAL_ENV??Re(Ce(),".config","toolnet-memory",".env");if(!Ae(r))return;let e=Me(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 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]=Pe(n.slice(o+1)))}}Ee();function S(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function k(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function U(){return{memory:{autoCapture:S(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:S(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:S(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:S(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:k(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:k(process.env.MEMORY_RERANK_TOP,10),finalContext:k(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:k(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:S(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:k(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Ke}from"node:crypto";import{existsSync as C,mkdirSync as De,readFileSync as Le,renameSync as Fe,writeFileSync as Ve}from"node:fs";import{basename as ze,dirname as R,join as x,parse as re,resolve as g}from"node:path";import{createHash as Z}from"node:crypto";import{spawnSync as Ie}from"node:child_process";var b="git-remote-v1",Te=new Set(["github.com","gitlab.com","bitbucket.org"]);function Q(r,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(n=>!n||n==="."||n==="..")?null:(Te.has(r)&&(t=t.toLowerCase()),t)}function _e(r){let e;try{e=new URL(r)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let n=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!n?`${t}:${e.port}`:t,s=Q(t,e.pathname);return s?`${o}/${s}`:null}function $e(r){let e=r.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let n=Q(t,e[2]??"");return n?`${t}/${n}`:null}function Y(r){let e=r.trim();return e?e.includes("://")?_e(e):$e(e):null}function Oe(r){return Z("sha256").update(`${b}:${r}`).digest("hex")}function X(r){return Z("sha256").update(`toolnet-project:${b}:${r}`).digest("hex").slice(0,16)}function Ne(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function z(r,e){let t=Ie("git",["-C",r,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function q(r,e){let t=Ne(r);return t?{scheme:b,canonicalRemote:r,fingerprint:Oe(r),repositoryName:t,source:e}:null}function ee(r){let e=z(r,["remote","get-url","origin"]);if(e){let o=Y(e);if(o)return q(o,"origin")}let t=z(r,["remote"]);if(!t)return null;let n=new Set;for(let o of t.split(/\r?\n/u).map(s=>s.trim()).filter(Boolean)){let s=z(r,["remote","get-url",o]);if(!s)continue;let i=Y(s);i&&n.add(i)}return n.size!==1?null:q([...n][0],"unique-remote")}var ne=".toolnet",We="project.json";function He(r){return Ke("sha256").update(r).digest("hex").slice(0,16)}function y(r){return x(r,ne,We)}function oe(r){return C(y(r))}function te(r,e){let t=g(r),n=re(t).root;for(;;){if(oe(t))return t;if(t===n||e&&t===g(e))break;let o=R(t);if(o===t)break;t=o}return null}function W(r){let e=g(r),t=re(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>C(x(e,s))))return e;if(e===t)break;let o=R(e);if(o===e)break;e=o}return g(r)}function A(r){let e;try{e=JSON.parse(Le(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}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:R(R(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 M(r,e){let t=x(r,ne);De(t,{recursive:!0});let n=y(r),o=`${n}.tmp-${process.pid}`;Ve(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Fe(o,n)}function f(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}}function H(r){return{version:1,scheme:b,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function Be(r){let e=r.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var P=class{adopt(e,t){let n=W(g(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(oe(n)){let a=A(y(n));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return f(a,n)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=H(t.gitIdentity));let i={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:n,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return M(n,i),f(i,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),s=y(o.rootPath),i=A(s),a=Be(i);if(a&&a!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${a}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let c=i.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:H(t)},i.updatedAt=new Date().toISOString(),M(o.rootPath,i)),f(i,o.rootPath)}findExisting(e=process.cwd()){let t=g(e),n=W(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>C(x(n,c))),i=te(t,s?n:void 0);if(!i)return null;let a=A(y(i));return f(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=g(e),n=W(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>C(x(n,u))),i=te(t,s?n:void 0);if(i){let u=y(i),p=A(u);return p.rootPath!==i&&(p.rootPath=i,p.updatedAt=new Date().toISOString(),M(i,p)),f(p,i)}let a=new Date().toISOString(),c=ze(n),d=ee(n),m={version:1,id:d?X(d.canonicalRemote):He(n),name:c,remote:d?.repositoryName??c,rootPath:n,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:d?{toolnetIdentity:H(d)}:void 0};return M(n,m),f(m,n)}};var Ge=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],Je=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function se(r){return r.normalize("NFKC").trim().toLowerCase()}function Ue(r){if(r.length===0)return 0;let e=new Map;for(let n of r)e.set(n,(e.get(n)??0)+1);let t=0;for(let n of e.values()){let o=n/r.length;t-=o*Math.log2(o)}return t}function Ye(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function qe(r,e,t){let n=r.slice(Math.max(0,e-48),e),o=r.slice(t,Math.min(r.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${o}`)}function Ze(r,e){return r.start<e.end&&e.start<r.end}function ie(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var E=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=se(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of Ge){let i=new RegExp(s.regex.source,s.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:s.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ie(t),o=[];for(let s of n)o.some(i=>Ze(i,s))||o.push(s);return ie(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=se(e);return Je.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(n)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||Ye(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||qe(e,o.index,o.index+s.length)&&(Ue(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var I=class{scanner;constructor(e={}){this.scanner=new E(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let n=e,o=[...t].sort((i,a)=>a.start-i.start),s=new Set;for(let i of o)s.add(i.type),n=n.slice(0,i.start)+`[REDACTED:${i.type}]`+n.slice(i.end);return{text:n,redacted:t.length,secretTypes:[...s].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[n,o]of Object.entries(e)){let s=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){t[n]="[REDACTED]";continue}t[n]=this.sanitizeValue(o)}return t}return e}};var tr=new I;import{homedir as xt}from"node:os";import{join as wt}from"node:path";import{DeleteObjectCommand as Xe,GetObjectCommand as et,HeadObjectCommand as tt,ListObjectsV2Command as rt,PutObjectCommand as nt,S3Client as ot}from"@aws-sdk/client-s3";import{getSignedUrl as st}from"@aws-sdk/s3-request-presigner";var T=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ot({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new nt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await st(this.client,new et({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 tt({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 Xe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new rt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as ae,mkdir as it,readFile as at,readdir as ct,rm as ut,stat as ce,writeFile as dt}from"node:fs/promises";import{dirname as lt,join as pt,relative as ue,resolve as mt}from"node:path";var w=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return mt(this.root,t)}async put(e,t){let n=this.path(e);await it(lt(n),{recursive:!0}),await dt(n,t)}async get(e){try{return await at(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 ae(this.path(e)),!0}catch{return!1}}async delete(e){await ut(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await ae(t)}catch{return n}let o=async i=>{let a=await ct(i,{withFileTypes:!0});for(let c of a){let d=pt(i,c.name);if(c.isDirectory()){await o(d);continue}let m=await ce(d);n.push({key:ue(this.root,d),size:m.size,updatedAt:m.mtime.toISOString()})}},s=await ce(t);return s.isDirectory()?await o(t):n.push({key:ue(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as ft,GetObjectCommand as gt,HeadObjectCommand as yt,ListObjectsV2Command as ht,PutObjectCommand as St,S3Client as kt}from"@aws-sdk/client-s3";import{getSignedUrl as bt}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 kt({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new St({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await bt(this.client,new gt({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 yt({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 ft({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new ht({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};function B(r,e){return console.warn(e),new w(r)}function de(r){let e=r.localRoot??wt(xt(),".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}):B(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}):B(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 T({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):B(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new w(e)}var _=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let n=JSON.parse(t);if(!Array.isArray(n))throw new Error("Invalid memory snapshot");return n}async save(e,t){let n=JSON.stringify(t,null,2);await this.storage.put(this.key(e),n,"application/json")}};var $=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let n=JSON.parse(t);if(n.version!==1||n.projectId!==e||!Array.isArray(n.records))throw new Error("Invalid vector snapshot");return n}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var O=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var N=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var K=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function vt(r){return new Promise(e=>setTimeout(e,r))}async function le(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await r()}catch(a){if(s=a,i>=t)break;let c=Math.min(o,n*2**(i-1)),d=Math.floor(Math.random()*Math.max(1,c*.2));await vt(c+d)}throw s}var jt=new Set(["put","get","getText","delete","list"]);function pe(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:jt.has(n)?(...s)=>le(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function me(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 fe(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 o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var D=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=me(o??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,o=await this.provider.getText(e);if(o){let i;try{i=JSON.parse(o)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(n=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=fe(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))}};var At=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],L=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",n){let o=new Date().toISOString(),s=o.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,s),c=[];for(let m of At){let u=`${i}/${m}`,p=await this.storage.get(u);p&&(await this.storage.put(`${a}/${m}`,p,"application/json"),c.push(m))}if(c.length===0)return null;let d={version:1,id:s,projectId:e,createdAt:o,reason:t,objects:c,metadata:n};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(d,null,2),"application/json"),d}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),o=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),s=[];for(let i of o){let a=await this.storage.getText(i.key);if(a)try{s.push(JSON.parse(a))}catch{}}return s.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let n=this.snapshotPrefix(e,t),o=await this.storage.getText(`${n}/snapshot.json`);if(!o)throw new Error(`Snapshot not found: ${t}`);let s=JSON.parse(o);if(s.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of s.objects){let d=await this.storage.get(`${n}/${c}`);d&&(await this.storage.put(`${i}/${c}`,d,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let n=this.snapshotPrefix(e,t),o=await this.storage.list(n);for(let s of o)await this.storage.delete(s.key);return o.length}async prune(e,t=10){let o=(await this.list(e)).slice(t),s=0;for(let i of o)await this.remove(e,i.id),s++;return s}};function G(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function ge(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?G(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?G(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?G(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: Hugging Face S3 storage credentials incomplete"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Mt}from"node:crypto";var F=class{constructor(e){this.storage=e}storage;async run(){let e=`_health/production-${Mt()}.txt`,t=`toolnet-memory:${Date.now()}`,n=!1;try{await this.storage.put(e,t,"text/plain"),n=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}return{ok:n,storage:{ok:n,provider:this.storage.name},embedding:null}}};import{existsSync as be,readFileSync as It,readdirSync as he}from"node:fs";import{join as j}from"node:path";var Yn=new Int32Array(new SharedArrayBuffer(4));import{closeSync as eo,existsSync as Ct,fsyncSync as to,mkdirSync as ro,openSync as no,readFileSync as Rt,renameSync as oo,writeFileSync as so}from"node:fs";import{dirname as ao,join as Pt}from"node:path";function Et(r){return Pt(r.rootPath,".toolnet","work","current.json")}function ye(r){let e=Et(r);if(!Ct(e))return null;try{let t=JSON.parse(Rt(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function xe(r){if(!be(r))return null;try{return JSON.parse(It(r,"utf8"))}catch{return null}}function Se(r,e){if(!be(r))return[];let t=[];for(let n of he(r,{withFileTypes:!0})){if(!n.isDirectory())continue;let o=j(r,n.name);for(let s of he(o,{withFileTypes:!0})){if(!s.isDirectory())continue;let i=xe(j(o,s.name,"state.json"));i&&i.version===1&&i.projectId===e.id&&t.push(i)}}return t}function Tt(r){let e=j(r.rootPath,".toolnet","runtime","sources"),t=j(r.rootPath,".toolnet","sessions"),n=Se(e,r),o=Se(t,r),s=new Map;for(let i of o)s.set(`${i.agent}:${i.nativeSessionId}`,i);for(let i of n)s.set(`${i.agent}:${i.nativeSessionId}`,i);return Array.from(s.values())}function ke(r){return r.filter(e=>!!e).sort().at(-1)}function _t(r){let e=xe(j(r.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==r.rootPath?null:e}function we(r){let e=Tt(r),n=[...e].sort((u,p)=>(u.lastLocalEventAt??u.updatedAt).localeCompare(p.lastLocalEventAt??p.updatedAt)).at(-1),o=Array.from(new Set(e.map(u=>u.agent))).sort(),s=e.reduce((u,p)=>u+Math.max(0,p.lastSequence-p.lastRemoteSequence),0),i=_t(r),a=i?.state==="capture-failed",c=i?.state==="sync-failed",d;a?d="degraded":s>0||c?d="pending":e.length>0?d="healthy":d="unknown";let m=ye(r);return{ok:d!=="degraded",agents:o,sessions:e.length,latestAgent:n?.agent,latestSessionId:n?.nativeSessionId,lastCaptureAt:ke(e.map(u=>u.lastLocalEventAt??u.updatedAt)),lastFlushAt:ke(e.map(u=>u.lastRemoteAt)),pendingWal:s,currentTask:m?.currentTask?.title,currentFile:m?.activeFiles?.at(-1)??m?.filesTouched.at(-1),syncHealth:d,opencode:i?{state:i.state,reason:i.reason,timestamp:i.timestamp,error:i.error}:void 0}}function je(){return process.argv.includes("--json")}function $t(r){let e=process.stdout.isTTY===!0&&process.env.TERM!=="dumb"&&process.env.NO_COLOR===void 0,t=(l,J)=>e?`\x1B[${l}m${J}\x1B[0m`:J,n=l=>t("38;5;82",l),o=l=>t("38;5;51",l),s=l=>t("38;5;214",l),i=l=>t("38;5;196",l),a=l=>t("38;5;255",l),c=l=>t("2",l),d=l=>t("1",l),m=c("\u2502"),u=c("\u251C");if(console.log(""),console.log(`${o("\u25C7")} ${d(a("ToolNet Memory Doctor"))}`),console.log(""),r.project&&console.log(`${n("\u25C6")} Project ${a(r.project)}`),console.log(m),r.storage){let l=typeof r.storage.provider=="string"?` \u2014 ${r.storage.provider}`:"";r.storage.ok?console.log(`${u} ${n("\u25C6")} Storage${l}`):console.log(`${u} ${i("\u2717")} Storage${l}`)}if((r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(m),console.log(`${o("\u25C7")} ${a("Project data")}`),r.memory!==void 0&&console.log(`${u} ${c("Memories")} ${a(String(r.memory))}`),r.graphSymbols!==void 0&&console.log(`${u} ${c("Graph symbols")} ${a(String(r.graphSymbols))}`),r.graphEdges!==void 0&&console.log(`${u} ${c("Graph edges")} ${a(String(r.graphEdges))}`),r.memoryVectors!==void 0&&console.log(`${u} ${c("Memory vectors")} ${a(String(r.memoryVectors))}`),r.codeChunks!==void 0&&console.log(`${u} ${c("Code chunks")} ${a(String(r.codeChunks))}`),r.codeVectors!==void 0&&console.log(`${u} ${c("Code vectors")} ${a(String(r.codeVectors))}`),r.snapshots!==void 0&&console.log(`${u} ${c("Snapshots")} ${a(String(r.snapshots))}`)),r.capture){console.log(m),console.log(`${o("\u25C7")} ${a("Session continuity")}`),console.log(`${u} ${c("Agents")} ${a(r.capture.agents.length?r.capture.agents.join(", "):"none")}`),r.capture.latestAgent&&console.log(`${u} ${c("Latest agent")} ${a(String(r.capture.latestAgent))}`),r.capture.currentTask&&console.log(`${u} ${c("Current task")} ${a(r.capture.currentTask)}`),r.capture.currentFile&&console.log(`${u} ${c("Current file")} ${a(r.capture.currentFile)}`),r.capture.lastCaptureAt&&console.log(`${u} ${c("Last capture")} ${a(r.capture.lastCaptureAt)}`),r.capture.lastFlushAt&&console.log(`${u} ${c("Last flush")} ${a(r.capture.lastFlushAt)}`),console.log(`${u} ${c("Pending WAL")} ${a(String(r.capture.pendingWal))}`);let l=r.capture.syncHealth==="healthy"?n(r.capture.syncHealth):r.capture.syncHealth==="degraded"?i(r.capture.syncHealth):s(r.capture.syncHealth);console.log(`${u} ${c("Sync health")} ${l}`)}let p=r.config?.errors??[];if(p.length>0){console.log(m),console.log(`${i("\u2717")} ${a("Configuration required")}`);for(let l of p)console.log(`${u} ${i("\u2022")} ${l}`)}let V=[...r.config?.warnings??[],...r.warnings??[]],h=[...new Set(V)];if(h.length>0){console.log(m),console.log(`${s("\u25C7")} ${a("Warnings")}`);for(let l of h)console.log(`${u} ${s("!")} ${l}`)}console.log(m),r.ok?console.log(`${n("\u2514 \u25C6")} ${d(a("ToolNet Memory is ready"))}`):(console.log(`${i("\u2514 \u2717")} ${d(a("ToolNet Memory requires attention"))}`),p.length>0&&console.log(c(" Run: toolnet-memory setup"))),console.log("")}function ve(r){je()?console.log(JSON.stringify(r,null,2)):$t(r)}async function Ot(){let r=ge();if(!r.ok){let l={ok:!1,config:r,warnings:r.warnings};ve(l),process.exitCode=1;return}let e=U(),t=new P().detect(),n=pe(de({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new D(n,t.id,t.name,t.remote??t.name),s=await new F(n).run(),i=await new _(o).load(t.id),a=await new O(o).load(t.id),c=await new $(o).load(t.id),d=await new N(o).load(t.id),m=await new K(o).load(t.id),u=await new L(o).list(t.id),p=we(t),V=p.syncHealth==="degraded"?[`Session capture degraded${p.opencode?.error?`: ${p.opencode.error}`:""}`]:[],h={ok:s.ok&&p.ok,project:t.name,storage:s.storage,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:c?.records.length??0,codeChunks:d?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:u.length,capture:p,warnings:[...r.warnings,...V]};ve(h),process.exitCode=h.ok?0:1}Ot().catch(r=>{let e=r instanceof Error?r.message:String(r);je()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});