toolnet-memory 0.3.14 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -1
- package/.release-target +1 -1
- package/README.md +25 -1
- package/bin/toolnet-memory +5 -0
- package/bundle/agy-hook.js +67 -67
- package/bundle/agy.js +61 -61
- package/bundle/api.js +15 -15
- package/bundle/auto-integrate.js +28 -28
- package/bundle/background-refresh.js +7 -7
- package/bundle/claude-hook.js +51 -50
- package/bundle/codex-context.js +25 -24
- package/bundle/codex.js +71 -71
- package/bundle/context-runtime.js +45 -44
- package/bundle/context.js +15 -15
- package/bundle/continuity-certify.js +13 -13
- package/bundle/copilot-hook.js +87 -85
- package/bundle/copilot.js +4 -4
- package/bundle/cursor-hook.js +87 -85
- package/bundle/cursor.js +4 -4
- package/bundle/doctor.js +4 -4
- package/bundle/full-index.js +20 -20
- package/bundle/gc.js +3 -0
- package/bundle/graph-index.js +4 -4
- package/bundle/graph-ui.js +3 -3
- package/bundle/grok-hook.js +60 -59
- package/bundle/grok.js +5 -5
- package/bundle/handoff-refresh.js +10 -10
- package/bundle/help-cli.js +4 -4
- package/bundle/impact.js +4 -4
- package/bundle/incremental.js +5 -4
- package/bundle/init.js +37 -37
- package/bundle/integration-status.js +4 -4
- package/bundle/kiro-hook.js +82 -81
- package/bundle/learner.js +6 -6
- package/bundle/mcp.js +17 -17
- package/bundle/memory-agent.js +7 -7
- package/bundle/memory-query.js +7 -7
- package/bundle/opencode.js +80 -80
- package/bundle/project-manual.js +7 -7
- package/bundle/recovery-certify.js +15 -15
- package/bundle/runtime.js +13 -12
- package/bundle/semantic.js +5 -5
- package/bundle/snapshot.js +4 -4
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +60 -60
- package/bundle/work-continuity.js +7 -7
- package/package.json +9 -3
- package/release-manifest.json +54 -3
package/bundle/cursor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{homedir as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),
|
|
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
|
|
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
|
|
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
|
|
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 me,readFileSync as ye}from"node:fs";import{homedir as he}from"node:os";import{join as Se}from"node:path";function ke(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 we(){let r=process.env.TOOLNET_GLOBAL_ENV??Se(he(),".config","toolnet-memory",".env");if(!me(r))return;let e=ye(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]=ke(n.slice(o+1)))}}we();function y(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function h(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function W(){return{memory:{autoCapture:y(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:y(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:y(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:y(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:h(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:h(process.env.MEMORY_RERANK_TOP,10),finalContext:h(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:h(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:y(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:h(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as be}from"node:crypto";import{existsSync as v,mkdirSync as ve,readFileSync as xe,renameSync as je,writeFileSync as Ae}from"node:fs";import{basename as Me,dirname as x,join as S,parse as U,resolve as f}from"node:path";var Y=".toolnet",Ce="project.json";function Re(r){return be("sha256").update(r).digest("hex").slice(0,16)}function j(r){return S(r,Y,Ce)}function Pe(r){return v(j(r))}function z(r,e){let t=f(r),n=U(t).root;for(;;){if(Pe(t))return t;if(t===n||e&&t===f(e))break;let o=x(t);if(o===t)break;t=o}return null}function H(r){let e=f(r),t=U(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>v(S(e,s))))return e;if(e===t)break;let o=x(e);if(o===e)break;e=o}return f(r)}function B(r){let e;try{e=JSON.parse(xe(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:x(x(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 J(r,e){let t=S(r,Y);ve(t,{recursive:!0});let n=j(r),o=`${n}.tmp-${process.pid}`;Ae(o,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),je(o,n)}function D(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 A=class{findExisting(e=process.cwd()){let t=f(e),n=H(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>v(S(n,c))),i=z(t,s?n:void 0);if(!i)return null;let a=B(j(i));return D(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=f(e),n=H(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>v(S(n,p))),i=z(t,s?n:void 0);if(i){let p=j(i),u=B(p);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),J(i,u)),D(u,i)}let a=new Date().toISOString(),c=Me(n),d={version:1,id:Re(n),name:c,remote:c,rootPath:n,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return J(n,d),D(d,n)}};var Ee=[{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"}],Te=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function G(r){return r.normalize("NFKC").trim().toLowerCase()}function $e(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 Ie(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function _e(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 Oe(r,e){return r.start<e.end&&e.start<r.end}function q(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var M=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=G(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of Ee){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=q(t),o=[];for(let s of n)o.some(i=>Oe(i,s))||o.push(s);return q(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=G(e);return Te.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)||Ie(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||_e(e,o.index,o.index+s.length)&&($e(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var C=class{scanner;constructor(e={}){this.scanner=new M(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 Ot=new C;import{homedir as st}from"node:os";import{join as it}from"node:path";import{DeleteObjectCommand as Ke,GetObjectCommand as De,HeadObjectCommand as Le,ListObjectsV2Command as Fe,PutObjectCommand as Ve,S3Client as We}from"@aws-sdk/client-s3";import{getSignedUrl as ze}from"@aws-sdk/s3-request-presigner";var R=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new We({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 Ve({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await ze(this.client,new De({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 Le({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 Ke({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Fe({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 Z,mkdir as He,readFile as Be,readdir as Je,rm as Ue,stat as Q,writeFile as Ye}from"node:fs/promises";import{dirname as Ge,join as qe,relative as X,resolve as Ze}from"node:path";var k=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ze(this.root,t)}async put(e,t){let n=this.path(e);await He(Ge(n),{recursive:!0}),await Ye(n,t)}async get(e){try{return await Be(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 Z(this.path(e)),!0}catch{return!1}}async delete(e){await Ue(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await Z(t)}catch{return n}let o=async i=>{let a=await Je(i,{withFileTypes:!0});for(let c of a){let d=qe(i,c.name);if(c.isDirectory()){await o(d);continue}let p=await Q(d);n.push({key:X(this.root,d),size:p.size,updatedAt:p.mtime.toISOString()})}},s=await Q(t);return s.isDirectory()?await o(t):n.push({key:X(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as Qe,GetObjectCommand as Xe,HeadObjectCommand as et,ListObjectsV2Command as tt,PutObjectCommand as rt,S3Client as nt}from"@aws-sdk/client-s3";import{getSignedUrl as ot}from"@aws-sdk/s3-request-presigner";var w=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new nt({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 rt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await ot(this.client,new Xe({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 et({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 Qe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new tt({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 L(r,e){return console.warn(e),new k(r)}function ee(r){let e=r.localRoot??it(st(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new w({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(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 w({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(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 R({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new k(e)}var P=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 E=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 T=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 $=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 I=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 at(r){return new Promise(e=>setTimeout(e,r))}async function te(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 at(c+d)}throw s}var ct=new Set(["put","get","getText","delete","list"]);function re(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:ct.has(n)?(...s)=>te(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function ne(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 oe(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 _=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=ne(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=oe(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 ut=["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"],O=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 p of ut){let u=`${i}/${p}`,g=await this.storage.get(u);g&&(await this.storage.put(`${a}/${p}`,g,"application/json"),c.push(p))}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 F(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function se(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?F(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?F(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?F(["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 dt}from"node:crypto";var N=class{constructor(e){this.storage=e}storage;async run(){let e=`_health/production-${dt()}.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 de,readFileSync as mt,readdirSync as ae}from"node:fs";import{join as b}from"node:path";var An=new Int32Array(new SharedArrayBuffer(4));import{closeSync as En,existsSync as lt,fsyncSync as Tn,mkdirSync as $n,openSync as In,readFileSync as pt,renameSync as _n,writeFileSync as On}from"node:fs";import{dirname as Kn,join as gt}from"node:path";function ft(r){return gt(r.rootPath,".toolnet","work","current.json")}function ie(r){let e=ft(r);if(!lt(e))return null;try{let t=JSON.parse(pt(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function le(r){if(!de(r))return null;try{return JSON.parse(mt(r,"utf8"))}catch{return null}}function ce(r,e){if(!de(r))return[];let t=[];for(let n of ae(r,{withFileTypes:!0})){if(!n.isDirectory())continue;let o=b(r,n.name);for(let s of ae(o,{withFileTypes:!0})){if(!s.isDirectory())continue;let i=le(b(o,s.name,"state.json"));i&&i.version===1&&i.projectId===e.id&&t.push(i)}}return t}function yt(r){let e=b(r.rootPath,".toolnet","runtime","sources"),t=b(r.rootPath,".toolnet","sessions"),n=ce(e,r),o=ce(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 ue(r){return r.filter(e=>!!e).sort().at(-1)}function ht(r){let e=le(b(r.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==r.rootPath?null:e}function pe(r){let e=yt(r),n=[...e].sort((u,g)=>(u.lastLocalEventAt??u.updatedAt).localeCompare(g.lastLocalEventAt??g.updatedAt)).at(-1),o=Array.from(new Set(e.map(u=>u.agent))).sort(),s=e.reduce((u,g)=>u+Math.max(0,g.lastSequence-g.lastRemoteSequence),0),i=ht(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 p=ie(r);return{ok:d!=="degraded",agents:o,sessions:e.length,latestAgent:n?.agent,latestSessionId:n?.nativeSessionId,lastCaptureAt:ue(e.map(u=>u.lastLocalEventAt??u.updatedAt)),lastFlushAt:ue(e.map(u=>u.lastRemoteAt)),pendingWal:s,currentTask:p?.currentTask?.title,currentFile:p?.activeFiles?.at(-1)??p?.filesTouched.at(-1),syncHealth:d,opencode:i?{state:i.state,reason:i.reason,timestamp:i.timestamp,error:i.error}:void 0}}function fe(){return process.argv.includes("--json")}function St(r){let e=process.stdout.isTTY===!0&&process.env.TERM!=="dumb"&&process.env.NO_COLOR===void 0,t=(l,V)=>e?`\x1B[${l}m${V}\x1B[0m`:V,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),p=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(p),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(p),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(p),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 g=r.config?.errors??[];if(g.length>0){console.log(p),console.log(`${i("\u2717")} ${a("Configuration required")}`);for(let l of g)console.log(`${u} ${i("\u2022")} ${l}`)}let K=[...r.config?.warnings??[],...r.warnings??[]],m=[...new Set(K)];if(m.length>0){console.log(p),console.log(`${s("\u25C7")} ${a("Warnings")}`);for(let l of m)console.log(`${u} ${s("!")} ${l}`)}console.log(p),r.ok?console.log(`${n("\u2514 \u25C6")} ${d(a("ToolNet Memory is ready"))}`):(console.log(`${i("\u2514 \u2717")} ${d(a("ToolNet Memory requires attention"))}`),g.length>0&&console.log(c(" Run: toolnet-memory setup"))),console.log("")}function ge(r){fe()?console.log(JSON.stringify(r,null,2)):St(r)}async function kt(){let r=se();if(!r.ok){let l={ok:!1,config:r,warnings:r.warnings};ge(l),process.exitCode=1;return}let e=W(),t=new A().detect(),n=re(ee({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new _(n,t.id,t.name,t.remote??t.name),s=await new N(n).run(),i=await new P(o).load(t.id),a=await new T(o).load(t.id),c=await new E(o).load(t.id),d=await new $(o).load(t.id),p=await new I(o).load(t.id),u=await new O(o).list(t.id),g=pe(t),K=g.syncHealth==="degraded"?[`Session capture degraded${g.opencode?.error?`: ${g.opencode.error}`:""}`]:[],m={ok:s.ok&&g.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:p?.records.length??0,snapshots:u.length,capture:g,warnings:[...r.warnings,...K]};ge(m),process.exitCode=m.ok?0:1}kt().catch(r=>{let e=r instanceof Error?r.message:String(r);fe()?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});
|