toolnet-memory 0.3.9 → 0.3.10
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/README.md +8 -1
- package/bin/toolnet-memory +48 -0
- package/bundle/auto-integrate.js +60 -28
- package/bundle/continuity-certify.js +1 -1
- package/bundle/copilot-hook.js +208 -0
- package/bundle/copilot.js +33 -0
- package/bundle/cursor-hook.js +206 -0
- package/bundle/cursor.js +33 -0
- package/bundle/grok-hook.js +114 -0
- package/bundle/grok.js +33 -0
- package/bundle/help-cli.js +4 -4
- package/bundle/init.js +65 -33
- package/bundle/kiro-hook.js +1 -1
- package/bundle/production-certify.js +5 -5
- package/bundle/setup.js +61 -29
- package/bundle/status-cli.js +4 -4
- package/bundle/update.js +5 -4
- package/package.json +16 -3
package/bundle/cursor.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import{homedir as yo}from"node:os";import{join as _}from"node:path";function V(o={}){return o.cursorHome??_(o.home??yo(),".cursor")}function I(o={}){return _(V(o),"mcp.json")}function E(o={}){return _(V(o),"hooks.json")}import{existsSync as Co,mkdirSync as bo,readFileSync as Oo,renameSync as wo,rmSync as Fo,writeFileSync as So}from"node:fs";import{dirname as vo}from"node:path";function f(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function k(o,r){if(!Co(o))return{};let n=Oo(o,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(e){throw new Error(`Invalid existing ${r} hooks file: ${e instanceof Error?e.message:String(e)}`)}if(!f(t))throw new Error(`Invalid existing ${r} hooks file: root must be a JSON object.`);return t}function C(o,r){bo(vo(o),{recursive:!0,mode:448});let n=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{So(n,`${JSON.stringify(r,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),wo(n,o)}finally{Fo(n,{force:!0})}}function R(o){return/^[A-Za-z0-9_./:-]+$/u.test(o)?o:`'${o.replace(/'/gu,"'\\''")}'`}var F=[["sessionStart",10],["beforeSubmitPrompt",10],["preToolUse",10],["postToolUse",15],["afterAgentResponse",15],["stop",30]];function K(o){return f(o)&&typeof o.command=="string"&&o.command.includes("session:cursor-hook")}function xo(o,r,n){let e={type:"command",command:`TOOLNET_HOOK_EVENT=${R(o)} ${R(r)} session:cursor-hook`,timeout:n};return o==="preToolUse"&&(e.matcher=".*"),e}function q(o={}){let r=o.hooksFile??E(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=k(r,"Cursor");if(t.version!==void 0&&t.version!==1)throw new Error(`Unsupported existing Cursor hooks version: ${String(t.version)}`);let e=t.hooks;if(e!==void 0&&!f(e))throw new Error("Invalid existing Cursor hooks file: hooks must be an object.");let s=f(e)?{...e}:{};for(let[l,c]of F){let a=s[l];if(a!==void 0&&!Array.isArray(a))throw new Error(`Invalid existing Cursor hooks file: hooks.${l} must be an array.`);let m=Array.isArray(a)?a.filter(p=>!K(p)):[];s[l]=[...m,xo(l,n,c)]}let i={...t,version:1,hooks:s};if(JSON.stringify(t)===JSON.stringify(i))return{hooksFile:r,changed:!1,hookCount:F.length};C(r,i);let u=k(r,"Cursor");if(u.version!==1||!f(u.hooks))throw new Error("Cursor hooks were written but verification failed.");let g=0;for(let[l]of F){let c=u.hooks[l];if(!Array.isArray(c))throw new Error("Cursor hooks were written but verification failed.");g+=c.filter(K).length}if(g!==F.length)throw new Error("Cursor hooks were written but verification failed.");return{hooksFile:r,changed:!0,hookCount:F.length}}import{existsSync as Io,mkdirSync as Eo,readFileSync as Ho,renameSync as No,rmSync as jo,writeFileSync as To}from"node:fs";import{dirname as $o}from"node:path";function d(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function b(o,r){if(!Io(o))return{};let n=Ho(o,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(e){throw new Error(`Invalid existing ${r} MCP config: ${e instanceof Error?e.message:String(e)}`)}if(!d(t))throw new Error(`Invalid existing ${r} MCP config: root must be a JSON object.`);return t}function H(o,r){Eo($o(o),{recursive:!0,mode:448});let n=`${o}.tmp-${process.pid}-${Date.now()}`;try{To(n,`${JSON.stringify(r,null,2)}
|
|
3
|
+
`,{encoding:"utf8",mode:384}),No(n,o)}finally{jo(n,{force:!0})}}function z(o,r){return d(o)?(o.type===void 0||o.type==="stdio")&&o.command===r&&Array.isArray(o.args)&&o.args.length===1&&o.args[0]==="mcp":!1}function Q(o={}){let r=o.configFile??I(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.serverName??"toolnet-memory",e=b(r,"Cursor"),s=e.mcpServers;if(s!==void 0&&!d(s))throw new Error("Invalid existing Cursor MCP config: mcpServers must be an object.");let i=d(s)?{...s}:{};if(z(i[t],n))return{installed:!0,changed:!1,configFile:r,serverName:t,command:n,args:["mcp"]};i[t]={type:"stdio",command:n,args:["mcp"]},H(r,{...e,mcpServers:i});let g=b(r,"Cursor").mcpServers;if(!d(g)||!z(g[t],n))throw new Error("Cursor MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:r,serverName:t,command:n,args:["mcp"]}}function X(o={}){let r=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=Q({binary:r,configFile:o.configFile}),t=q({binary:r,hooksFile:o.hooksFile});return{installed:n.installed,changed:n.changed||t.changed,mcp:n,hooks:t,files:[n.configFile,t.hooksFile]}}import{homedir as Jo}from"node:os";import{join as N}from"node:path";function Z(o={}){return o.copilotHome??process.env.COPILOT_HOME??N(o.home??Jo(),".copilot")}function j(o={}){return N(Z(o),"mcp-config.json")}function Mo(o={}){return N(Z(o),"hooks")}function T(o={}){return N(Mo(o),"toolnet-memory.json")}var S=[["sessionStart",10],["userPromptSubmitted",10],["userPromptTransformed",10],["preToolUse",10],["postToolUse",15],["agentStop",30]];function Go(o){if(typeof o.command=="string")return o.command;if(typeof o.bash=="string")return o.bash}function oo(o){return f(o)&&Go(o)?.includes("session:copilot-hook")===!0}function Ao(o,r,n){let t={type:"command",command:`${r} session:copilot-hook`,env:{TOOLNET_HOOK_EVENT:o},timeoutSec:n};return o==="preToolUse"&&(t.matcher=".*"),t}function ro(o={}){let r=o.hooksFile??T(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=k(r,"GitHub Copilot CLI");if(t.version!==void 0&&t.version!==1)throw new Error(`Unsupported existing GitHub Copilot CLI hooks version: ${String(t.version)}`);let e=t.hooks;if(e!==void 0&&!f(e))throw new Error("Invalid existing GitHub Copilot CLI hooks file: hooks must be an object.");let s=f(e)?{...e}:{};for(let[l,c]of S){let a=s[l];if(a!==void 0&&!Array.isArray(a))throw new Error(`Invalid existing GitHub Copilot CLI hooks file: hooks.${l} must be an array.`);let m=Array.isArray(a)?a.filter(p=>!oo(p)):[];s[l]=[...m,Ao(l,n,c)]}let i={...t,version:1,hooks:s};if(JSON.stringify(t)===JSON.stringify(i))return{hooksFile:r,changed:!1,hookCount:S.length};C(r,i);let u=k(r,"GitHub Copilot CLI");if(u.version!==1||!f(u.hooks))throw new Error("GitHub Copilot CLI hooks were written but verification failed.");let g=0;for(let[l]of S){let c=u.hooks[l];if(!Array.isArray(c))throw new Error("GitHub Copilot CLI hooks were written but verification failed.");g+=c.filter(oo).length}if(g!==S.length)throw new Error("GitHub Copilot CLI hooks were written but verification failed.");return{hooksFile:r,changed:!0,hookCount:S.length}}function no(o,r){return d(o)?(o.type===void 0||o.type==="local"||o.type==="stdio")&&o.command===r&&Array.isArray(o.args)&&o.args.length===1&&o.args[0]==="mcp"&&Array.isArray(o.tools)&&o.tools.length===1&&o.tools[0]==="*":!1}function to(o={}){let r=o.configFile??j(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.serverName??"toolnet-memory",e=b(r,"GitHub Copilot CLI"),s=e.mcpServers;if(s!==void 0&&!d(s))throw new Error("Invalid existing GitHub Copilot CLI MCP config: mcpServers must be an object.");let i=d(s)?{...s}:{};if(no(i[t],n))return{installed:!0,changed:!1,configFile:r,serverName:t,command:n,args:["mcp"]};i[t]={type:"stdio",command:n,args:["mcp"],tools:["*"]},H(r,{...e,mcpServers:i});let g=b(r,"GitHub Copilot CLI").mcpServers;if(!d(g)||!no(g[t],n))throw new Error("GitHub Copilot CLI MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:r,serverName:t,command:n,args:["mcp"]}}function eo(o={}){let r=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=to({binary:r,configFile:o.configFile}),t=ro({binary:r,hooksFile:o.hooksFile});return{installed:n.installed,changed:n.changed||t.changed,mcp:n,hooks:t,files:[n.configFile,t.hooksFile]}}import{existsSync as Do,mkdirSync as Uo,readFileSync as io,renameSync as Bo,rmSync as Wo,writeFileSync as Yo}from"node:fs";import{dirname as Vo}from"node:path";import{homedir as Po}from"node:os";import{join as y}from"node:path";function L(o={}){return o.grokHome??process.env.GROK_HOME??y(o.home??Po(),".grok")}function $(o={}){return y(L(o),"config.toml")}function _o(o={}){return y(L(o),"hooks")}function J(o={}){return y(_o(o),"toolnet-memory.json")}function Ro(o={}){return y(L(o),"skills")}function Lo(o={}){return y(Ro(o),"toolnet-continuity")}function M(o={}){return y(Lo(o),"SKILL.md")}var D=`---
|
|
4
|
+
name: toolnet-continuity
|
|
5
|
+
description: Restore previous ToolNet project work when the user asks to continue, resume, pick up, finish unfinished work, or asks where work stopped.
|
|
6
|
+
when-to-use: continue, resume, pick up, carry on, ti\u1EBFp t\u1EE5c, l\xE0m ti\u1EBFp, l\xE0m n\u1ED1t, \u0111ang l\xE0m \u0111\u1EBFn \u0111\xE2u, d\u1EEBng \u1EDF \u0111\xE2u
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# ToolNet Continuity
|
|
10
|
+
|
|
11
|
+
When the user asks to continue or resume previous work:
|
|
12
|
+
|
|
13
|
+
1. Use the ToolNet Memory MCP server as the continuity source.
|
|
14
|
+
2. Invoke \`memory_agent_ask\` before exploring old history if the current
|
|
15
|
+
ToolNet handoff is missing, stale, or ambiguous.
|
|
16
|
+
3. Prefer \`mode="local"\` for current task, last file, blocker, completed
|
|
17
|
+
work, TODOs, and next action.
|
|
18
|
+
4. Use \`mode="ai"\` only when continuity requires synthesis.
|
|
19
|
+
5. Do not reconstruct previous work from:
|
|
20
|
+
- \`.toolnet/sessions/**\`
|
|
21
|
+
- ToolNet \`events.jsonl\` or \`state.json\`
|
|
22
|
+
- raw transcripts
|
|
23
|
+
- another coding agent's private session/history files
|
|
24
|
+
6. After ToolNet continuity is known, verify current git and repository
|
|
25
|
+
source truth before changing code.
|
|
26
|
+
7. Do not ask the user to repeat context ToolNet already provides.
|
|
27
|
+
|
|
28
|
+
Current repository evidence overrides stale memory.
|
|
29
|
+
`;function Ko(o,r){Uo(Vo(o),{recursive:!0,mode:448});let n=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{Yo(n,r,{encoding:"utf8",mode:384}),Bo(n,o)}finally{Wo(n,{force:!0})}}function so(o={}){let r=o.skillFile??M();if(Do(r)&&io(r,"utf8")===D)return{skillFile:r,changed:!1};if(Ko(r,D),io(r,"utf8")!==D)throw new Error("Grok ToolNet continuity skill was written but verification failed.");return{skillFile:r,changed:!0}}var v=[["SessionStart",10],["UserPromptSubmit",10],["PreToolUse",10],["PostToolUse",15],["Stop",30]];function co(o){return!f(o)||!Array.isArray(o.hooks)?!1:o.hooks.some(r=>f(r)&&typeof r.command=="string"&&r.command.includes("session:grok-hook"))}function qo(o,r,n){let t={hooks:[{type:"command",command:`${r} session:grok-hook`,timeout:n,env:{TOOLNET_HOOK_EVENT:o}}]};return o==="PreToolUse"&&(t.matcher=".*"),t}function lo(o={}){let r=o.hooksFile??J(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=k(r,"Grok Build"),e=t.hooks;if(e!==void 0&&!f(e))throw new Error("Invalid existing Grok Build hooks file: hooks must be an object.");let s=f(e)?{...e}:{};for(let[l,c]of v){let a=s[l];if(a!==void 0&&!Array.isArray(a))throw new Error(`Invalid existing Grok Build hooks file: hooks.${l} must be an array.`);let m=Array.isArray(a)?a.filter(p=>!co(p)):[];s[l]=[...m,qo(l,n,c)]}let i={...t,hooks:s};if(JSON.stringify(t)===JSON.stringify(i))return{hooksFile:r,changed:!1,hookCount:v.length};C(r,i);let u=k(r,"Grok Build");if(!f(u.hooks))throw new Error("Grok Build hooks were written but verification failed.");let g=0;for(let[l]of v){let c=u.hooks[l];if(!Array.isArray(c))throw new Error("Grok Build hooks were written but verification failed.");g+=c.filter(co).length}if(g!==v.length)throw new Error("Grok Build hooks were written but verification failed.");return{hooksFile:r,changed:!0,hookCount:v.length}}import{existsSync as zo,mkdirSync as Qo,readFileSync as Xo,renameSync as Zo,rmSync as or,writeFileSync as rr}from"node:fs";import{dirname as nr}from"node:path";function ao(o){return zo(o)?Xo(o,"utf8"):""}function tr(o,r){Qo(nr(o),{recursive:!0,mode:448});let n=`${o}.tmp-${process.pid}-${Date.now()}`;try{rr(n,r,{encoding:"utf8",mode:384}),Zo(n,o)}finally{or(n,{force:!0})}}function U(o){return o.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}function er(o){return`[mcp_servers."${U(o)}"]`}function ir(o,r){return[er(o),`command = "${U(r)}"`,'args = ["mcp"]',"enabled = true"].join(`
|
|
30
|
+
`)}function sr(o){let r=o.trim();return r.startsWith("[")&&r.includes("]")}function G(o){return o.trim().replace(/\s+/g,"")}function cr(o){return new Set([G(`[mcp_servers.${o}]`),G(`[mcp_servers."${o}"]`),G(`[mcp_servers.'${o}']`)])}function go(o,r){let n=o.split(/\r?\n/),t=cr(r),e=-1;for(let c=0;c<n.length;c+=1){let a=G(n[c].replace(/\s+#.*$/,""));if(t.has(a)){e=c;break}}if(e<0)return null;let s=n.length;for(let c=e+1;c<n.length;c+=1)if(sr(n[c])){s=c;break}let i=[],u=0;for(let c of n)i.push(u),u+=c.length+1;let g=i[e]??0,l=s>=n.length?o.length:i[s]??o.length;return{start:g,end:l}}function lr(o,r,n){let t=`${ir(r,n)}
|
|
31
|
+
`,e=go(o,r);if(e){let s=o.slice(0,e.start),i=o.slice(e.end);return`${s}${t}${i.replace(/^\n+/,"")}`}return o.trim()?`${o.replace(/\s*$/,"")}
|
|
32
|
+
|
|
33
|
+
${t}`:t}function uo(o,r,n){let t=go(o,r);if(!t)return!1;let e=o.slice(t.start,t.end);return e.includes(`command = "${U(n)}"`)&&/args\s*=\s*\[\s*"mcp"\s*\]/.test(e)&&/enabled\s*=\s*true/.test(e)}function fo(o={}){let r=o.configFile??$(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.serverName??"toolnet-memory",e=ao(r);if(uo(e,t,n))return{installed:!0,changed:!1,configFile:r,serverName:t,command:n,args:["mcp"]};let s=lr(e,t,n);tr(r,s);let i=ao(r);if(!uo(i,t,n))throw new Error("Grok Build MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:r,serverName:t,command:n,args:["mcp"]}}function mo(o={}){let r=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=fo({binary:r,configFile:o.configFile}),t=lo({binary:r,hooksFile:o.hooksFile}),e=so({skillFile:o.skillFile});return{installed:n.installed,changed:n.changed||t.changed||e.changed,mcp:n,hooks:t,skill:e,files:[n.configFile,t.hooksFile,e.skillFile]}}import{existsSync as O,readFileSync as W}from"node:fs";function h(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function x(o){if(!O(o))return{};try{let r=JSON.parse(W(o,"utf8"));return h(r)?{value:r}:{error:"root must be a JSON object"}}catch(r){return{error:r instanceof Error?r.message:String(r)}}}function po(o,r){if(!o||!h(o.mcpServers))return!1;let n=o.mcpServers["toolnet-memory"];return!h(n)||typeof n.command!="string"||!n.command.trim()||!Array.isArray(n.args)||n.args.length!==1||n.args[0]!=="mcp"?!1:!r||Array.isArray(n.tools)&&n.tools.includes("*")}function ko(o,r,n){if(!o||!h(o.hooks))return[];let t=o.hooks;return r.filter(e=>{let s=t[e];return Array.isArray(s)&&s.some(i=>h(i)&&(typeof i.command=="string"&&i.command.includes(n)||typeof i.bash=="string"&&i.bash.includes(n)))})}function ar(o,r){if(!o||!h(o.hooks))return[];let n=o.hooks;return r.filter(t=>{let e=n[t];return Array.isArray(e)&&e.some(s=>!h(s)||!Array.isArray(s.hooks)?!1:s.hooks.some(i=>h(i)&&typeof i.command=="string"&&i.command.includes("session:grok-hook")))})}function ur(o){if(!O(o))return!1;let r=W(o,"utf8"),n=/\[mcp_servers\.(?:"toolnet-memory"|'toolnet-memory'|toolnet-memory)\]/,t=r.search(n);if(t<0)return!1;let e=r.slice(t),s=e.slice(1).search(/\n\s*\[[^\]]+\]/),i=s>=0?e.slice(0,s+1):e;return/command\s*=\s*"[^"]+"/.test(i)&&/args\s*=\s*\[\s*"mcp"\s*\]/.test(i)&&!/enabled\s*=\s*false/.test(i)}function B(o){let r=[];o.mcpError&&r.push(`MCP config: ${o.mcpError}`),o.hookError&&r.push(`Hooks config: ${o.hookError}`);let n=o.mcpConfigured&&o.hooksConfigured&&(o.skill?.configured??!0),t=O(o.configFile)||O(o.hooksFile)||(o.skill?O(o.skill.skillFile):!1),e=r.length>0?"invalid":n?"ready":t?"partial":"not-installed";return{installed:n,state:e,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:r}}function Y(o,r={}){if(o==="cursor"){let l=["sessionStart","beforeSubmitPrompt","preToolUse","postToolUse","afterAgentResponse","stop"],c=r.configFile??I(),a=r.hooksFile??E(),m=x(c),p=x(a),w=p.error?[]:ko(p.value,l,"session:cursor-hook");return B({mcpConfigured:!m.error&&po(m.value,!1),configFile:c,mcpError:m.error,hooksConfigured:l.every(P=>w.includes(P)),hooksFile:a,events:w,hookError:p.error})}if(o==="copilot"){let l=["sessionStart","userPromptSubmitted","userPromptTransformed","preToolUse","postToolUse","agentStop"],c=r.configFile??j(),a=r.hooksFile??T(),m=x(c),p=x(a),w=p.error?[]:ko(p.value,l,"session:copilot-hook");return B({mcpConfigured:!m.error&&po(m.value,!0),configFile:c,mcpError:m.error,hooksConfigured:l.every(P=>w.includes(P)),hooksFile:a,events:w,hookError:p.error})}let n=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"],t=r.configFile??$(),e=r.hooksFile??J(),s=r.skillFile??M(),i=x(e),u=i.error?[]:ar(i.value,n),g=O(s)&&W(s,"utf8").includes("memory_agent_ask");return B({mcpConfigured:ur(t),configFile:t,hooksConfigured:n.every(l=>u.includes(l)),hooksFile:e,events:u,hookError:i.error,skill:{configured:g,skillFile:s}})}var A={cursor:"Cursor CLI",copilot:"GitHub Copilot CLI",grok:"Grok Build"};function ho(o){let r=process.argv.slice(2),n=r.includes("--json");if(r.includes("--status")||r[0]==="status"){let i=Y(o);if(n)console.log(JSON.stringify(i,null,2));else{console.log(`${A[o]} Integration`),console.log("=".repeat(`${A[o]} Integration`.length)),console.log(""),console.log(`State : ${i.state}`),console.log(`MCP : ${i.mcp.configured?"ready":"missing"} \u2014 ${i.mcp.configFile}`),console.log(`Hooks : ${i.hooks.configured?"ready":"missing"} \u2014 ${i.hooks.hooksFile}`),i.skill&&console.log(`Skill : ${i.skill.configured?"ready":"missing"} \u2014 ${i.skill.skillFile}`),i.hooks.events.length>0&&console.log(`Events: ${i.hooks.events.join(", ")}`);for(let u of i.errors)console.log(`Error : ${u}`);console.log("")}i.installed||(process.exitCode=1);return}let e=o==="cursor"?X():o==="copilot"?eo():mo(),s=Y(o);if(!s.installed)throw new Error(`${A[o]} integration installation did not verify successfully (state=${s.state}).`);if(n){console.log(JSON.stringify({installed:!0,changed:e.changed,files:e.files,status:s},null,2));return}console.log(`\u2705 ${A[o]} integration installed`),console.log(`MCP: ${e.mcp.configFile}`),console.log(`Hooks: ${e.hooks.hooksFile}`),s.skill&&console.log(`Skill: ${s.skill.skillFile}`),console.log("Server: toolnet-memory")}try{ho("cursor")}catch(o){console.error(o instanceof Error?o.message:String(o)),process.exitCode=1}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import*as ee from"fs";import*as q from"path";function fs(e){return e?Math.ceil(e.length/3.5):0}function Dt(e,t){if(!e)return"";if(fs(e)<=t)return e;let r=Math.floor(t*3.5),s=e.slice(0,r),o=s.lastIndexOf("."),i=s.lastIndexOf(`
|
|
2
|
+
`),a=Math.max(o,i);return a>r*.7?s.slice(0,a+1):s}import{createHash as gs}from"node:crypto";import{chmodSync as qt,existsSync as ys,mkdirSync as hs,readFileSync as Ss,renameSync as ks,writeFileSync as Ht}from"node:fs";import{dirname as Vt,join as Ae}from"node:path";var dt="toolnet.context-offload.v1",ws="toolnet.context-offload-asset.v1",vs=256,bs=new Set(["tool_call","tool_result","file_read","file_write","file_edit","command","test","artifact"]);function Jt(e){return Ae(e,".toolnet","offload")}function xs(e){return Ae(Jt(e),"assets")}function Bt(e){return Ae(Jt(e),"graph.json")}function Gt(e){hs(e,{recursive:!0,mode:448});try{qt(e,448)}catch{}}function js(e,t){Gt(Vt(e));let n=`${e}.${process.pid}.${Date.now()}.tmp`;Ht(n,t,{encoding:"utf8",mode:384}),ks(n,e);try{qt(e,384)}catch{}}function lt(e){return Array.isArray(e)?e.map(lt):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>[t,lt(n)])):e}function As(e){return gs("sha256").update(JSON.stringify(lt(e)),"utf8").digest("hex")}function ut(){return{schema:dt,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function Is(e){let t=Bt(e);if(!ys(t))return ut();try{let n=JSON.parse(Ss(t,"utf8"));return n.schema!==dt||n.version!==1||!Array.isArray(n.nodes)?ut():n}catch{return ut()}}function Cs(e,t){js(Bt(e),JSON.stringify(t,null,2)+`
|
|
3
|
+
`)}function Ps(e,t=260){if(typeof e!="string")return null;let n=e.replace(/\s+/gu," ").trim();return n?n.slice(0,t):null}function Ms(e){let t=[...e.provenance.files??[],e.provenance.sourcePath],n=[];for(let r of t){let s=Ps(r);if(!(!s||n.includes(s))&&(n.push(s),n.length===3))break}return n}function Es(e){return`${e.agent}:${e.sourceEventId??e.id}`.replace(/\s+/gu," ").trim().slice(0,120)}function Ts(e,t){Gt(Vt(e));try{return Ht(e,t,{encoding:"utf8",flag:"wx",mode:384}),!0}catch(n){if(n.code==="EEXIST")return!1;throw n}}function Os(e,t){let n=e.nodes.find(s=>s.id===t.id),r=n?{...n,kind:t.kind,bytes:t.bytes,sourceRefs:Array.from(new Set([...n.sourceRefs,...t.sourceRefs])).slice(-8),files:Array.from(new Set([...n.files,...t.files])).slice(0,6)}:t;return{schema:dt,version:1,updatedAt:new Date().toISOString(),nodes:[...e.nodes.filter(s=>s.id!==t.id),r].slice(-vs)}}function Ut(e,t){let n=Is(e),r=0,s=0,o=0,i=[];for(let a of t){if(!bs.has(a.type))continue;r+=1;let c=As({type:a.type,data:a.data}),u={schema:ws,version:1,assetId:c,event:{type:a.type,agent:a.agent,nativeSessionId:a.nativeSessionId,timestamp:a.timestamp,sourceEventId:a.sourceEventId,provenance:a.provenance,data:a.data}},f=JSON.stringify(u,null,2)+`
|
|
4
|
+
`;Ts(Ae(xs(e),`${c}.json`),f)?s+=1:o+=1,i.push(c),n=Os(n,{id:c,kind:a.type,bytes:Buffer.byteLength(f,"utf8"),createdAt:a.timestamp,sourceRefs:[Es(a)],files:Ms(a)})}return r>0&&Cs(e,n),{eligible:r,written:s,deduped:o,graphNodes:n.nodes.length,assetIds:i}}import{existsSync as Xt,mkdirSync as Fs,readFileSync as Qt,renameSync as Ls,writeFileSync as zs}from"node:fs";import{dirname as Ds,join as Zt}from"node:path";import{createHash as Rs}from"node:crypto";import{dirname as Ns}from"node:path";import{mkdirSync as _s,readFileSync as Ks,renameSync as $s,writeFileSync as Ws}from"node:fs";function w(e){return Rs("sha256").update(e).digest("hex")}function pt(e){if(Array.isArray(e))return e.map(pt);if(e&&typeof e=="object"){let t=e,n={};for(let r of Object.keys(t).sort())n[r]=pt(t[r]);return n}return e}function Ie(e){return JSON.stringify(pt(e))}function Yt(e){try{return JSON.parse(Ks(e,"utf8"))}catch{return null}}function T(e,t){_s(Ns(e),{recursive:!0});let n=`${e}.${process.pid}.tmp`;Ws(n,JSON.stringify(t,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),$s(n,e)}function en(e){return Zt(e.rootPath,".toolnet","context","handoff.md")}function tn(e){return Zt(e.rootPath,".toolnet","context","handoff.json")}function nn(e,t){Fs(Ds(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;zs(n,t.endsWith(`
|
|
6
|
+
`)?t:`${t}
|
|
7
|
+
`,{encoding:"utf8",mode:384}),Ls(n,e)}function qs(e,t){nn(e,`${JSON.stringify(t,null,2)}
|
|
8
|
+
`)}function rn(e,t){let n=t.replace(/\r\n/g,`
|
|
9
|
+
`).trim();if(!n)return null;let r={version:1,projectId:e.id,projectName:e.name,text:n,digest:w(n),generatedAt:new Date().toISOString()};return nn(en(e),n),qs(tn(e),r),r}function sn(e){let t=en(e);if(!Xt(t))return null;try{let n=Qt(t,"utf8").trim();if(!n)return null;let r=new Date(0).toISOString(),s=tn(e);if(Xt(s))try{let o=JSON.parse(Qt(s,"utf8"));typeof o.generatedAt=="string"&&(r=o.generatedAt)}catch{}return{version:1,projectId:e.id,projectName:e.name,text:n,digest:w(n),generatedAt:r}}catch{return null}}function on(e){let t=q.resolve(e),n=q.parse(t).root;for(;t!==n;){let r=q.join(t,".toolnet");if(ee.existsSync(r)&&ee.statSync(r).isDirectory())return t;t=q.dirname(t)}return null}function an(e){return e.replace(/\\/g,"/").toLowerCase()}function mt(e,t,n=0){if(!(n>6||t.length>=250)){if(typeof e=="string"){t.push(e);return}if(Array.isArray(e)){for(let r of e)if(mt(r,t,n+1),t.length>=250)break;return}if(e&&typeof e=="object"){for(let r of Object.values(e))if(mt(r,t,n+1),t.length>=250)break}}}function Hs(e){let t=an(e);if(t.includes(".toolnet/sessions/")||t.endsWith(".toolnet/sessions")||t.includes(".gemini/antigravity-cli/brain/")||t.endsWith(".gemini/antigravity-cli/brain")||t.includes("/transcript.jsonl")||t.endsWith("transcript.jsonl")||t.includes(".toolnet/")&&(t.endsWith("/events.jsonl")||t.endsWith("/state.json")||t.includes("/sessions/")))return!0;let n=process.env.CURSOR_TRANSCRIPT_PATH;return!!(n&&an(n)===t)}function cn(e){let t=[];return mt(e,t),t.find(Hs)?{blocked:!0,reason:"ToolNet continuity guard: do not read or reconstruct previous work from raw ToolNet/agent session history. Use the injected ToolNet handoff first; if it is insufficient, invoke the MCP tool memory_agent_ask directly. Then verify normal repository/git source truth."}:{blocked:!1}}function Ce(e){return typeof e=="string"&&e.trim()?e.trim():void 0}function un(e,t=process.env){return Ce(t.TOOLNET_HOOK_EVENT)??Ce(e.hookEventName)??Ce(e.hook_event_name)??Ce(t.GROK_HOOK_EVENT)??""}function ln(e){return cn(e.toolInput??e.tool_input??e)}function dn(e){return{decision:"deny",reason:e}}import{existsSync as uu}from"node:fs";import{join as lu}from"node:path";import{existsSync as Vs,readFileSync as Js}from"node:fs";import{homedir as Bs}from"node:os";import{join as Gs}from"node:path";function Us(e){let t=e.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
|
|
10
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function Ys(){let e=process.env.TOOLNET_GLOBAL_ENV??Gs(Bs(),".config","toolnet-memory",".env");if(!Vs(e))return;let t=Js(e,"utf8");for(let n of t.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Us(r.slice(s+1)))}}Ys();function ae(e,t){return e===void 0?t:["1","true","yes","on"].includes(e.toLowerCase())}function ce(e,t){if(!e)return t;let n=Number(e);return Number.isFinite(n)?n:t}function Pe(){return{memory:{autoCapture:ae(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:ae(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:ae(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:ae(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:ce(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:ce(process.env.MEMORY_RERANK_TOP,10),finalContext:ce(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:ce(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:ae(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:ce(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Xs}from"node:crypto";import{existsSync as ft,mkdirSync as Qs,readFileSync as Zs,renameSync as eo,writeFileSync as to}from"node:fs";import{basename as no,dirname as Me,join as Te,parse as fn,resolve as ue}from"node:path";var gn=".toolnet",ro="project.json";function so(e){return Xs("sha256").update(e).digest("hex").slice(0,16)}function gt(e){return Te(e,gn,ro)}function oo(e){return ft(gt(e))}function io(e,t){let n=ue(e),r=fn(n).root;for(;;){if(oo(n))return n;if(n===r||t&&n===ue(t))break;let s=Me(n);if(s===n)break;n=s}return null}function ao(e){let t=ue(e),n=fn(t).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>ft(Te(t,o))))return t;if(t===n)break;let s=Me(t);if(s===t)break;t=s}return ue(e)}function co(e){let t;try{t=JSON.parse(Zs(e,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${e}: ${s instanceof Error?s.message:String(s)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${e}`);let n=t;if(typeof n.id!="string"||!n.id.trim())throw new Error(`ToolNet project manifest is missing id: ${e}`);if(typeof n.name!="string"||!n.name.trim())throw new Error(`ToolNet project manifest is missing name: ${e}`);let r=new Date().toISOString();return{version:1,id:n.id,name:n.name,remote:typeof n.remote=="string"&&n.remote.trim()?n.remote:n.name,rootPath:typeof n.rootPath=="string"?n.rootPath:Me(Me(e)),createdAt:typeof n.createdAt=="string"?n.createdAt:r,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:r,graphVersion:typeof n.graphVersion=="number"?n.graphVersion:0,memoryVersion:typeof n.memoryVersion=="number"?n.memoryVersion:0,metadata:n.metadata&&typeof n.metadata=="object"?n.metadata:void 0}}function pn(e,t){let n=Te(e,gn);Qs(n,{recursive:!0});let r=gt(e),s=`${r}.tmp-${process.pid}`;to(s,JSON.stringify(t,null,2)+`
|
|
11
|
+
`,{encoding:"utf8",mode:384}),eo(s,r)}function mn(e,t){return{id:e.id,name:e.name,remote:e.remote,rootPath:t,createdAt:e.createdAt,updatedAt:e.updatedAt,graphVersion:e.graphVersion,memoryVersion:e.memoryVersion,metadata:e.metadata}}var Ee=class{detect(t=process.cwd()){let n=ue(t),r=ao(n),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>ft(Te(r,f))),i=io(n,o?r:void 0);if(i){let f=gt(i),m=co(f);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),pn(i,m)),mn(m,i)}let a=new Date().toISOString(),c=no(r),u={version:1,id:so(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return pn(r,u),mn(u,r)}};var uo=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],Oe=class{scan(t){let n=[];for(let r of uo){let s=new RegExp(r.regex.source,r.regex.flags);for(let o of t.matchAll(s))n.push({type:r.type,value:o[0]})}return n}hasSecrets(t){return this.scan(t).length>0}};var B=class{scanner=new Oe;sanitize(t){let n=t,r=this.scanner.scan(t),s=new Set;for(let o of r)s.add(o.type),n=n.split(o.value).join(`[REDACTED:${o.type}]`);return{text:n,redacted:r.length,secretTypes:[...s]}}sanitizeValue(t){if(typeof t=="string")return this.sanitize(t).text;if(Array.isArray(t))return t.map(n=>this.sanitizeValue(n));if(t&&typeof t=="object"){let n={};for(let[r,s]of Object.entries(t)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")?n[r]="[REDACTED]":n[r]=this.sanitizeValue(s)}return n}return t}};import{homedir as Ro}from"node:os";import{join as No}from"node:path";import{DeleteObjectCommand as lo,GetObjectCommand as po,HeadObjectCommand as mo,ListObjectsV2Command as fo,PutObjectCommand as go,S3Client as yo}from"@aws-sdk/client-s3";import{getSignedUrl as ho}from"@aws-sdk/s3-request-presigner";var Re=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new yo({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new go({Bucket:this.bucket,Key:t,Body:s,ContentType:r}))}async get(t){let n=await ho(this.client,new po({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let n=await this.get(t);return n?Buffer.from(n).toString("utf8"):null}async exists(t){try{return await this.client.send(new mo({Bucket:this.bucket,Key:t})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(t){await this.client.send(new lo({Bucket:this.bucket,Key:t}))}async list(t=""){let n=[],r;do{let s=await this.client.send(new fo({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};import{access as yn,mkdir as So,readFile as ko,readdir as wo,rm as vo,stat as hn,writeFile as bo}from"node:fs/promises";import{dirname as xo,join as jo,relative as Sn,resolve as Ao}from"node:path";var le=class{constructor(t){this.root=t}root;name="local";path(t){let n=t.replace(/^\/+/,"");return Ao(this.root,n)}async put(t,n){let r=this.path(t);await So(xo(r),{recursive:!0}),await bo(r,n)}async get(t){try{return await ko(this.path(t))}catch(n){if(typeof n=="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return null;throw n}}async getText(t){let n=await this.get(t);return n?Buffer.from(n).toString("utf8"):null}async exists(t){try{return await yn(this.path(t)),!0}catch{return!1}}async delete(t){await vo(this.path(t),{force:!0})}async list(t=""){let n=this.path(t),r=[];try{await yn(n)}catch{return r}let s=async i=>{let a=await wo(i,{withFileTypes:!0});for(let c of a){let u=jo(i,c.name);if(c.isDirectory()){await s(u);continue}let f=await hn(u);r.push({key:Sn(this.root,u),size:f.size,updatedAt:f.mtime.toISOString()})}},o=await hn(n);return o.isDirectory()?await s(n):r.push({key:Sn(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as Io,GetObjectCommand as Co,HeadObjectCommand as Po,ListObjectsV2Command as Mo,PutObjectCommand as Eo,S3Client as To}from"@aws-sdk/client-s3";import{getSignedUrl as Oo}from"@aws-sdk/s3-request-presigner";var de=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new To({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new Eo({Bucket:this.bucket,Key:t,Body:s,ContentType:r}))}async get(t){let n=await Oo(this.client,new Co({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let n=await this.get(t);return n?Buffer.from(n).toString("utf8"):null}async exists(t){try{return await this.client.send(new Po({Bucket:this.bucket,Key:t})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(t){await this.client.send(new Io({Bucket:this.bucket,Key:t}))}async list(t=""){let n=[],r;do{let s=await this.client.send(new Mo({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};function yt(e,t){return console.warn(t),new le(e)}function kn(e){let t=e.localRoot??No(Ro(),".toolnet-memory","storage");if(e.provider==="r2"){let n=e.r2;return n?.accountId&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new de({name:"r2",endpoint:`https://${n.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:n.bucket,forcePathStyle:!0,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):yt(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(e.provider==="s3"){let n=e.s3;return n?.bucket&&n.accessKeyId&&n.secretAccessKey?new de({name:"s3",endpoint:n.endpoint,region:n.region??"us-east-1",bucket:n.bucket,forcePathStyle:n.forcePathStyle??!1,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):yt(t,"[storage] S3 credentials missing. Using local fallback.")}if(e.provider==="huggingface"){let n=e.huggingface;return n?.namespace&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new Re({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):yt(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new le(t)}function _o(e){return new Promise(t=>setTimeout(t,e))}async function wn(e,t={}){let n=Math.max(1,t.attempts??3),r=t.baseDelayMs??150,s=t.maxDelayMs??2e3,o;for(let i=1;i<=n;i++)try{return await e()}catch(a){if(o=a,i>=n)break;let c=Math.min(s,r*2**(i-1)),u=Math.floor(Math.random()*Math.max(1,c*.2));await _o(c+u)}throw o}var Ko=new Set(["put","get","getText","delete","list"]);function vn(e,t={}){return new Proxy(e,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:Ko.has(r)?(...o)=>wn(()=>Promise.resolve(s.apply(n,o)),t):s.bind(n)}})}function bn(e){let t=e.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function xn(e){let t=e.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let n=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:t))}var Ne=class{constructor(t,n,r,s){this.provider=t;this.name=t.name,this.projectId=n,this.projectName=r,this.folder=bn(s??r),this.sourcePrefix=`projects/${n}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,n=new Date().toISOString(),r=n,s=await this.provider.getText(t);if(s){let i;try{i=JSON.parse(s)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${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"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:n};await this.provider.put(t,JSON.stringify(o,null,2)+`
|
|
12
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=xn(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,n,r){return await this.ensureRegistered(),this.provider.put(this.key(t),n,r)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};import{existsSync as Jo,readFileSync as Bo}from"node:fs";import{join as Go}from"node:path";import{existsSync as $o,mkdirSync as Wo,readFileSync as Fo,renameSync as Lo,writeFileSync as zo}from"node:fs";import{dirname as Do,join as qo}from"node:path";function jn(e){return qo(e.rootPath,".toolnet","context","session-origin.json")}function Ho(e,t){Wo(Do(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;zo(n,`${JSON.stringify(t,null,2)}
|
|
13
|
+
`,{encoding:"utf8",mode:384}),Lo(n,e)}function _e(e,t){return[...e].filter(n=>n.kind===t).sort((n,r)=>{let s=n.occurredAt.localeCompare(r.occurredAt);return s!==0?s:n.sequence-r.sequence}).at(-1)}function An(e,t){let n=_e(t.observations,"file"),r=_e(t.observations,"next_action"),s=_e(t.observations,"blocker"),o=_e(t.observations,"decision"),i={version:1,projectId:e.id,agent:t.agent,nativeSessionId:t.nativeSessionId,updatedAt:t.workState.updatedAt,currentRequest:t.workState.currentRequest,currentActivity:t.workState.currentActivity,currentTask:t.workState.currentTask?.title,currentPhase:t.workState.currentPhase?.title,lastTouchedFile:n?.text??t.workState.activeFiles?.at(-1)??t.workState.filesTouched.at(-1),latestNextAction:r?.text??t.workState.nextActions.at(-1),latestBlocker:s?.text??t.workState.blockers.at(-1),latestDecision:o?.text??t.workState.decisions.at(-1)};return Ho(jn(e),i),i}function Vo(e){let t=jn(e);if(!$o(t))return null;try{let n=JSON.parse(Fo(t,"utf8"));return n.version!==1||n.projectId!==e.id?null:n}catch{return null}}function In(e){let t=Vo(e);if(!t)return null;let n=["Previous session:",`- Agent: ${t.agent}`,`- Session: ${t.nativeSessionId}`];return t.currentRequest&&n.push(`- Current request: ${t.currentRequest}`),t.currentActivity&&n.push(`- Current activity: ${t.currentActivity}`),t.currentPhase&&n.push(`- Current phase: ${t.currentPhase}`),t.currentTask&&n.push(`- Current task: ${t.currentTask}`),t.lastTouchedFile&&n.push(`- Last touched file: ${t.lastTouchedFile}`),t.latestBlocker&&n.push(`- Blocker: ${t.latestBlocker}`),t.latestNextAction&&n.push(`- Next action: ${t.latestNextAction}`),t.latestDecision&&n.push(`- Important decision: ${t.latestDecision}`),n.join(`
|
|
14
|
+
`)}function Uo(e){let t=Go(e.rootPath,".toolnet","current.md");if(!Jo(t))return null;try{return Bo(t,"utf8").trim()}catch{return null}}function Yo(e,t){let n=t.replace(/\r\n/g,`
|
|
15
|
+
`).trim(),r=2400,s=n.length>r?`${n.slice(0,r)}
|
|
16
|
+
|
|
17
|
+
[Current work truncated for fast handoff]`:n,o=In(e);return["# ToolNet Fast Handoff","",`Project: ${e.name}`,"",...o?[o,""]:[],s,"","---","","Continuation rule:","- Continue unfinished work; do not redo completed steps.","- Query ToolNet Memory only when deeper history is needed."].join(`
|
|
18
|
+
`)}function Cn(e){let t=Uo(e);if(t===null)return{updated:!1,reason:"missing-current",chars:0};if(!t.trim())return{updated:!1,reason:"empty-current",chars:0};let n=Yo(e,t);return sn(e)?.text.trim()===n.trim()?{updated:!1,reason:"unchanged",chars:n.length}:(rn(e,n),{updated:!0,reason:"updated",chars:n.length})}import{join as Xo}from"node:path";function Pn(e,t){let n=e.trim(),r=n.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=w(n).slice(0,12);if(!r||r==="."||r==="..")return`${t}--${s}`;let o=r.slice(0,100);return o===n&&n.length<=100?o:`${o.slice(0,85)}--${s}`}function Ke(e,t,n){let r=t.trim(),s=n.trim();if(!r)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let o=Pn(r.toLowerCase(),"agent"),i=Pn(s,"session");return{projectId:e.id,projectName:e.name,projectRoot:e.rootPath,agent:r,nativeSessionId:s,sessionKey:`${r}:${s}`,remotePrefix:["projects",e.id,"sessions",o,i].join("/"),localDirectory:Xo(e.rootPath,".toolnet","sessions",o,i)}}function Mn(e){return String(e).padStart(12,"0")}var $e=class{constructor(t,n=100,r=512*1024){this.storage=t;this.maxEventsPerChunk=n;this.maxChunkBytes=r;if(n<1)throw new Error("maxEventsPerChunk must be positive");if(r<1024)throw new Error("maxChunkBytes is too small")}storage;maxEventsPerChunk;maxChunkBytes;async getJson(t){let n=await this.storage.getText(t);return n?JSON.parse(n):null}async putJson(t,n){await this.storage.put(t,JSON.stringify(n,null,2)+`
|
|
19
|
+
`,"application/json")}async scan(t){let n=`${t.remotePrefix}/events/`,r=await this.storage.list(n),s=[],o=0;for(let i of r){let a=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!a)continue;let c=Number(a[1]),u=Number(a[2]);!Number.isFinite(c)||!Number.isFinite(u)||(s.push({key:i.key,start:c,end:u}),o=Math.max(o,u))}return s.sort((i,a)=>i.start-a.start),{chunks:s,maxSequence:o}}split(t){let n=[],r=[],s=0;for(let o of t){let i=Buffer.byteLength(JSON.stringify(o)+`
|
|
20
|
+
`,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(t){return this.getJson(`${t.remotePrefix}/session.json`)}async loadCursor(t){return this.getJson(`${t.remotePrefix}/cursor.json`)}async recover(t){let n=await this.scan(t);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(t,n,r,s={}){let o=await this.loadManifest(t),i=await this.scan(t),a=n.filter(y=>y.sequence>i.maxSequence),c=0;for(let y of this.split(a)){let h=y[0],k=y[y.length-1],C=y.map(E=>JSON.stringify(E)).join(`
|
|
21
|
+
`)+`
|
|
22
|
+
`,M=w(C).slice(0,16),I=[t.remotePrefix,"events",`${Mn(h.sequence)}-${Mn(k.sequence)}-${M}.jsonl`].join("/");await this.storage.exists(I)||await this.storage.put(I,C,"application/x-ndjson"),c+=y.length}let u=await this.scan(t),f=n[n.length-1],m=o?.status??"active";f?.type==="session_end"||f?.type==="session_idle"?m="idle":f?.type==="error"?m="error":n.length>0&&(m="active");let d=new Date().toISOString(),l=n[0],g={version:1,projectId:t.projectId,projectName:t.projectName,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,status:m,createdAt:o?.createdAt??l?.timestamp??d,updatedAt:f?.timestamp??d,firstEventAt:o?.firstEventAt??l?.timestamp,lastEventAt:f?.timestamp??o?.lastEventAt,eventCount:u.maxSequence,chunkCount:u.chunks.length,metadata:{...o?.metadata,...s.metadata}};(s.title??o?.title)&&(g.title=s.title??o?.title);let S={version:1,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,lastLocalSequence:n.length>0?n[n.length-1].sequence:u.maxSequence,lastRemoteSequence:u.maxSequence,sourceCursors:r,updatedAt:d};return await this.putJson(`${t.remotePrefix}/cursor.json`,S),await this.putJson(`${t.remotePrefix}/session.json`,g),{uploadedEvents:c,lastRemoteSequence:u.maxSequence,eventCount:g.eventCount,chunkCount:g.chunkCount,status:m}}};import{closeSync as St,existsSync as ri,fsyncSync as si,mkdirSync as oi,openSync as kt,readSync as ii,rmSync as Tn,statSync as On,writeSync as ai}from"node:fs";import{join as wt}from"node:path";var Qo=new Set(["thinking","reasoning","reasoningcontent","chainofthought","cot","analysistext","internalreasoning","modelthinking"]),Zo=new Set(["reasoning","thinking","chain_of_thought","chain-of-thought","internal_reasoning","internal-reasoning"]);function ei(e){return e.toLowerCase().replace(/[^a-z0-9]+/gu,"")}function ti(e){for(let t of["type","kind"]){let n=e[t];if(typeof n=="string"){let r=n.toLowerCase();if(Zo.has(r))return n}}return null}function ht(e,t=0){if(t>12)return"[ToolNet nested value omitted]";if(Array.isArray(e))return e.map(o=>ht(o,t+1));if(!e||typeof e!="object")return e;let n=e,r=ti(n);if(r)return{type:r,omitted:"[private reasoning omitted]"};let s={};for(let[o,i]of Object.entries(n))Qo.has(ei(o))||(s[o]=ht(i,t+1));return s}function ni(e){if(!e)return new Date().toISOString();let t=new Date(e);return Number.isNaN(t.getTime())?new Date().toISOString():t.toISOString()}function G(e){return e?.trim()||void 0}function En(e,t={}){let n={...e.provenance??{}},r=G(e.source)??G(t.source)??G(n.source);return{...e,timestamp:ni(e.timestamp),source:r,turnId:G(e.turnId)??G(t.turnId),cwd:G(e.cwd)??G(t.cwd),data:ht(e.data??{}),provenance:n}}var ci=12e4,ui=80,li=2e3;function di(e){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,e)}var te=class{constructor(t,n={}){this.identity=t;this.eventContext=n;oi(t.localDirectory,{recursive:!0}),this.eventsFile=wt(t.localDirectory,"events.jsonl"),this.stateFile=wt(t.localDirectory,"state.json"),this.lockFile=wt(t.localDirectory,"journal.lock")}identity;eventContext;eventsFile;stateFile;lockFile;initialState(){let t=new Date().toISOString();return{version:1,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,status:"idle",createdAt:t,updatedAt:t,lastSequence:0,lastRemoteSequence:0,remoteByteOffset:0,sourceCursors:{},recentEventIds:[]}}loadStateUnsafe(){return Yt(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(t){T(this.stateFile,t)}acquireLock(){for(let t=0;t<ui;t+=1)try{return kt(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-On(this.lockFile).mtimeMs>ci){Tn(this.lockFile,{force:!0});continue}}catch{}di(25)}throw new Error(`Session journal is locked: ${this.lockFile}`)}withLock(t){let n=this.acquireLock();try{return t()}finally{St(n),Tn(this.lockFile,{force:!0})}}append(t){return t.length===0?[]:this.withLock(()=>{let n=this.loadStateUnsafe(),r=new Set(n.recentEventIds),s=n.lastSequence,o=[];for(let m of t){let d=En(m,this.eventContext),l=d.timestamp??new Date().toISOString(),g=d.data??{},S=d.provenance?.rawDigest??w(Ie(g)),y=d.sourceEventId?[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,d.sourceEventId].join("|"):[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,s+1,d.type,l,S].join("|"),h=w(y).slice(0,32);if(r.has(h))continue;s+=1;let k={version:1,id:h,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,sessionId:this.identity.nativeSessionId,type:d.type,timestamp:l,source:d.source??d.provenance?.source??this.identity.agent,data:g,provenance:{...d.provenance,rawDigest:S}};d.role!==void 0&&(k.role=d.role),d.turnId!==void 0&&(k.turnId=d.turnId),d.cwd!==void 0&&(k.cwd=d.cwd),d.sourceEventId!==void 0&&(k.sourceEventId=d.sourceEventId),d.sourceSequence!==void 0&&(k.sourceSequence=d.sourceSequence),o.push(k),r.add(h)}if(o.length===0)return[];let i=o.map(m=>JSON.stringify(m)).join(`
|
|
23
|
+
`)+`
|
|
24
|
+
`,a=kt(this.eventsFile,"a",384);try{ai(a,i,null,"utf8"),si(a)}finally{St(a)}let c=o[o.length-1],u="active";c.type==="session_end"||c.type==="session_idle"?u="idle":c.type==="error"&&(u="error");let f=Array.from(r).slice(-li);return this.saveStateUnsafe({...n,status:u,updatedAt:c.timestamp,lastLocalEventAt:c.timestamp,lastSequence:c.sequence,recentEventIds:f}),o})}readPending(){return this.withLock(()=>{let t=this.loadStateUnsafe();if(!ri(this.eventsFile))return{events:[],startOffset:t.remoteByteOffset,endOffset:t.remoteByteOffset};let n=On(this.eventsFile).size,r=Math.min(t.remoteByteOffset,n);if(n<=r)return{events:[],startOffset:r,endOffset:n};let s=n-r,o=Buffer.alloc(s),i=kt(this.eventsFile,"r");try{ii(i,o,0,s,r)}finally{St(i)}return{events:o.toString("utf8").split(`
|
|
25
|
+
`).filter(Boolean).map(u=>JSON.parse(u)),startOffset:r,endOffset:n}})}markRemote(t,n){this.withLock(()=>{let r=this.loadStateUnsafe(),s=new Date().toISOString();this.saveStateUnsafe({...r,lastRemoteSequence:Math.max(r.lastRemoteSequence,t),remoteByteOffset:Math.max(r.remoteByteOffset,n),lastRemoteAt:s,updatedAt:s})})}setSourceCursor(t,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,sourceCursors:{...r.sourceCursors,[t]:String(n)},updatedAt:new Date().toISOString()})})}};import{closeSync as Ka,existsSync as $a,openSync as Wa,readSync as Fa,statSync as La}from"node:fs";function Rn(e,t){let n=t.toLowerCase();return n.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||n.includes("tuy\u1EC7t \u0111\u1ED1i")||n.includes("must not")||n.includes("never ")?"critical":e==="rule"||e==="decision"?"high":e==="todo"||n.includes("error")||n.includes("failed")||n.includes("exception")?"normal":"temporary"}var $n=[/không được/iu,/tuyệt đối/iu,/bắt buộc/iu,/đừng\s+/iu,/must not/iu,/do not/iu,/don't/iu,/\bnever\b/iu],pi=[/từ giờ/iu,/về sau/iu,/mỗi lần/iu,/luôn luôn/iu,/\bluôn\b/iu,/quy tắc/iu,/workflow/iu,/\balways\b/iu,/\brequired\b/iu,/\bmust\b/iu,/from now on/iu],mi=[/\bchốt\b/iu,/quyết định/iu,/sẽ dùng/iu,/chọn .+ thay/iu,/đổi sang/iu,/chuyển sang/iu,/\bdecided\b/iu,/\bchosen\b/iu,/we will use/iu,/use .+ instead/iu,/switch(?:ed)? to/iu],fi=[/\btodo\b/iu,/cần làm/iu,/cần thêm/iu,/cần sửa/iu,/cần kiểm tra/iu,/tiếp theo/iu,/bước tiếp theo/iu,/còn phải/iu,/còn cần/iu,/next step/iu,/\bneed to\b/iu,/\bremaining\b/iu,/follow[- ]?up/iu],gi=[/đã sửa/iu,/đã fix/iu,/đã khắc phục/iu,/đã xử lý/iu,/hoàn tất/iu,/hoàn thành/iu,/\bfixed\b/iu,/\bresolved\b/iu,/\bimplemented\b/iu,/\bcompleted\b/iu,/\bpasses?\b/iu],Nn=[/kiến trúc/iu,/pipeline/iu,/adapter/iu,/schema/iu,/runtime/iu,/namespace/iu,/storage/iu,/lưu trữ/iu,/workflow/iu,/session core/iu,/memory engine/iu,/retrieval/iu],yi=[/\bdùng\b/iu,/\btách\b/iu,/\bthay\b/iu,/\bchuyển\b/iu,/\blưu\b/iu,/\bmap\b/iu,/\buse\b/iu,/\bsplit\b/iu,/\bstore\b/iu,/\breplace\b/iu,/\bmove\b/iu],hi=[/đường dẫn/iu,/\bpath\b/iu,/\bport\b/iu,/\bendpoint\b/iu,/\bdomain\b/iu,/\bbucket\b/iu,/\brepository\b/iu,/\brepo\b/iu,/\bbranch\b/iu,/\/[A-Za-z0-9._/-]{4,}/u],Si=[/\blà\b/iu,/\bở\b/iu,/\bdùng\b/iu,/\bnằm\b/iu,/\bis\b/iu,/\buse\b/iu,/located/iu,/runs on/iu],_n=new Set(["content","text","message","prompt","summary","description","reason","title","last_assistant_message","lastAssistantMessage","input_messages","inputMessages"]),ki=new Set(["payload","data","content","message","messages","parts","summary"]);function O(e,t){return t.some(n=>n.test(e))}function Wn(e){return e.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function wi(e){return Wn(e).toLowerCase().replace(/[^\p{L}\p{N}:/._-]+/gu," ").replace(/\s+/g," ").trim()}function vi(e){return!(e.length<12||e.length>1e3||(e.match(new RegExp("\\p{L}","gu"))??[]).length<6||/^(?:https?:\/\/\S+|[A-Za-z0-9+/=]{80,})$/u.test(e))}function vt(e,t,n,r=0){if(!(r>6)){if(typeof e=="string"){(!t||_n.has(t))&&n.push(e);return}if(Array.isArray(e)){for(let s of e.slice(0,50))vt(s,t,n,r+1);return}if(!(!e||typeof e!="object"))for(let[s,o]of Object.entries(e))(_n.has(s)||ki.has(s))&&vt(o,s,n,r+1)}}function bi(e){let t=[];vt(e.data,void 0,t);let n=[],r=new Set;for(let s of t)for(let o of s.split(/\n+|(?<=[.!?])\s+/u)){let i=Wn(o);if(vi(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function Kn(e){return(e.role??(typeof e.data.role=="string"?e.data.role:"")).toLowerCase()}function xi(e,t,n){if(n.type==="decision")return{kind:"decision",confidence:1};if(n.type==="todo")return{kind:"todo",confidence:1};let r=t==="user"||n.type==="user_prompt",s=t==="assistant"||n.type==="assistant_message";return r&&O(e,$n)?{kind:"rule",confidence:.98}:r&&O(e,pi)?{kind:"rule",confidence:.92}:O(e,mi)?{kind:O(e,Nn)?"architecture":"decision",confidence:r?.93:.86}:r&&O(e,fi)?{kind:"todo",confidence:.87}:O(e,Nn)&&O(e,yi)?{kind:"architecture",confidence:r?.88:.82}:s&&O(e,gi)?{kind:"fix",confidence:.8}:r&&O(e,hi)&&O(e,Si)?{kind:"context",confidence:.79}:null}function ji(e){switch(e){case"rule":return"rule";case"decision":case"architecture":return"decision";case"todo":return"todo";case"fix":case"context":return"code"}}function Ai(e,t,n){return e==="rule"&&O(n,$n)?"critical":e==="architecture"||e==="decision"||e==="rule"?"high":e==="fix"||e==="context"?"normal":Rn(t,n)}function Fn(e,t){let n=[],r=new Set,s=new Map;for(let o of t){let i=typeof o.data.messageId=="string"?o.data.messageId:void 0,a=Kn(o);i&&a&&s.set(i,a)}for(let o of t){let i=Kn(o),a=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&a&&(i=s.get(a)??"");for(let c of bi(o)){let u=xi(c,i,o);if(!u||u.confidence<.75)continue;let f=ji(u.kind),m=wi(c),d=w([e.projectId,u.kind,m].join("|"));if(r.has(d))continue;r.add(d);let l=o.provenance.sourcePath?[o.provenance.sourcePath]:[],g=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:d,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,kind:u.kind,type:f,content:c,confidence:u.confidence,importance:Ai(u.kind,f,c),tags:[f],provenance:{agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,eventIds:[o.id],sourceEventIds:g,sourcePaths:l,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}import{createHash as Ii}from"node:crypto";var Ci=["project-knowledge","implementation","continuation","session-context"],Pi={"project-knowledge":"Project knowledge",implementation:"Implementation state",continuation:"Work continuation","session-context":"Session context"};function bt(e){return Ii("sha256").update(e).digest("hex")}function We(e,t){return`${e}:${bt(t).slice(0,24)}`}function Mi(e){try{return bt(JSON.stringify(e))}catch{return bt(String(e))}}function U(e){let t=new Set,n=[];for(let r of e){let s=r?.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();t.has(o)||(t.add(o),n.push(s))}return n}function zn(e,t=420){let n=e.replace(/\s+/gu," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-1)).trimEnd()}\u2026`}function Ei(e){return e==="rule"||e==="architecture"?"project-knowledge":e==="decision"||e==="fix"?"implementation":e==="todo"?"continuation":"session-context"}function Ln(e){return e.length===0?0:e.reduce((t,n)=>t+n,0)/e.length}function Ti(e){return e.slice().sort((t,n)=>n.importanceScore-t.importanceScore||n.confidence-t.confidence||t.id.localeCompare(n.id)).slice(0,5).map(t=>zn(t.content)).join(" | ")}function Oi(e){return e.slice().sort((t,n)=>n.importanceScore-t.importanceScore||n.confidence-t.confidence||t.id.localeCompare(n.id)).slice(0,6).map(t=>zn(t.content)).join(`
|
|
26
|
+
`)}function Dn(e,t){let n=e.slice().sort((d,l)=>d.sequence-l.sequence||d.timestamp.localeCompare(l.timestamp)||d.id.localeCompare(l.id)),r=n.map(d=>({id:We("raw",[d.projectId,d.agent,d.nativeSessionId,d.id,String(d.sequence)].join("|")),level:"raw",eventId:d.id,sourceEventId:d.sourceEventId,sequence:d.sequence,type:d.type,role:d.role,timestamp:d.timestamp,sourcePath:d.provenance.sourcePath,payloadDigest:Mi(d.data)})),s=new Map,o=new Map;n.forEach((d,l)=>{let g=r[l];g&&(s.set(d.id,g.id),d.sourceEventId&&o.set(d.sourceEventId,g.id))});let i=t.map(d=>{let l=U([...d.provenance.eventIds.map(g=>s.get(g)),...d.provenance.sourceEventIds.map(g=>o.get(g))]);return{id:We("fact",d.fingerprint),level:"fact",fingerprint:d.fingerprint,kind:d.kind,type:d.type,content:d.content,knowledgeClass:d.knowledgeClass,importanceScore:d.importanceScore,confidence:d.confidence,tags:U([...d.tags,"level:fact",`class:${d.knowledgeClass}`,`kind:${d.kind}`]),rawIds:l,sourcePaths:U(d.provenance.sourcePaths)}}),a=new Map;for(let d of i){let l=Ei(d.kind),g=a.get(l)??[];g.push(d),a.set(l,g)}let c=[];for(let d of Ci){let l=a.get(d);if(!l?.length)continue;let g=l.slice().sort((y,h)=>h.importanceScore-y.importanceScore||h.confidence-y.confidence||y.id.localeCompare(h.id)),S=g.map(y=>y.id);c.push({id:We("scene",`${d}|${S.join("|")}`),level:"scene",kind:d,title:Pi[d],summary:Ti(g),factIds:S,importanceScore:Math.max(...g.map(y=>y.importanceScore)),confidence:Ln(g.map(y=>y.confidence)),tags:U(["level:scene",`scene:${d}`,...g.flatMap(y=>y.tags)]),sourcePaths:U(g.flatMap(y=>y.sourcePaths))})}let u=new Map(i.map(d=>[d.id,d])),f=[];for(let d of c){let g=d.factIds.map(h=>u.get(h)).filter(h=>!!h).filter(h=>(h.knowledgeClass==="permanent"||h.knowledgeClass==="task")&&h.importanceScore>=.55);if(g.length===0)continue;let S=g.some(h=>h.knowledgeClass==="permanent")?"permanent":"task",y=Oi(g);f.push({id:We("knowledge",`${d.id}|${S}|${g.map(h=>h.id).join("|")}`),level:"knowledge",knowledgeClass:S,title:d.title,content:y,sceneIds:[d.id],factIds:g.map(h=>h.id),importanceScore:Math.max(...g.map(h=>h.importanceScore)),confidence:Ln(g.map(h=>h.confidence)),tags:U(["level:knowledge",`class:${S}`,`scene:${d.kind}`,...g.flatMap(h=>h.tags)]),sourcePaths:U(g.flatMap(h=>h.sourcePaths))})}let m=[];for(let d of i)for(let l of d.rawIds)m.push({from:l,to:d.id,type:"supports"});for(let d of c)for(let l of d.factIds)m.push({from:l,to:d.id,type:"belongs_to"});for(let d of f)for(let l of d.sceneIds)m.push({from:l,to:d.id,type:"promotes_to"});return{schema:"toolnet.memory-hierarchy.v1",version:1,raw:r,facts:i,scenes:c,knowledge:f,links:m,stats:{raw:r.length,facts:i.length,scenes:c.length,knowledge:f.length,links:m.length}}}function pe(){let e=Pe(),t=process.env.TOOLNET_SESSION_SAVE||"summary",n=process.env.TOOLNET_RAW_TRANSCRIPT==="on"||t==="archive"||t==="full",r=process.env.TOOLNET_MEMORY_PROMOTION||"conservative",s=parseFloat(process.env.TOOLNET_PROMOTE_MIN_SCORE||"0.65"),o=parseInt(process.env.TOOLNET_SESSION_SUMMARY_MAX_TOKENS||"700",10),i=parseInt(process.env.TOOLNET_DURABLE_MEMORY_MAX_ITEMS_PER_SESSION||"10",10),a=n,c=process.env.TOOLNET_RAW_TRANSCRIPT_REMOTE==="on"||t==="full";return{sessionSave:t,rawTranscript:n,memoryPromotion:r,promoteMinScore:s,sessionSummaryMaxTokens:o,durableMemoryMaxItemsPerSession:i,archiveLocal:a,archiveRemote:c}}function qn(e){return(e||pe()).durableMemoryMaxItemsPerSession}function Hn(e){return(e||pe()).sessionSummaryMaxTokens}var Vn=new B;function Jn(e){let t=e.trim();if(t.startsWith("{")&&t.endsWith("}")||t.startsWith("[")&&t.endsWith("]"))try{let r=JSON.parse(t);return JSON.stringify(Vn.sanitizeValue(r))}catch{}let n=Vn.sanitize(e).text;return n=n.replace(/("(?:api[_-]?key|token|secret|password|cookie|authorization)"\s*:\s*)"[^"]*"/gi,'$1"[REDACTED]"').replace(/('(?:api[_-]?key|token|secret|password|cookie|authorization)'\s*:\s*)'[^']*'/gi,"$1'[REDACTED]'").replace(/\b(api[_-]?key|token|secret|password|cookie|authorization)\b\s*[:=]\s*[^\s,;]+/gi,"$1=[REDACTED]").replace(/\bbearer\s+[A-Za-z0-9._~+/=-]+/gi,"Bearer [REDACTED]"),n}function Ri(e,t){let n=e.toLowerCase(),r=.5,s=["nh\u1EDB","remember","quy t\u1EAFc","rule","t\u1EEB gi\u1EDD","from now","kh\xF4ng \u0111\u01B0\u1EE3c","must not","lu\xF4n lu\xF4n","always","never","critical","important","blocker","deploy","production","architecture"];for(let i of s)n.includes(i)&&(r+=.15);t==="rule"||t==="architecture"||t==="blocker"?r+=.2:t==="decision"||t==="deploy"?r+=.15:(t==="fix"||t==="next_action")&&(r+=.1),e.length<20?r-=.3:e.length>500&&(r-=.1);let o=[/npm (notice|warn|ERR)/i,/\d+ packages? in \d+/i,/found \d+ vulnerabilities/i,/up to date/i,/added \d+ packages/i,/^(ok|done|success|error|warning)$/i];for(let i of o)i.test(e)&&(r-=.4);return Math.max(0,Math.min(1,r))}function Ni(e,t){let n=[],r=new Set;for(let i of e){let a=i.split(`
|
|
27
|
+
`).filter(c=>c.trim());for(let c of a){let u=c.trim();if(u.length<15)continue;let f=u.toLowerCase().replace(/\s+/g," ");if(r.has(f))continue;r.add(f);let m="decision";/\b(rule|quy tắc|policy|standard|convention)\b/i.test(u)||/\b(always|never|must|should|từ giờ|không được)\b/i.test(u)?m="rule":/\b(fix|fixed|bug|issue|error|lỗi)\b/i.test(u)?m="fix":/\b(blocker|blocked|stuck|cannot|không thể)\b/i.test(u)?m="blocker":/\b(next|todo|action|task|cần làm)\b/i.test(u)?m="next_action":/\b(deploy|release|publish|ship)\b/i.test(u)?m="deploy":/\b(architecture|design|structure|pattern)\b/i.test(u)?m="architecture":/\.(ts|js|py|go|rs|java|cpp|c|h)\b/i.test(u)&&(m="file");let d=Ri(u,m);if(d<.3)continue;let l=Jn(u);n.push({category:m,text:l,importance:d,sourceSessionId:t})}}let s=pe(),o=qn(s);return n.sort((i,a)=>a.importance-i.importance).slice(0,o)}function _i(e){let t=pe(),n=Hn(t),o=e.join(`
|
|
28
|
+
|
|
29
|
+
`).split(`
|
|
30
|
+
`).filter(i=>{let a=i.trim();return a.length>20&&!a.startsWith("npm")&&!a.startsWith("\u2713")&&!a.startsWith("Error:")}).slice(0,20).map(i=>Jn(i)).join(`
|
|
31
|
+
`);return Dt(o,n)}function Bn(e,t){let r=(Array.isArray(e)?e:e.split(`
|
|
32
|
+
|
|
33
|
+
`).filter(l=>l.trim())).map(l=>typeof l=="string"?l:JSON.stringify(l)).filter(l=>l.trim()),s=Ni(r,t),o=s.filter(l=>l.category==="decision").map(l=>l.text),i=s.filter(l=>l.category==="rule").map(l=>l.text),a=s.filter(l=>l.category==="file").map(l=>l.text),c=s.filter(l=>l.category==="fix").map(l=>l.text),u=s.filter(l=>l.category==="blocker").map(l=>l.text),f=s.filter(l=>l.category==="next_action").map(l=>l.text),m=s.filter(l=>l.category==="deploy").map(l=>l.text);return{summary:_i(r),decisions:o,projectRules:i,filesChanged:a,bugsFixed:c,commands:m,blockers:u,nextActions:f,durableFacts:s}}function H(e){let t=new Set,n=[];for(let r of e){let s=r?.replace(/\s+/g," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();t.has(o)||(t.add(o),n.push(s))}return n}function Ki(e){let t=new Map;for(let n of e){if(!n||!n.id||!Number.isFinite(n.sequence))continue;let r=n.sourceEventId?`${n.agent}:${n.sourceEventId}`:n.id,s=t.get(r);(!s||n.sequence>s.sequence)&&t.set(r,n)}return[...t.values()].sort((n,r)=>n.sequence-r.sequence||n.timestamp.localeCompare(r.timestamp))}function $i(e){switch(e){case"critical":return 1;case"high":return .85;case"normal":return .6;case"temporary":return .25}}function Wi(e){let t=$i(e.importance);return Math.max(0,Math.min(1,t*.75+e.confidence*.25))}function Fi(e){return e.importance==="temporary"||e.confidence<.78?"transient":e.kind==="rule"||e.kind==="architecture"?"permanent":e.kind==="decision"||e.kind==="todo"||e.kind==="fix"?"task":"session"}function Li(e){let t=e.normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}_./:-]+/gu)??[],n=new Set;for(let r of t)if(!(r.length<2||/^\d+$/u.test(r))&&(n.add(r),n.size>=40))break;return[...n]}function zi(e){let t=Fi(e),n=Wi(e),r=Li(e.content);return{...e,knowledgeClass:t,importanceScore:n,retrievalTerms:r,tags:H([...e.tags,"level:fact",`class:${t}`,`kind:${e.kind}`])}}function Di(e){return e.map(t=>{try{return JSON.stringify({type:t.type,role:t.role,data:t.data,provenance:{sourcePath:t.provenance.sourcePath,files:t.provenance.files}})}catch{return""}}).filter(Boolean)}function qi(e,t,n){let r=Bn(Di(t),e.nativeSessionId),s=n.filter(u=>u.kind==="todo").map(u=>u.content),o=n.flatMap(u=>u.provenance.sourcePaths),i=n.filter(u=>u.kind==="architecture").map(u=>u.content),a=H([...s,...r.nextActions]),c=H([...r.nextActions,...s]);return{summary:r.summary,state:{task:c[0]??a[0],decisions:H(r.decisions),files:H([...r.filesChanged,...o]),todos:a,completed:H(r.bugsFixed),blockers:H(r.blockers),nextActions:c,architecture:H(i)}}}function Fe(e,t){let n=Ki(t),r=Fn(e,n).map(zi),s=r.filter(f=>f.knowledgeClass!=="transient").sort((f,m)=>m.importanceScore-f.importanceScore),{summary:o,state:i}=qi(e,n,s),a=s.map(f=>({fingerprint:f.fingerprint,kind:f.kind,knowledgeClass:f.knowledgeClass,importanceScore:f.importanceScore,content:f.content,terms:f.retrievalTerms})),c=Dn(n,s),u=f=>r.filter(m=>m.knowledgeClass===f).length;return{version:2,normalizedEvents:n,summary:o,state:i,candidates:s,retrievalIndex:a,hierarchy:c,stats:{inputEvents:t.length,normalizedEvents:n.length,extractedCandidates:r.length,persistedCandidates:s.length,permanent:u("permanent"),task:u("task"),session:u("session"),transient:u("transient")}}}import{createHash as Xi}from"node:crypto";import{existsSync as Qi,readdirSync as Zi,readFileSync as ea}from"node:fs";import{basename as ta,join as lr}from"node:path";import{randomUUID as Yn}from"node:crypto";var j=class extends Error{constructor(n,r){super(n);this.statusCode=r}statusCode};function me(e){let t=new Set,n=[];for(let r of e){let s=r.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();t.has(o)||(t.add(o),n.push(s))}return n}function X(e){let t=e.normalize("NFKD").replace(/[\u0300-\u036f]/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,120);if(!t)throw new j("Invalid Wiki slug",400);return t}function Gn(e){let t=[];for(let n of e.matchAll(/\[\[([^\[\]]+)\]\]/gu)){let r=n[1]?.trim();r&&t.push(X(r))}return me(t)}function Hi(e){return e.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_-]+/u).map(t=>t.trim()).filter(t=>t.length>=2)}function Un(e){return{id:`revision-${Yn()}`,pageId:e.id,slug:e.slug,revision:e.revision,title:e.title,...e.summary?{summary:e.summary}:{},content:e.content,tags:[...e.tags],links:[...e.links],createdAt:e.updatedAt}}function Y(e){return structuredClone(e)}var Le=class{constructor(t){this.store=t}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}async mutate(t){let n,r=this.queue.then(async()=>{let s=await this.ensureState();n=t(s),s.updatedAt=new Date().toISOString(),await this.store.save(s)});return this.queue=r.then(()=>{},()=>{}),await r,n}async summary(){let t=await this.ensureState(),n=new Set(t.pages.flatMap(r=>r.links));return{schema:"toolnet.wiki-summary.v1",projectId:t.projectId,pages:t.pages.length,revisions:t.revisions.length,tags:me(t.pages.flatMap(r=>r.tags)).sort((r,s)=>r.localeCompare(s)),links:t.pages.reduce((r,s)=>r+s.links.length,0),orphanPages:t.pages.filter(r=>r.links.length===0&&!n.has(r.slug)).length,automatedPages:t.pages.filter(r=>r.tags.some(s=>s.startsWith("toolnet-auto-"))).length,updatedAt:t.updatedAt}}async listPages(){let t=await this.ensureState();return Y([...t.pages].sort((n,r)=>n.title.localeCompare(r.title)))}async getPage(t){let n=await this.ensureState(),r=X(t),s=n.pages.find(o=>o.slug===r||o.id===t);if(!s)throw new j(`Wiki page not found: ${t}`,404);return Y(s)}async createPage(t){return this.mutate(n=>{let r=t.title.trim(),s=t.content.trim();if(!r)throw new j("Wiki title is required",400);let o=X(t.slug??r);if(n.pages.some(c=>c.slug===o))throw new j(`Wiki page already exists: ${o}`,409);let i=new Date().toISOString(),a={id:`wiki-${Yn()}`,slug:o,title:r,...t.summary?.trim()?{summary:t.summary.trim()}:{},content:s,tags:me(t.tags??[]),links:Gn(s),revision:1,createdAt:i,updatedAt:i};return n.pages.push(a),n.revisions.push(Un(a)),Y(a)})}async updatePage(t,n){return this.mutate(r=>{let s=X(t),o=r.pages.find(i=>i.slug===s||i.id===t);if(!o)throw new j(`Wiki page not found: ${t}`,404);if(n.title!==void 0){let i=n.title.trim();if(!i)throw new j("Wiki title is required",400);o.title=i}if(n.summary!==void 0){let i=n.summary.trim();i?o.summary=i:delete o.summary}return n.content!==void 0&&(o.content=n.content.trim(),o.links=Gn(o.content)),n.tags!==void 0&&(o.tags=me(n.tags)),o.revision+=1,o.updatedAt=new Date().toISOString(),r.revisions.push(Un(o)),Y(o)})}async history(t){let n=await this.getPage(t),r=await this.ensureState();return Y(r.revisions.filter(s=>s.pageId===n.id).sort((s,o)=>o.revision-s.revision))}async backlinks(t){let n=await this.getPage(t),r=await this.ensureState();return Y(r.pages.filter(s=>s.links.includes(n.slug)).sort((s,o)=>s.title.localeCompare(o.title)))}async search(t,n=10){let r=await this.ensureState(),s=me(Hi(t));if(s.length===0)return[];let o=Math.max(1,Math.min(20,Math.floor(n))),i=[];for(let a of r.pages){let c=a.title.toLowerCase(),u=a.slug.toLowerCase(),f=a.summary?.toLowerCase()??"",m=a.content.toLowerCase(),d=a.tags.map(g=>g.toLowerCase()),l=0;for(let g of s)u===g&&(l+=12),c===g&&(l+=10),c.includes(g)&&(l+=6),u.includes(g)&&(l+=5),d.some(S=>S===g)?l+=5:d.some(S=>S.includes(g))&&(l+=3),f.includes(g)&&(l+=2),m.includes(g)&&(l+=1);l>0&&i.push({page:Y(a),score:l})}return i.sort((a,c)=>c.score-a.score||c.page.updatedAt.localeCompare(a.page.updatedAt)).slice(0,o)}};var Xn="wiki/state.v1.json";function Vi(e){let t=new Date().toISOString();return{schema:"toolnet.wiki.v1",version:1,projectId:e.id,pages:[],revisions:[],createdAt:t,updatedAt:t}}function Ji(e,t){let n=JSON.parse(e);if(n.schema!=="toolnet.wiki.v1"||n.version!==1||n.projectId!==t.id||!Array.isArray(n.pages)||!Array.isArray(n.revisions))throw new Error("Invalid ToolNet Wiki state");return n}var ze=class{constructor(t,n){this.storage=t;this.project=n}storage;project;async load(){let t=await this.storage.getText(Xn);if(!t){let n=Vi(this.project);return await this.save(n),n}return Ji(t,this.project)}async save(t){await this.storage.put(Xn,JSON.stringify(t,null,2),"application/json")}};import{createHash as Bi,randomUUID as Qn}from"node:crypto";var Zn="wiki/governance.v1.json",rr="toolnet.knowledge-governance.v1",er=500,fe={autoApproveThreshold:.86,criticalApproveThreshold:.94,staleAfterDays:90};function Gi(e,t=0,n=1){return Math.max(t,Math.min(n,e))}function xt(e){return e.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/gu," ").trim()}function tr(e){return Bi("sha256").update(e.normalize("NFKC").replace(/\s+/gu," ").trim()).digest("hex")}function Ui(e){let t=[e.title,e.summary??"",e.content.slice(0,2e3),...e.tags].join(" ").toLowerCase();return/\b(?:architecture|security|authentication|authorization|auth|database|production|deploy|deployment|payment|billing|permission|permissions|acl|credential|secret|migration)\b/u.test(t)}function Yi(e){let t=e.sourceType==="skill"?.96:e.sourceType==="memory"?.94:.88,n=e.tags.map(r=>r.toLowerCase());return(n.includes("permanent")||n.includes("task"))&&(t+=.03),e.content.length>=200&&(t+=.02),e.content.length<80&&(t-=.05),e.title.length<4&&(t-=.05),Gi(t)}function nr(e){let t=new Date().toISOString();return{schema:rr,version:1,projectId:e,policy:{...fe},reviews:[],audit:[],createdAt:t,updatedAt:t}}function sr(e){let t=e.autoApproveThreshold??fe.autoApproveThreshold,n=e.criticalApproveThreshold??fe.criticalApproveThreshold,r=e.staleAfterDays??fe.staleAfterDays;if(!Number.isFinite(t)||t<.5||t>1)throw new j("Invalid autoApproveThreshold",400);if(!Number.isFinite(n)||n<.5||n>1)throw new j("Invalid criticalApproveThreshold",400);if(!Number.isInteger(r)||r<1||r>3650)throw new j("Invalid staleAfterDays",400);return{autoApproveThreshold:t,criticalApproveThreshold:n,staleAfterDays:r}}var De=class{constructor(t,n){this.storage=t;this.project=n}storage;project;async load(){let t=await this.storage.getText(Zn);if(!t){let n=nr(this.project.id);return await this.save(n),n}try{let n=JSON.parse(t);if(n.schema!==rr||n.version!==1||n.projectId!==this.project.id||!Array.isArray(n.reviews)||!Array.isArray(n.audit))throw new Error("invalid");return{...n,policy:sr(n.policy??fe)}}catch{let n=nr(this.project.id);return await this.save(n),n}}async save(t){await this.storage.put(Zn,JSON.stringify(t,null,2),"application/json")}},qe=class{constructor(t){this.store=t}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}audit(t,n,r,s={}){t.audit.push({id:Qn(),action:n,principal:r,...s.reviewId?{reviewId:s.reviewId}:{},...s.sourceKey?{sourceKey:s.sourceKey}:{},timestamp:new Date().toISOString(),...s.metadata?{metadata:s.metadata}:{}}),t.audit.length>er&&(t.audit=t.audit.slice(-er))}async mutate(t){let n,r=this.queue.then(async()=>{let s=await this.ensureState();n=await t(s),s.updatedAt=new Date().toISOString(),await this.store.save(s)});return this.queue=r.then(()=>{},()=>{}),await r,n}async policy(){return{...(await this.ensureState()).policy}}async setPolicy(t,n){return this.mutate(r=>(r.policy=sr({...r.policy,...t}),this.audit(r,"policy:update",n,{metadata:{...r.policy}}),{...r.policy}))}async summary(){let t=await this.ensureState(),n=r=>t.reviews.filter(s=>s.status===r).length;return{schema:"toolnet.knowledge-governance-summary.v1",projectId:t.projectId,pending:n("pending"),approved:n("approved"),rejected:n("rejected"),superseded:n("superseded"),criticalPending:t.reviews.filter(r=>r.status==="pending"&&r.risk==="critical").length,conflictPending:t.reviews.filter(r=>r.status==="pending"&&r.risk==="conflict").length,auditEvents:t.audit.length,policy:{...t.policy},updatedAt:t.updatedAt}}async listReviews(t){let n=await this.ensureState();return structuredClone(n.reviews.filter(r=>!t||r.status===t).sort((r,s)=>s.updatedAt.localeCompare(r.updatedAt)))}async auditLog(t=100){let n=await this.ensureState(),r=Math.max(1,Math.min(500,Math.floor(t)));return structuredClone(n.audit.slice(-r).reverse())}async assess(t,n){let r=await this.ensureState(),s=Yi(t),o=xt(t.title),i=n.filter(f=>f.slug!==t.slug&&xt(f.title)===o&&tr(f.content)!==tr(t.content)).map(f=>f.slug),a=Ui(t),c=[];s<r.policy.autoApproveThreshold&&c.push(`confidence:${s.toFixed(2)}`),a&&s<r.policy.criticalApproveThreshold&&c.push("critical-knowledge"),i.length>0&&c.push("conflicting-knowledge");let u=i.length>0?"conflict":a?"critical":"normal";return{confidence:s,risk:u,requiresReview:i.length>0||s<r.policy.autoApproveThreshold||a&&s<r.policy.criticalApproveThreshold,reasons:c,conflicts:i}}async gate(t,n){let r=await this.assess(t,n);return this.mutate(s=>{let o=s.reviews.find(c=>c.sourceKey===t.sourceKey&&c.digest===t.digest);if(o?.status==="approved")return{allowed:!0,mode:"review-approved",assessment:r,review:structuredClone(o)};if(o?.status==="rejected")return{allowed:!1,mode:"rejected",assessment:r,review:structuredClone(o)};if(!r.requiresReview)return this.audit(s,"knowledge:auto-approved","system",{sourceKey:t.sourceKey,metadata:{confidence:r.confidence,risk:r.risk}}),{allowed:!0,mode:"auto-approved",assessment:r};if(o?.status==="pending")return{allowed:!1,mode:"pending-review",assessment:r,review:structuredClone(o)};let i=new Date().toISOString(),a={id:Qn(),sourceKey:t.sourceKey,sourceType:t.sourceType,slug:t.slug,marker:t.marker,digest:t.digest,title:t.title,...t.summary?{summary:t.summary}:{},content:t.content,tags:[...new Set([...t.tags,t.marker])],confidence:r.confidence,risk:r.risk,reasons:[...r.reasons],conflicts:[...r.conflicts],status:"pending",createdAt:i,updatedAt:i};return s.reviews.push(a),this.audit(s,"knowledge:review-requested","system",{reviewId:a.id,sourceKey:a.sourceKey,metadata:{confidence:a.confidence,risk:a.risk}}),{allowed:!1,mode:"pending-review",assessment:r,review:structuredClone(a)}})}async markApplied(t,n){await this.mutate(r=>{let s=r.reviews.find(o=>o.sourceKey===t&&o.digest===n&&o.status==="approved");s&&(s.appliedAt=new Date().toISOString(),s.updatedAt=s.appliedAt,this.audit(r,"knowledge:applied",s.reviewedBy??"system",{reviewId:s.id,sourceKey:t}))})}async decide(t,n,r){return this.mutate(async s=>{let o=s.reviews.find(u=>u.id===t);if(!o)throw new j(`Governance review not found: ${t}`,404);if(o.status!=="pending")throw new j("Governance review is already resolved",409);let i=new Date().toISOString();if(o.reviewedAt=i,o.reviewedBy=n.principal,o.updatedAt=i,n.note?.trim()&&(o.reviewNote=n.note.trim()),n.action==="reject")return o.status="rejected",this.audit(s,"knowledge:rejected",n.principal,{reviewId:t,sourceKey:o.sourceKey}),structuredClone(o);if(n.action==="supersede")return o.status="superseded",n.targetReviewId&&(o.supersededBy=n.targetReviewId),this.audit(s,"knowledge:superseded",n.principal,{reviewId:t,sourceKey:o.sourceKey,metadata:{targetReviewId:n.targetReviewId}}),structuredClone(o);if(n.action==="merge"){if(!n.targetReviewId)throw new j("targetReviewId is required for merge",400);let u=s.reviews.find(f=>f.id===n.targetReviewId);if(!u)throw new j("Merge target review not found",404);return o.status="superseded",o.mergedInto=u.id,this.audit(s,"knowledge:merged",n.principal,{reviewId:t,sourceKey:o.sourceKey,metadata:{targetReviewId:u.id}}),structuredClone(o)}o.status="approved";let c=(await r.listPages()).find(u=>u.slug===o.slug);if(c&&!c.tags.includes(o.marker))throw new j(`Wiki page '${o.slug}' is manually managed`,409);return c?await r.updatePage(o.slug,{title:o.title,summary:o.summary??"",content:o.content,tags:o.tags}):await r.createPage({slug:o.slug,title:o.title,...o.summary?{summary:o.summary}:{},content:o.content,tags:o.tags}),o.appliedAt=i,this.audit(s,"knowledge:approved",n.principal,{reviewId:t,sourceKey:o.sourceKey}),structuredClone(o)})}async quality(t){let n=await this.ensureState(),r=await t.listPages(),s=Date.now(),o=n.policy.staleAfterDays*864e5,i=r.map(f=>{let m=s-Date.parse(f.updatedAt);return{slug:f.slug,title:f.title,updatedAt:f.updatedAt,ageDays:Math.max(0,Math.floor(m/864e5)),stale:Number.isFinite(m)&&m>o}}).filter(f=>f.stale).map(({stale:f,...m})=>m),a=new Map;for(let f of r){let m=xt(f.title),d=a.get(m)??[];d.push(f),a.set(m,d)}let c=[...a.entries()].filter(([,f])=>f.length>1).map(([f,m])=>({title:f,pages:m.map(d=>d.slug)})),u=n.reviews.filter(f=>f.status==="pending");return{schema:"toolnet.knowledge-quality.v1",totalPages:r.length,automatedPages:r.filter(f=>f.tags.some(m=>m.startsWith("toolnet-auto-"))).length,manualPages:r.filter(f=>!f.tags.some(m=>m.startsWith("toolnet-auto-"))).length,stalePages:i,duplicateTitles:c,pendingReviews:u.length,lowConfidenceReviews:u.filter(f=>f.confidence<n.policy.autoApproveThreshold).length,conflicts:u.filter(f=>f.risk==="conflict").length,generatedAt:new Date().toISOString()}}};var dr="wiki/automation.v1.json",pr="toolnet.wiki-automation.v1",It=8e3,or=new Set(["raw","rawtext","raw_text","rawtranscript","raw_transcript","transcript","messages","message","payload","prompt","response","assistantmessage","assistant_message","userprompt","user_prompt"]);function ye(e){return Xi("sha256").update(JSON.stringify(e)).digest("hex")}function ge(e){if(!(!e||typeof e!="object"||Array.isArray(e)))return e}function ir(e){return Array.isArray(e)?e:[]}function mr(e){return typeof e!="string"?void 0:e.replace(/\s+/gu," ").trim()||void 0}function jt(e){return Array.isArray(e)?e.map(mr).filter(t=>!!t):[]}function _(e,t){for(let n of t){let r=mr(e[n]);if(r)return r}}function he(e){let t=new Set,n=[];for(let r of e){let s=r.replace(/\s+/gu," ").trim();if(!s)continue;let o=s.normalize("NFKC").toLowerCase();t.has(o)||(t.add(o),n.push(s))}return n}function He(e,t=0,n=""){if(t>3)return[];let r=n.replace(/[^a-z0-9]/giu,"").toLowerCase();if(or.has(r))return[];if(typeof e=="string"){let i=e.replace(/\s+/gu," ").trim();return i.length<8?[]:[i]}if(Array.isArray(e))return e.flatMap(i=>He(i,t+1,n));let s=ge(e);if(!s)return[];let o=[];for(let[i,a]of Object.entries(s)){let c=i.replace(/[^a-z0-9]/giu,"").toLowerCase();or.has(c)||o.push(...He(a,t+1,i))}return o}function ar(e){let n=he(["content","summary","text","value","statement","description","decision","task","knowledge","context","outcome","reason","rationale"].flatMap(s=>He(e[s],0,s)));return(n.length>0?n:he(He(e))).join(`
|
|
34
|
+
|
|
35
|
+
`).slice(0,It)}function cr(e,t){return _(e,["id","key","fingerprint","knowledgeId","sceneId"])??t}function ur(e,t){return _(e,["title","name","topic","label","task","kind","type"])??t}function na(e){return(_(e,["knowledgeClass","class","classification","scope"])??"").toLowerCase()}function ra(e){return(_(e,["kind","sceneKind","type"])??"").toLowerCase()}function sa(e){let t=ge(e);if(!t)return[];let n=[],r=ir(t.knowledge);for(let[o,i]of r.entries()){let a=ge(i);if(!a)continue;let c=na(a);if(c==="session"||c==="transient")continue;let u=ar(a);if(u.length<20)continue;let f=cr(a,ye(a).slice(0,16)),m=ur(a,`Durable Memory ${o+1}`);n.push({sourceKey:`memory:${f}`,sourceType:"memory",title:m,summary:_(a,["summary","description"]),content:u,tags:he(["toolnet","auto","memory",...c?[c]:[]])})}let s=ir(t.scenes);for(let[o,i]of s.entries()){let a=ge(i);if(!a)continue;let c=ra(a);if(c==="session-context")continue;let u=ar(a);if(u.length<20)continue;let f=cr(a,ye(a).slice(0,16)),m=ur(a,`Knowledge Scene ${o+1}`);n.push({sourceKey:`scene:${f}`,sourceType:"scene",title:m,summary:_(a,["summary","description"]),content:u,tags:he(["toolnet","auto","scene",...c?[c]:[]])})}return n}function oa(e){return lr(e,".toolnet","memory","skills")}function ia(e){let t=oa(e);if(!Qi(t))return{candidates:[],failed:0};let n=[],r=0,s=Zi(t).filter(o=>o.endsWith(".json")).sort();for(let o of s)try{let i=JSON.parse(ea(lr(t,o),"utf8")),a=ge(i);if(!a||a.schema!=="toolnet.skill-memory.v1")continue;let c=_(a,["id","fingerprint"])??ta(o,".json"),u=_(a,["task"])??"",f=_(a,["title"])||u||`Reusable Skill ${c.slice(0,8)}`,m=_(a,["summary"])??void 0,d=jt(a.steps),l=jt(a.verification),g=jt(a.files),S=[];u&&S.push(`## Task
|
|
36
|
+
${u}`),m&&S.push(`## Summary
|
|
37
|
+
${m}`),d.length>0&&S.push(`## Procedure
|
|
38
|
+
${d.map((h,k)=>`${k+1}. ${h}`).join(`
|
|
39
|
+
`)}`),l.length>0&&S.push(`## Verification
|
|
40
|
+
${l.map(h=>`- ${h}`).join(`
|
|
41
|
+
`)}`),g.length>0&&S.push(`## Relevant Files
|
|
42
|
+
${g.map(h=>`- \`${h}\``).join(`
|
|
43
|
+
`)}`);let y=S.join(`
|
|
44
|
+
|
|
45
|
+
`).slice(0,It);if(y.length<20)continue;n.push({sourceKey:`skill:${c}`,sourceType:"skill",title:f,summary:m,content:y,tags:["toolnet","auto","skill","sop"]})}catch{r+=1}return{candidates:n,failed:r}}function At(e){let t=new Date().toISOString();return{schema:pr,version:1,projectId:e,entries:[],createdAt:t,updatedAt:t}}async function aa(e,t){let n=await e.getText(dr);if(!n)return At(t);try{let r=JSON.parse(n);return r.schema!==pr||r.version!==1||r.projectId!==t||!Array.isArray(r.entries)?At(t):r}catch{return At(t)}}async function ca(e,t){await e.put(dr,JSON.stringify(t,null,2),"application/json")}function ua(e){return`toolnet-auto-${ye(e).slice(0,12)}`}function la(e){let t=X(e.title).slice(0,72),n=ye(e.sourceKey).slice(0,10);return X(`auto-${e.sourceType}-${t}-${n}`)}function da(e){return[`> Auto-generated by ToolNet Knowledge Automation from ${e.sourceType==="skill"?"reusable Skill Memory":e.sourceType==="scene"?"semantic memory scene":"durable memory"}.`,"",e.content].join(`
|
|
46
|
+
`).slice(0,It)}function pa(e){return ye({sourceType:e.sourceType,title:e.title,summary:e.summary,content:e.content,tags:e.tags})}function ma(e,t){return e.tags.includes(t)}async function fr(e){let t=sa(e.hierarchy),n=ia(e.project.rootPath),r=new Map;for(let l of[...t,...n.candidates])r.set(l.sourceKey,l);let s=[...r.values()].sort((l,g)=>l.sourceKey.localeCompare(g.sourceKey)),o={schema:"toolnet.wiki-automation-result.v1",scanned:t.length+n.candidates.length,eligible:s.length,created:0,updated:0,unchanged:0,skipped:0,failed:n.failed,reviewPending:0,autoApproved:0,reviewApproved:0,pages:[]},i=new Le(new ze(e.storage,e.project));await i.initialize();let a=new qe(new De(e.storage,e.project));await a.initialize();let c=await aa(e.storage,e.project.id),u=await i.listPages(),f=new Map(u.map(l=>[l.slug,l])),m=new Map(c.entries.map(l=>[l.sourceKey,l]));for(let l of s)try{let g=ua(l.sourceKey),S=pa(l),y=m.get(l.sourceKey),h=y?.slug??la(l),k=f.get(h);if(k&&!ma(k,g)){o.skipped+=1;continue}let C=he([...l.tags,g]),M=da(l),I=await a.gate({sourceKey:l.sourceKey,sourceType:l.sourceType,slug:h,marker:g,digest:S,title:l.title,...l.summary?{summary:l.summary}:{},content:M,tags:C},[...f.values()]);if(!I.allowed){I.mode==="pending-review"?o.reviewPending+=1:o.skipped+=1;continue}I.mode==="auto-approved"?o.autoApproved+=1:I.mode==="review-approved"&&(o.reviewApproved+=1),k?y?.digest!==S?(k=await i.updatePage(h,{title:l.title,summary:l.summary??"",content:M,tags:C}),f.set(k.slug,k),o.updated+=1,o.pages.push({sourceKey:l.sourceKey,sourceType:l.sourceType,slug:k.slug,action:"updated"})):(o.unchanged+=1,o.pages.push({sourceKey:l.sourceKey,sourceType:l.sourceType,slug:h,action:"unchanged"})):(k=await i.createPage({slug:h,title:l.title,summary:l.summary,content:M,tags:C}),f.set(k.slug,k),o.created+=1,o.pages.push({sourceKey:l.sourceKey,sourceType:l.sourceType,slug:k.slug,action:"created"}));let E=new Date().toISOString(),x={sourceKey:l.sourceKey,sourceType:l.sourceType,slug:h,digest:S,marker:g,updatedAt:E},v=c.entries.findIndex(F=>F.sourceKey===l.sourceKey);v>=0?c.entries[v]=x:c.entries.push(x),m.set(l.sourceKey,x),await a.markApplied(l.sourceKey,S)}catch(g){if(g instanceof j&&g.statusCode===409){o.skipped+=1;continue}o.failed+=1}let d=new Date().toISOString();return c.updatedAt=d,c.lastRunAt=d,c.entries.sort((l,g)=>l.sourceKey.localeCompare(g.sourceKey)),await ca(e.storage,c),o}import{createHash as fa}from"node:crypto";import{chmodSync as yr,existsSync as ga,mkdirSync as ya,readFileSync as Fp,readdirSync as Lp,renameSync as ha,statSync as zp,writeFileSync as Sa}from"node:fs";import{join as hr}from"node:path";var ka="toolnet.skill-memory.v1",gr=5,wa=16,va=24,ba=32;function xa(e){return fa("sha256").update(e).digest("hex")}function ke(e,t=Number.MAX_SAFE_INTEGER){let n=new Set,r=[];for(let s of e){let o=s.replace(/\s+/gu," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();if(!n.has(i)&&(n.add(i),r.push(o),r.length>=t))break}return r}function Ct(e,t=360){let n=e.replace(/\s+/gu," ").trim();return n.length<=t?n:n.slice(0,Math.max(0,t-1)).trimEnd()+"\u2026"}function ja(e){return e.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/giu,"Bearer [REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{8,}\b/gu,"[REDACTED]").replace(/\b(api[_-]?key|token|password|passwd|secret)\b(\s*[:=]\s*)(["']?)[^\s"'`]+/giu,"$1$2[REDACTED]")}function z(e,t=360){return e&&Ct(ja(e),t)||void 0}function we(e,t){for(let n of t){let r=e[n];if(typeof r=="string"&&r.trim())return r}}function Sr(e,t){for(let n of t){let r=e[n];if(typeof r=="number"&&Number.isFinite(r))return r;if(typeof r=="string"&&r.trim()&&Number.isFinite(Number(r)))return Number(r)}}function kr(e,t){for(let n of t){let r=e[n];if(typeof r=="boolean")return r;if(typeof r=="string"){let s=r.trim().toLowerCase();if(["true","yes","pass","passed","success","succeeded","ok"].includes(s))return!0;if(["false","no","fail","failed","error"].includes(s))return!1}}}function wr(e){let t=e.data??{};if(kr(t,["passed","pass","success","succeeded","ok"])===!1)return!0;let r=Sr(t,["exitCode","exit_code","code","statusCode"]);if(r!==void 0&&r!==0)return!0;let s=we(t,["status","result","outcome"]);return!!(s&&/\b(fail(?:ed)?|error|broken|cancelled)\b/iu.test(s))}function Se(e){let t=e.data??{};if(wr(e))return!1;if(kr(t,["passed","pass","success","succeeded","ok"])===!0||Sr(t,["exitCode","exit_code","code","statusCode"])===0)return!0;let s=we(t,["status","result","outcome"]);return s&&/\b(pass(?:ed)?|success(?:ful)?|succeeded|ok|green|complete(?:d)?)\b/iu.test(s)?!0:e.type==="commit"||e.type==="deploy"}function vr(e){let t=e.data??{},n=we(t,["path","file","filePath","filename","target"]);if(n)return z(n,260);let r=e.provenance?.files;return z(r?.[0],260)}function Pt(e){return z(we(e.data??{},["command","cmd","script"]),420)}function ne(e){return z(we(e.data??{},["name","test","suite","title","message","text","result","status"]),300)}function Aa(e){let t=[];for(let n of[...e].sort((r,s)=>r.sequence-s.sequence))if(Se(n)){if(n.type==="test"){let r=ne(n)??Pt(n)??"Tests passed";t.push(`Test passed: ${r}`);continue}if(n.type==="commit"){let r=ne(n);t.push(r?`Commit: ${r}`:"Commit completed");continue}if(n.type==="deploy"){let r=ne(n);t.push(r?`Deploy: ${r}`:"Deployment completed")}}return ke(t,10)}function Ia(e,t){let n=[];for(let r of[...e].sort((s,o)=>s.sequence-o.sequence))switch(r.type){case"file_write":case"file_edit":{let s=vr(r);s&&n.push(`Update ${s}`);break}case"command":{if(wr(r))break;let s=Pt(r);s&&n.push(`Run: ${s}`);break}case"test":{if(!Se(r))break;let s=ne(r)??Pt(r)??"project tests";n.push(`Verify: ${s}`);break}case"commit":{if(!Se(r))break;let s=ne(r);n.push(s?`Commit: ${s}`:"Commit verified changes");break}case"deploy":{if(!Se(r))break;let s=ne(r);n.push(s?`Deploy: ${s}`:"Deploy verified build");break}default:break}if(n.length===0)for(let r of t.files.slice(0,8)){let s=z(r,260);s&&n.push(`Update ${s}`)}return ke(n,wa)}function Ca(e,t){let n=[...t.files];for(let r of e){let s=vr(r);s&&n.push(s);for(let o of r.provenance?.files??[]){let i=z(o,260);i&&n.push(i)}}return ke(n,va)}function Pa(e){return ke(e.filter(t=>["file_write","file_edit","command","test","commit","deploy"].includes(t.type)).map(t=>t.id),ba)}function Ma(e){return e.map(n=>n.timestamp).filter(Boolean).sort().at(-1)??new Date(0).toISOString()}function br(e,t,n){if(t.length===0)return[];let r=Aa(t),s=ke(n.completed.map(g=>z(g,280)??""),gr);if(!(s.length>0||t.some(g=>["test","commit","deploy"].includes(g.type)&&Se(g))))return[];let i=z(n.task,280)??z(n.nextActions[0],280),a=s.length>0?s:i?[i]:[];if(a.length===0)return[];let c=Ia(t,n);if(c.length===0)return[];let u=Ca(t,n),f=Pa(t),m=Math.min(...t.map(g=>g.sequence)),d=Math.max(...t.map(g=>g.sequence)),l=Ma(t);return a.slice(0,gr).map(g=>{let S=[`Reusable procedure learned from successful task: ${g}.`,u.length>0?`Files: ${u.slice(0,6).join(", ")}.`:"",r.length>0?`Verification: ${r.slice(0,4).join("; ")}.`:""].filter(Boolean),y=JSON.stringify({projectId:e.projectId,task:g,steps:c,verification:r,files:u}),h=xa(y);return{schema:ka,version:1,id:`skill-${h.slice(0,24)}`,fingerprint:h,projectId:e.projectId,title:Ct(`SOP: ${g}`,180),task:g,summary:Ct(S.join(" "),900),steps:c,verification:r,files:u,source:{agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,firstSequence:m,lastSequence:d,eventIds:f},createdAt:l}})}function Ea(e){return hr(e.rootPath,".toolnet","memory","skills")}function Ta(e){let t=Ea(e);return ya(t,{recursive:!0,mode:448}),yr(t,448),t}function xr(e,t){if(t.length===0)return{written:0,deduped:0,files:[]};let n=Ta(e),r=0,s=0,o=[];for(let i of t){if(i.projectId!==e.id)throw new Error(`Skill project mismatch: ${i.projectId} != ${e.id}`);let a=hr(n,`${i.id}.json`);if(o.push(a),ga(a)){s+=1;continue}let c=`${a}.${process.pid}.${Date.now()}.tmp`;Sa(c,JSON.stringify(i,null,2)+`
|
|
47
|
+
`,{encoding:"utf8",mode:384}),ha(c,a),yr(a,384),r+=1}return{written:r,deduped:s,files:o}}function jr(e){return String(e).padStart(12,"0")}function Oa(e){return e.remotePrefix.replace("/sessions/","/memory/learned/")}var Ve=class{constructor(t){this.storage=t}storage;async write(t,n,r){if(r.length===0||n.length===0)return null;let s=Math.min(...n.map(f=>f.sequence)),o=Math.max(...n.map(f=>f.sequence)),i={version:1,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,candidateCount:r.length,candidates:r},a=JSON.stringify(i,null,2)+`
|
|
48
|
+
`,c=w(r.map(f=>f.fingerprint).sort().join("|")).slice(0,16),u=[Oa(t),"batches",`${jr(s)}-${jr(o)}-${c}.json`].join("/");return await this.storage.exists(u)||await this.storage.put(u,a,"application/json"),u}};import{createHash as Ra}from"node:crypto";function Ar(e){return String(e).padStart(12,"0")}function Na(e){return Ra("sha256").update(e).digest("hex")}function _a(e){return e.remotePrefix.replace("/sessions/","/memory/hierarchy/")}var Je=class{constructor(t){this.storage=t}storage;async write(t,n,r){if(n.length===0||r.facts.length===0)return null;let s=Math.min(...n.map(u=>u.sequence)),o=Math.max(...n.map(u=>u.sequence)),i={schema:"toolnet.memory-hierarchy-batch.v1",version:1,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,hierarchy:r},a=Na([...r.facts.map(u=>u.id),...r.knowledge.map(u=>u.id)].sort().join("|")).slice(0,16),c=[_a(t),"batches",`${Ar(s)}-${Ar(o)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,`${JSON.stringify(i,null,2)}
|
|
49
|
+
`,"application/json"),c}};function za(e,t){if(!$a(e))return{events:[],nextOffset:t};let n=La(e).size,r=Number.isFinite(t)?Math.max(0,t):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=Wa(e,"r");try{Fa(i,o,0,s,r)}finally{Ka(i)}let a=o.toString("utf8"),c=a.lastIndexOf(`
|
|
50
|
+
`);if(c<0)return{events:[],nextOffset:r};let u=a.slice(0,c+1);return{events:u.split(`
|
|
51
|
+
`).filter(Boolean).flatMap(m=>{try{return[JSON.parse(m)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(u,"utf8")}}var Be=class{constructor(t){this.options=t;this.journal=new Ve(t.storage),this.hierarchyJournal=new Je(t.storage)}options;journal;hierarchyJournal;async learnNew(){let t=this.options.wal.loadState(),n=Number(t.sourceCursors["memory.learner.offset"]??0),r=Number.isFinite(n)?n:0,s=za(this.options.wal.eventsFile,r);if(s.events.length===0)return{scannedEvents:0,candidates:0,journalWritten:!1,nextOffset:s.nextOffset};let o=Fe(this.options.identity,s.events),i=o.candidates,a=!1;i.length>0&&(a=!!await this.journal.write(this.options.identity,s.events,i));let c=!1;o.hierarchy.facts.length>0&&(c=!!await this.hierarchyJournal.write(this.options.identity,s.events,o.hierarchy));let u=br(this.options.identity,s.events,o.state),f=xr(this.options.project,u);this.options.wal.setSourceCursor("memory.pipeline.version",2),this.options.wal.setSourceCursor("memory.pipeline.normalized_events",o.stats.normalizedEvents),this.options.wal.setSourceCursor("memory.pipeline.persisted",o.stats.persistedCandidates),this.options.wal.setSourceCursor("memory.pipeline.permanent",o.stats.permanent),this.options.wal.setSourceCursor("memory.pipeline.task",o.stats.task),this.options.wal.setSourceCursor("memory.pipeline.session",o.stats.session),this.options.wal.setSourceCursor("memory.pipeline.transient",o.stats.transient),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.version",o.hierarchy.version),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.raw",o.hierarchy.stats.raw),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.facts",o.hierarchy.stats.facts),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.scenes",o.hierarchy.stats.scenes),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.knowledge",o.hierarchy.stats.knowledge),this.options.wal.setSourceCursor("memory.pipeline.hierarchy.journal_written",c?1:0),this.options.wal.setSourceCursor("memory.skill.assets",u.length),this.options.wal.setSourceCursor("memory.skill.written",f.written),this.options.wal.setSourceCursor("memory.skill.deduped",f.deduped);try{let m=Ut(this.options.project.rootPath,s.events);this.options.wal.setSourceCursor("memory.context_offload.eligible",m.eligible),this.options.wal.setSourceCursor("memory.context_offload.written",m.written),this.options.wal.setSourceCursor("memory.context_offload.deduped",m.deduped),this.options.wal.setSourceCursor("memory.context_offload.graph_nodes",m.graphNodes),this.options.wal.setSourceCursor("memory.context_offload.failed",0)}catch{this.options.wal.setSourceCursor("memory.context_offload.failed",1)}try{let m=await fr({project:this.options.project,storage:this.options.storage,hierarchy:o.hierarchy});this.options.wal.setSourceCursor("memory.wiki_automation.scanned",m.scanned),this.options.wal.setSourceCursor("memory.wiki_automation.eligible",m.eligible),this.options.wal.setSourceCursor("memory.wiki_automation.created",m.created),this.options.wal.setSourceCursor("memory.wiki_automation.updated",m.updated),this.options.wal.setSourceCursor("memory.wiki_automation.unchanged",m.unchanged),this.options.wal.setSourceCursor("memory.wiki_automation.skipped",m.skipped),this.options.wal.setSourceCursor("memory.wiki_automation.failed",m.failed),this.options.wal.setSourceCursor("memory.wiki_automation.review_pending",m.reviewPending),this.options.wal.setSourceCursor("memory.wiki_automation.auto_approved",m.autoApproved),this.options.wal.setSourceCursor("memory.wiki_automation.review_approved",m.reviewApproved)}catch{this.options.wal.setSourceCursor("memory.wiki_automation.failed",1)}return this.options.wal.setSourceCursor("memory.learner.offset",s.nextOffset),{scannedEvents:s.events.length,candidates:i.length,journalWritten:a,nextOffset:s.nextOffset}}};import{closeSync as oc,existsSync as ic,openSync as ac,readSync as cc,statSync as uc}from"node:fs";function Ir(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function be(e){return e.toLowerCase().replace(/[^a-z0-9]/gu,"")}function ve(e,t,n=0){if(n>8)return;if(Array.isArray(e)){for(let s of e.slice(0,50))ve(s,t,n+1);return}let r=Ir(e);if(r)for(let[s,o]of Object.entries(r))t(s,o,r),ve(o,t,n+1)}function re(e,t){let n=[];return ve(e,(r,s)=>{t.has(be(r))&&typeof s=="string"&&s.trim()&&n.push(s.trim())}),n}function Da(e){let t=e.trim();if(!t.startsWith("{"))return null;try{return Ir(JSON.parse(t))}catch{return null}}function qa(e){let t=e.data;for(let r of["tool","toolName","tool_name"]){let s=t[r];if(typeof s=="string"&&s.trim())return s.trim().toLowerCase()}let n="";return ve(t,(r,s,o)=>{if(n)return;let i=be(r);if(["tool","toolname"].includes(i)&&typeof s=="string"){n=s.trim().toLowerCase();return}if(i!=="name"||typeof s!="string")return;let a=typeof o.type=="string"?o.type.toLowerCase():"";(a.includes("tool")||a.includes("function")||a.includes("command"))&&(n=s.trim().toLowerCase())}),n}function Ha(e){let t=re(e.data,new Set(["command","cmd","script"])),n=re(e.data,new Set(["arguments","args"]));for(let r of n){let s=Da(r);if(s)for(let o of re(s,new Set(["command","cmd","script"])))t.push(o)}return Array.from(new Set(t.map(r=>r.trim()).filter(Boolean)))}function Va(e){let t=re(e.data,new Set(["filepath","file_path","filename","file","path","target"].map(be)));return Array.from(new Set(t.map(n=>n.trim()).filter(n=>n.length>0&&n.length<1e3&&!n.includes(`
|
|
52
|
+
`))))}function Ja(e,t){return e.type==="file_edit"||e.type==="file_write"?"modified":/\b(delete|remove|unlink)\b/iu.test(t)?"deleted":/\b(create|add[_-]?file|new[_-]?file)\b/iu.test(t)?"created":/\b(edit|write|patch|apply[_-]?patch|replace|update[_-]?file)\b/iu.test(t)?"modified":null}function Ba(e){let t=re(e.data,new Set(["patch","diff","arguments","input"].map(be))),n=[];for(let r of t){let s=[{regex:/^\*\*\* Update File:\s*(.+)$/gimu,action:"modified"},{regex:/^\*\*\* Add File:\s*(.+)$/gimu,action:"created"},{regex:/^\*\*\* Delete File:\s*(.+)$/gimu,action:"deleted"}];for(let o of s)for(let i of r.matchAll(o.regex)){let a=i[1]?.trim();a&&n.push({kind:"file",text:a,fileAction:o.action,confidence:.99})}}return n}function Ga(e){let t=e.toLowerCase();return/\b(typecheck|type-check)\b/u.test(t)||/\btsc\b[\s\S]*--noemit\b/u.test(t)?"typecheck":/\b(eslint|lint)\b/u.test(t)?"lint":/\b(vitest|jest|pytest)\b/u.test(t)||/\bgo\s+test\b/u.test(t)||/\bcargo\s+test\b/u.test(t)||/\b(npm|pnpm|yarn)\s+(run\s+)?test\b/u.test(t)?"test":/\b(npm|pnpm|yarn)\s+(run\s+)?build\b/u.test(t)||/\bcargo\s+build\b/u.test(t)||/\bgo\s+build\b/u.test(t)||/\btsc\b/u.test(t)?"build":null}function Ua(e){let t=null;return ve(e,(n,r)=>{if(t===null&&["exitcode","code"].includes(be(n))){if(typeof r=="number"&&Number.isFinite(r)){t=r;return}if(typeof r=="string"){let s=Number(r);Number.isFinite(s)&&(t=s)}}}),t}function Ya(e){return re(e,new Set(["status","state","result","output","outputsummary","message","text"]))}function Xa(e){let t=Ua(e.data);if(t!==null)return t===0?"passed":"failed";let n=Ya(e.data).join(`
|
|
53
|
+
`).toLowerCase();return/\b(error|failed|failure|failing)\b/u.test(n)&&!/\b0\s+failed\b/u.test(n)?"failed":/\b(success|successful|completed|passed|green)\b/u.test(n)||/\b\d+\s+passed\b/u.test(n)?"passed":/\b(running|started|in[_ -]?progress)\b/u.test(n)?"running":"unknown"}function Qa(e){let t=[],n=new Set;for(let r of e){let s=[r.kind,r.fileAction??"",r.checkKind??"",r.checkStatus??"",r.text].join("|");n.has(s)||(n.add(s),t.push(r))}return t}function Cr(e){let t=[],n=qa(e),r=Ja(e,n);if(r)for(let s of Va(e))t.push({kind:"file",text:s,fileAction:r,confidence:e.type==="file_edit"||e.type==="file_write"?1:.96});t.push(...Ba(e));for(let s of Ha(e)){t.push({kind:"command",text:s,confidence:.98});let o=Ga(s);o&&t.push({kind:"test",text:s,checkKind:o,checkStatus:Xa(e),confidence:.98})}return Qa(t)}var Za=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function Z(e){return e.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function Mr(e){return Z(e).toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function Q(e,t,n=0){if(!(n>6)){if(typeof e=="string"){t.push(e);return}if(Array.isArray(e)){for(let r of e.slice(0,50))Q(r,t,n+1);return}if(!(!e||typeof e!="object"))for(let[r,s]of Object.entries(e))(Za.has(r)||["data","payload","parts","messages"].includes(r))&&Q(s,t,n+1)}}function Ge(e){return/\b(cancelled|canceled)\b|đã hủy|bỏ qua/iu.test(e)?"cancelled":/\b(blocked|blocker)\b|đang vướng|bị vướng|đang kẹt|chưa thể/iu.test(e)?"blocked":/\b(completed|complete|done|finished|passed)\b|hoàn thành|hoàn tất|đã xong|đã làm xong|\bxong\b/iu.test(e)?"completed":/\bin[\s_-]*progress\b|working on|đang làm|đang thực hiện|đang xử lý|đang triển khai/iu.test(e)?"in_progress":"pending"}function Pr(e){let t=Z(e);return/^(?:đang\s+làm|đang\s+thực\s+hiện|đang\s+xử\s+lý|đang\s+triển\s+khai|hoàn\s+thành|hoàn\s+tất|đã\s+xong|đã\s+làm\s+xong|xong|pending|in[\s_-]*progress|completed|complete|done|finished|blocked|cancelled|canceled)[.!]*$/iu.test(t)}function A(e,t,n,r,s={}){let o=Z(r),i=s.key??Mr(o);return{version:1,id:w([e.projectId,n,i,t.id,o,s.status??"",s.fileAction??"",s.checkKind??"",s.checkStatus??"",s.order??""].join("|")).slice(0,32),projectId:e.projectId,kind:n,key:i,text:o,status:s.status,fileAction:s.fileAction,checkKind:s.checkKind,checkStatus:s.checkStatus,order:s.order,confidence:s.confidence??.85,occurredAt:t.timestamp,sequence:t.sequence,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,eventId:t.id,sourceEventId:t.sourceEventId}}function ec(e,t,n){let r=Z(n);if(r.length<5||r.length>1200)return[];let s=[],o=/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r),i=r.match(/^(?:mục tiêu|goal|objective)\s*(?::|-)\s*(.+)$/iu);i?.[1]&&s.push(A(e,t,"goal",i[1],{confidence:.97}));let a=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);a?.[1]&&s.push(A(e,t,"plan",a[1],{confidence:.95}));let c=/\b(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?([^.;\n]{0,220})/giu,u;for(;!o&&(u=c.exec(r));){let d=Number(u[1]),l=Z(u[2]??""),g=l&&!Pr(l)?`Phase ${d} - ${l}`:`Phase ${d}`;s.push(A(e,t,"phase",g,{key:`phase:${d}`,order:d,status:Ge(r),confidence:.93}))}let f=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);f?.[2]&&s.push(A(e,t,"task",f[2],{status:f[1].trim()?"completed":Ge(f[2]),confidence:.96}));let m=r.match(/^(?:todo|task|việc)\s*(\d+)?(?:\s*[:.\-–—]\s*|\s+)(.+)$/iu);if(m?.[2]){let d=m[1]?Number(m[1]):void 0,l=Z(m[2]),g=Pr(l);s.push(A(e,t,"task",g&&d!==void 0?`TODO ${d}`:l,{key:d!==void 0?`task:${d}`:Mr(l),order:d,status:Ge(r),confidence:.93}))}if(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r)){let d=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");d&&s.push(A(e,t,"next_action",d,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(A(e,t,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(A(e,t,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(A(e,t,"decision",r,{confidence:.9})),r.length<=300&&/^(?:đang\s+(?:sửa|cập nhật|triển khai|xử lý|làm|refactor|fix)|(?:i(?:'m| am)\s+)?(?:working on|implementing|fixing|refactoring|updating|editing)\b)/iu.test(r)&&s.push(A(e,t,"activity",r,{confidence:.86})),s}function Ue(e,t){if(t.length===0)return[];let n=[],r=new Set;function s(i){r.has(i.id)||(r.add(i.id),n.push(i))}for(let i of t){if(i.type==="user_prompt"||i.role==="user"){let c=[];Q(i.data,c);let u=c.map(f=>Z(f)).find(f=>f.length>=8&&f.length<=1200&&!/^\[?toolnet\b/iu.test(f));u&&s(A(e,i,"request",u,{confidence:.96}))}for(let c of Cr(i))s(A(e,i,c.kind,c.text,{fileAction:c.fileAction,checkKind:c.checkKind,checkStatus:c.checkStatus,status:c.kind==="test"?c.checkStatus==="passed"?"completed":c.checkStatus==="failed"?"blocked":c.checkStatus==="running"?"in_progress":"pending":void 0,confidence:c.confidence}));if(i.type==="decision"){let c=[];Q(i.data,c);for(let u of c)s(A(e,i,"decision",u,{confidence:1}))}if(i.type==="todo"){let c=[];Q(i.data,c);for(let u of c)s(A(e,i,"task",u,{status:Ge(u),confidence:1}))}if(["file_write","file_edit"].includes(i.type))for(let c of["filePath","path","file"]){let u=i.data[c];typeof u=="string"&&u&&s(A(e,i,"file",u,{fileAction:"modified",confidence:1}))}if(i.type==="test"){let c=[];Q(i.data,c);for(let u of c)s(A(e,i,"test",u,{confidence:1}))}let a=[];Q(i.data,a);for(let c of a)for(let u of c.split(/\n+/u))for(let f of ec(e,i,u))s(f)}let o=t[t.length-1];return s(A(e,o,"session",`${e.agent}:${e.nativeSessionId}`,{key:e.sessionKey,confidence:1})),n}function Er(e){return String(e).padStart(12,"0")}var Ye=class{constructor(t){this.storage=t}storage;async write(t,n){if(n.length===0)return null;let r=Math.min(...n.map(u=>u.sequence)),s=Math.max(...n.map(u=>u.sequence)),o={version:1,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,createdAt:new Date().toISOString(),firstSequence:r,lastSequence:s,observations:n},i=JSON.stringify(o,null,2)+`
|
|
54
|
+
`,a=w(n.map(u=>u.id).sort().join("|")).slice(0,16),c=[`projects/${t.projectId}`,"work","observations",t.agent,t.nativeSessionId,`${Er(r)}-${Er(s)}-${a}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,i,"application/json"),c}};import{join as Tr}from"node:path";import{mkdirSync as tc}from"node:fs";function Rr(e){return e.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function K(e,t=20){let n=[],r=new Set;for(let s of e.slice().reverse()){let o=Rr(s);if(!(!o||r.has(o))&&(r.add(o),n.push(s),n.length>=t))break}return n.reverse()}function nc(e,t=20){let n=new Map;for(let r of e){let s=`${r.kind}|${Rr(r.command)}`;n.delete(s),n.set(s,r)}return Array.from(n.values()).slice(-t)}function rc(e){return e.kind==="phase"?/^Phase\s+\d+$/iu.test(e.text):e.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(e.text):!1}function Or(e,t){let n=t.status??e?.status??"pending",r=n;e&&(e.status==="completed"&&n!=="completed"?r="completed":n==="pending"&&(e.status==="in_progress"||e.status==="blocked")&&(r=e.status));let s=e&&rc(t)?e.title:t.text;return{id:e?.id??w(t.key).slice(0,24),title:s,status:r,order:t.order??e?.order,confidence:Math.max(t.confidence,e?.confidence??0),updatedAt:t.occurredAt,updatedBy:{agent:t.agent,nativeSessionId:t.nativeSessionId,eventId:t.eventId}}}async function sc(e,t){let n=`projects/${e.id}/work/observations/`,r=await t.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await t.getText(o.key);if(i)try{let a=JSON.parse(i);a.version===1&&Array.isArray(a.observations)&&s.push(a)}catch{}}return s}async function Xe(e,t){let r=(await sc(e,t)).flatMap(p=>p.observations).sort((p,b)=>{let D=p.occurredAt.localeCompare(b.occurredAt);if(D!==0)return D;let zt=p.sequence-b.sequence;return zt!==0?zt:p.id.localeCompare(b.id)}),s=new Map,o=new Map,i,a,c,u,f,m=[],d=[],l=[],g=[],S=[],y=new Map,h=[],k=[],C=[],M=[],I=[],E=[];for(let p of r)switch(p.kind){case"request":i=p.text;break;case"activity":a=p.text;break;case"goal":c=p.text;break;case"plan":u=p.text;break;case"phase":s.set(p.key,Or(s.get(p.key),p));break;case"task":o.set(p.key,Or(o.get(p.key),p));break;case"decision":m.push(p.text);break;case"blocker":d.push(p.text);break;case"warning":l.push(p.text);break;case"next_action":g.push(p.text);break;case"file":{S.push(p.text);let b=p.fileAction??"active";y.delete(p.text),y.set(p.text,b),b==="modified"?h.push(p.text):b==="created"?k.push(p.text):b==="deleted"&&C.push(p.text);break}case"command":M.push(p.text);break;case"test":I.push(p.text),p.checkKind&&E.push({kind:p.checkKind,command:p.text,status:p.checkStatus??"unknown",updatedAt:p.occurredAt,agent:p.agent,nativeSessionId:p.nativeSessionId});break;case"session":f={agent:p.agent,nativeSessionId:p.nativeSessionId,sessionKey:p.sessionKey,updatedAt:p.occurredAt};break}let x=Array.from(s.values()).sort((p,b)=>(p.order??Number.MAX_SAFE_INTEGER)-(b.order??Number.MAX_SAFE_INTEGER)),v=Array.from(o.values()).sort((p,b)=>(p.order??Number.MAX_SAFE_INTEGER)-(b.order??Number.MAX_SAFE_INTEGER)),F=x.find(p=>p.status==="in_progress")??x.find(p=>p.status==="blocked")??x.find(p=>p.status==="pending"),L=v.find(p=>p.status==="in_progress")??v.find(p=>p.status==="blocked")??v.find(p=>p.status==="pending"),at=K([...g,...L?[L.title]:[],...!L&&F?[F.title]:[],...v.filter(p=>p.status==="pending").slice(0,5).map(p=>p.title)],8),ct=K([...d,...x.filter(p=>p.status==="blocked").map(p=>p.title),...v.filter(p=>p.status==="blocked").map(p=>p.title)],20),oe={version:1,projectId:e.id,projectName:e.name,currentRequest:i,currentActivity:a,goal:c,plan:u,phases:x,tasks:v,decisions:K(m,20),blockers:ct,warnings:K(l,20),nextActions:at,filesTouched:K(S,30),activeFiles:Array.from(y.entries()).filter(([,p])=>p!=="deleted").map(([p])=>p).slice(-5),modifiedFiles:K(h,30),createdFiles:K(k,30),deletedFiles:K(C,30),commands:K(M,20),tests:K(I,20),checks:nc(E,20),currentPhase:F,currentTask:L,progress:{phasesTotal:x.length,phasesCompleted:x.filter(p=>p.status==="completed").length,tasksTotal:v.length,tasksCompleted:v.filter(p=>p.status==="completed").length,blocked:x.filter(p=>p.status==="blocked").length+v.filter(p=>p.status==="blocked").length},lastSession:f,updatedAt:r.length?r[r.length-1].occurredAt:new Date().toISOString()},ie=Tr(e.rootPath,".toolnet","work");return tc(ie,{recursive:!0}),T(Tr(ie,"current.json"),oe),await t.put(`projects/${e.id}/work/current.json`,JSON.stringify(oe,null,2)+`
|
|
55
|
+
`,"application/json"),oe}async function Nr(e,t){let n=await t.getText(`projects/${e.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function lc(e,t){if(!ic(e))return{events:[],nextOffset:t};let n=uc(e).size,r=Number.isFinite(t)?Math.max(0,t):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=ac(e,"r");try{cc(i,o,0,s,r)}finally{oc(i)}let a=o.toString("utf8"),c=a.lastIndexOf(`
|
|
56
|
+
`);if(c<0)return{events:[],nextOffset:r};let u=a.slice(0,c+1);return{events:u.split(`
|
|
57
|
+
`).filter(Boolean).flatMap(m=>{try{return[JSON.parse(m)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(u,"utf8")}}var Qe=class{constructor(t){this.options=t;this.journal=new Ye(t.storage)}options;journal;async learnNew(){let t=this.options.wal.loadState(),n=Number(t.sourceCursors["work.continuity.offset"]??0),r=lc(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=Ue(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await Xe(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.continuity.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{closeSync as kc,existsSync as wc,openSync as vc,readSync as bc,statSync as xc}from"node:fs";var dc=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function se(e){return e.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function Mt(e,t,n=0){if(!(n>6)){if(typeof e=="string"){t.push(e);return}if(Array.isArray(e)){for(let r of e.slice(0,50))Mt(r,t,n+1);return}if(!(!e||typeof e!="object"))for(let[r,s]of Object.entries(e))(dc.has(r)||["data","payload","parts","messages"].includes(r))&&Mt(s,t,n+1)}}function R(e,t,n,r,s,o=.95){let i=se(r);return{version:1,id:w([e.projectId,n,s.type,s.key??"",i.toLowerCase(),t.id].join("|")).slice(0,32),projectId:e.projectId,kind:n,value:i,scope:s.type,scopeKey:s.key,scopeOrder:s.order,confidence:o,evidence:{agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,eventId:t.id,sourceEventId:t.sourceEventId,sequence:t.sequence,occurredAt:t.timestamp}}}function $(e,t){let n=e.toLowerCase();for(let r of t){let s=r.toLowerCase();if(n.startsWith(`${s}:`)||n.startsWith(`${s} -`)||n.startsWith(`${s} \u2014`))return se(e.slice(r.length+1))}return null}function pc(e){let t=e.trimStart();return t.startsWith("- ")||t.startsWith("* ")||/^\d+[.)]\s+/u.test(t)}function mc(e){return se(e.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function _r(e,t){let n=[],r=new Set;function s(o){!o.value||o.value.length<3||r.has(o.id)||(r.add(o.id),n.push(o))}for(let o of t){let i=[];Mt(o.data,i);for(let a of i){let c={type:"project"},u=null;for(let f of a.split(/\r?\n/u)){let m=se(f);if(!m){u=null;continue}let d=m.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(d){let v=Number(d[1]);c={type:"phase",key:`phase:${v}`,order:v,title:se(d[2]??"")},u=null;continue}let l=m.match(/^(?:todo|task|việc)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(l){let v=Number(l[1]);c={type:"task",key:`task:${v}`,order:v,title:se(l[2]??"")},u=null;continue}let g=$(m,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(g){s(R(e,o,"mission",g,{type:"project"},.99)),u=null;continue}let S=$(m,["current objective","active objective","m\u1EE5c ti\xEAu hi\u1EC7n t\u1EA1i","objective","m\u1EE5c ti\xEAu","m\u1EE5c \u0111\xEDch"]);if(S){s(R(e,o,c.type==="phase"?"phase_objective":"objective",S,c,.98)),u=null;continue}let y=$(m,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(y){s(R(e,o,c.type==="phase"?"phase_why":"why",y,c,.98)),u=null;continue}let h=$(m,["desired outcome","final outcome","k\u1EBFt qu\u1EA3 cu\u1ED1i","k\u1EBFt qu\u1EA3 mong mu\u1ED1n","m\u1EE5c ti\xEAu cu\u1ED1i"]);if(h){s(R(e,o,"desired_outcome",h,{type:"project"},.98)),u=null;continue}let k=$(m,["plan rationale","approach rationale","why this approach","t\u1EA1i sao ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn ki\u1EBFn tr\xFAc"]);if(k){s(R(e,o,"plan_rationale",k,{type:"project"},.98)),u=null;continue}let C=$(m,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(C){s(R(e,o,"phase_deliverable",C,c,.97)),u=null;continue}let M=$(m,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if(M){s(R(e,o,"acceptance_criterion",M,c,.98)),u="acceptance_criterion";continue}let I=$(m,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(I){s(R(e,o,"dependency",I,c,.97)),u="dependency";continue}let E=$(m,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(E){s(R(e,o,"open_question",E,c,.95)),u="open_question";continue}let x=$(m,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(x){s(R(e,o,"constraint",x,c,.97)),u="constraint";continue}if(/^(?:acceptance criteria|definition of done|done khi|tiêu chí hoàn thành)\s*:?\s*$/iu.test(m)){u="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(m)){u="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(m)){u="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(m)){u="constraint";continue}if(u&&pc(f)){s(R(e,o,u,mc(f),c,.96));continue}u=null}}}return n}function Kr(e){return String(e).padStart(12,"0")}var Ze=class{constructor(t){this.storage=t}storage;async write(t,n){if(n.length===0)return null;let r=Math.min(...n.map(c=>c.evidence.sequence)),s=Math.max(...n.map(c=>c.evidence.sequence)),o={version:1,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,firstSequence:r,lastSequence:s,createdAt:new Date().toISOString(),observations:n},i=w(n.map(c=>c.id).sort().join("|")).slice(0,16),a=[`projects/${t.projectId}`,"work","semantic","observations",t.agent,t.nativeSessionId,`${Kr(r)}-${Kr(s)}-${i}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,JSON.stringify(o,null,2)+`
|
|
58
|
+
`,"application/json"),a}};import{mkdirSync as fc}from"node:fs";import{join as $r}from"node:path";function gc(e){return{value:e.value,confidence:e.confidence,evidence:e.evidence}}function yc(e,t){if(!t)return!0;let n=e.evidence.occurredAt.localeCompare(t.evidence.occurredAt);return n!==0?n>0:e.evidence.sessionKey===t.evidence.sessionKey?e.evidence.sequence>=t.evidence.sequence:e.confidence>=t.confidence}function V(e,t){return yc(t,e)?t:e}function J(e,t=30){let n=new Set,r=[];for(let s of e){let o=s.value.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim();!o||n.has(o)||(n.add(o),r.push(s))}return r.slice(-t)}async function hc(e,t){let n=`projects/${e.id}/work/semantic/observations/`,r=await t.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await t.getText(o.key);if(i)try{let a=JSON.parse(i);a.version===1&&Array.isArray(a.observations)&&s.push(a)}catch{}}return s}function Sc(e){return{key:e.scopeKey??`phase:${e.scopeOrder??0}`,order:e.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function Wr(e,t){let r=(await hc(e,t)).flatMap(S=>S.observations).sort((S,y)=>{let h=S.evidence.occurredAt.localeCompare(y.evidence.occurredAt);return h!==0?h:S.evidence.sessionKey===y.evidence.sessionKey?S.evidence.sequence-y.evidence.sequence:S.id.localeCompare(y.id)}),s,o,i,a,c,u=new Map,f=[],m=[],d=[];for(let S of r){let y=gc(S);if(S.scope==="phase"&&S.scopeKey){let h=u.get(S.scopeKey)??Sc(S);switch(S.kind){case"phase_objective":h.objective=V(h.objective,y);break;case"phase_why":h.why=V(h.why,y);break;case"phase_deliverable":h.deliverable=V(h.deliverable,y);break;case"acceptance_criterion":h.acceptanceCriteria.push(y);break;case"dependency":h.dependencies.push(y);break;case"open_question":h.openQuestions.push(y);break;case"constraint":h.constraints.push(y);break;case"note":h.notes.push(y);break}u.set(h.key,h);continue}switch(S.kind){case"mission":s=V(s,y);break;case"objective":o=V(o,y);break;case"why":i=V(i,y);break;case"desired_outcome":a=V(a,y);break;case"plan_rationale":c=V(c,y);break;case"open_question":f.push(y);break;case"constraint":m.push(y);break;case"note":d.push(y);break}}for(let S of u.values())S.acceptanceCriteria=J(S.acceptanceCriteria,20),S.dependencies=J(S.dependencies,15),S.openQuestions=J(S.openQuestions,15),S.constraints=J(S.constraints,15),S.notes=J(S.notes,20);let l={version:1,projectId:e.id,projectName:e.name,mission:s,activeObjective:o,why:i,desiredOutcome:a,planRationale:c,phases:Array.from(u.values()).sort((S,y)=>S.order-y.order),openQuestions:J(f,20),constraints:J(m,20),notes:J(d,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},g=$r(e.rootPath,".toolnet","work");return fc(g,{recursive:!0}),T($r(g,"semantic-current.json"),l),await t.put(`projects/${e.id}/work/semantic/current.json`,JSON.stringify(l,null,2)+`
|
|
59
|
+
`,"application/json"),l}function jc(e,t){if(!wc(e))return{events:[],nextOffset:t};let n=xc(e).size,r=Number.isFinite(t)?Math.max(0,t):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=Buffer.alloc(n-r),o=vc(e,"r");try{bc(o,s,0,s.length,r)}finally{kc(o)}let i=s.toString("utf8"),a=i.lastIndexOf(`
|
|
60
|
+
`);if(a<0)return{events:[],nextOffset:r};let c=i.slice(0,a+1);return{events:c.split(`
|
|
61
|
+
`).filter(Boolean).flatMap(u=>{try{return[JSON.parse(u)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var et=class{constructor(t){this.options=t;this.journal=new Ze(t.storage)}options;journal;async learnNew(){let t=this.options.wal.loadState(),n=Number(t.sourceCursors["work.semantic.offset"]??0),r=jc(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=_r(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await Wr(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.semantic.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{existsSync as Jc,mkdirSync as Bc}from"node:fs";import{join as Tt}from"node:path";import{existsSync as zr,mkdirSync as Ac,readFileSync as Ic,statSync as Fr,writeFileSync as Cc}from"node:fs";import{dirname as Pc,join as Mc}from"node:path";var Lr=64*1024,Ec=`# ToolNet Project Operating Manual
|
|
62
|
+
|
|
63
|
+
This file contains persistent instructions for AI agents working on this project.
|
|
64
|
+
|
|
65
|
+
## Critical Rules
|
|
66
|
+
|
|
67
|
+
<!--
|
|
68
|
+
Examples:
|
|
69
|
+
|
|
70
|
+
- [enforce] Never edit production files directly.
|
|
71
|
+
- [enforce] Edit source only in /path/to/source.
|
|
72
|
+
- [enforce] Deploy only with ./deploy.sh --apply
|
|
73
|
+
-->
|
|
74
|
+
|
|
75
|
+
## Workflow
|
|
76
|
+
|
|
77
|
+
<!--
|
|
78
|
+
Describe the correct working process.
|
|
79
|
+
-->
|
|
80
|
+
|
|
81
|
+
## Architecture
|
|
82
|
+
|
|
83
|
+
<!--
|
|
84
|
+
Important architecture conventions.
|
|
85
|
+
-->
|
|
86
|
+
|
|
87
|
+
## Verification
|
|
88
|
+
|
|
89
|
+
<!--
|
|
90
|
+
Tests / QA required after changes.
|
|
91
|
+
-->
|
|
92
|
+
|
|
93
|
+
## Known Gotchas
|
|
94
|
+
|
|
95
|
+
<!--
|
|
96
|
+
Things an AI agent should always remember.
|
|
97
|
+
-->
|
|
98
|
+
|
|
99
|
+
## Preferences
|
|
100
|
+
|
|
101
|
+
<!--
|
|
102
|
+
- [advisory] Prefer small focused files.
|
|
103
|
+
-->
|
|
104
|
+
`;function Dr(e){return Mc(e.rootPath,".toolnet","PROJECT.md")}function Tc(e){return e.normalize("NFKC").replace(/\s+/g," ").trim()}function Oc(e){let t=[],n=new Set,r=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=r.exec(e);){let o=s[1].toLowerCase(),i=Tc(s[2]);if(!i)continue;let a=`${o}:${i.toLowerCase()}`;n.has(a)||(n.add(a),t.push({id:w(a).slice(0,24),mode:o,text:i,source:"manual"}))}return t}function Rc(e){let t=Dr(e);return zr(t)||(Ac(Pc(t),{recursive:!0}),Cc(t,Ec,{encoding:"utf8",mode:384})),t}function qr(e,t=!1){let n=t?Rc(e):Dr(e);if(!zr(n))return null;if(Fr(n).size>Lr)throw new Error(`PROJECT.md exceeds ${Lr} bytes`);let s=Ic(n,"utf8");return{path:n,content:s,digest:w(s),rules:Oc(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(Fr(n).mtimeMs).toISOString()}}import{existsSync as Nc,mkdirSync as _c,readFileSync as Kc,renameSync as $c,writeFileSync as Wc}from"node:fs";import{dirname as Fc,join as Lc}from"node:path";function zc(e,t){_c(Fc(e),{recursive:!0});let n=`${e}.tmp-${process.pid}-${Date.now()}`;Wc(n,`${JSON.stringify(t,null,2)}
|
|
105
|
+
`,{encoding:"utf8",mode:384}),$c(n,e)}function Ur(e){return Lc(e.rootPath,".toolnet","work","current.json")}function Et(e){let t=Ur(e);if(!Nc(t))return null;try{let n=JSON.parse(Kc(t,"utf8"));return n.version!==1||n.projectId!==e.id?null:n}catch{return null}}function tt(e){return e.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function N(e,t,n){let r=[],s=new Set;for(let o of[...e,...t].reverse()){let i=tt(o);if(!(!i||s.has(i))&&(s.add(i),r.push(o),r.length>=n))break}return r.reverse()}function Dc(e,t,n=20){let r=new Map;for(let s of[...e,...t]){let o=`${s.kind}|${tt(s.command)}`;r.delete(o),r.set(o,s)}return Array.from(r.values()).slice(-n)}function qc(e){return e.kind==="phase"?/^Phase\s+\d+$/iu.test(e.text):e.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(e.text):!1}function Hr(e,t){let n=t.status??e?.status??"pending",r=n;e?.status==="completed"&&n!=="completed"&&(r="completed"),e&&n==="pending"&&(e.status==="in_progress"||e.status==="blocked")&&(r=e.status);let s=e&&qc(t)?e.title:t.text;return{id:e?.id??t.id,title:s,status:r,order:t.order??e?.order,confidence:Math.max(e?.confidence??0,t.confidence),updatedAt:t.occurredAt,updatedBy:{agent:t.agent,nativeSessionId:t.nativeSessionId,eventId:t.eventId}}}function Vr(e){let t=new Map;for(let n of e){let r=n.order!==void 0?`order:${n.order}`:tt(n.title);t.set(r,n)}return t}function Jr(e){return e.order!==void 0?`order:${e.order}`:tt(e.key||e.text)}function Br(e){return Array.from(e).sort((t,n)=>{let r=t.order??Number.MAX_SAFE_INTEGER,s=n.order??Number.MAX_SAFE_INTEGER;return r!==s?r-s:t.updatedAt.localeCompare(n.updatedAt)})}function Gr(e){return e.find(t=>t.status==="in_progress")??e.find(t=>t.status==="blocked")??e.find(t=>t.status==="pending")}function Yr(e,t){let n=Et(e),r=Vr(n?.phases??[]),s=Vr(n?.tasks??[]),o=n?.currentRequest,i=n?.currentActivity,a=n?.goal,c=n?.plan,u=n?.lastSession,f=[],m=[],d=[],l=[],g=[],S=[...n?.activeFiles??[]],y=[],h=[],k=[],C=[],M=[],I=[],E=[...t].sort((p,b)=>{let D=p.occurredAt.localeCompare(b.occurredAt);return D!==0?D:p.sequence-b.sequence});for(let p of E)switch(p.kind){case"request":o=p.text;break;case"activity":i=p.text;break;case"goal":a=p.text;break;case"plan":c=p.text;break;case"phase":{let b=Jr(p);r.set(b,Hr(r.get(b),p));break}case"task":{let b=Jr(p);s.set(b,Hr(s.get(b),p));break}case"decision":f.push(p.text);break;case"blocker":m.push(p.text);break;case"warning":d.push(p.text);break;case"next_action":l.push(p.text);break;case"file":{g.push(p.text);let b=p.fileAction??"active",D=S.indexOf(p.text);D>=0&&S.splice(D,1),b!=="deleted"&&S.push(p.text),b==="modified"?y.push(p.text):b==="created"?h.push(p.text):b==="deleted"&&k.push(p.text);break}case"command":C.push(p.text);break;case"test":M.push(p.text),p.checkKind&&I.push({kind:p.checkKind,command:p.text,status:p.checkStatus??"unknown",updatedAt:p.occurredAt,agent:p.agent,nativeSessionId:p.nativeSessionId});break;case"session":u={agent:p.agent,nativeSessionId:p.nativeSessionId,sessionKey:p.sessionKey,updatedAt:p.occurredAt};break}let x=Br(r.values()),v=Br(s.values()),F=Gr(x),L=Gr(v),at=N(n?.nextActions??[],[...l,...L?[L.title]:[],...!L&&F?[F.title]:[],...v.filter(p=>p.status==="pending").slice(0,5).map(p=>p.title)],8),ct=N(n?.blockers??[],[...m,...x.filter(p=>p.status==="blocked").map(p=>p.title),...v.filter(p=>p.status==="blocked").map(p=>p.title)],20),oe=E.length>0?E[E.length-1].occurredAt:n?.updatedAt??new Date().toISOString(),ie={version:1,projectId:e.id,projectName:e.name,currentRequest:o,currentActivity:i,goal:a,plan:c,phases:x,tasks:v,decisions:N(n?.decisions??[],f,20),blockers:ct,warnings:N(n?.warnings??[],d,20),nextActions:at,filesTouched:N(n?.filesTouched??[],g,30),activeFiles:N([],S,5),modifiedFiles:N(n?.modifiedFiles??[],y,30),createdFiles:N(n?.createdFiles??[],h,30),deletedFiles:N(n?.deletedFiles??[],k,30),commands:N(n?.commands??[],C,20),tests:N(n?.tests??[],M,20),checks:Dc(n?.checks??[],I,20),currentPhase:F,currentTask:L,progress:{phasesTotal:x.length,phasesCompleted:x.filter(p=>p.status==="completed").length,tasksTotal:v.length,tasksCompleted:v.filter(p=>p.status==="completed").length,blocked:x.filter(p=>p.status==="blocked").length+v.filter(p=>p.status==="blocked").length},lastSession:u,updatedAt:oe};return zc(Ur(e),ie),ie}function P(e,t){let n=new Set,r=[];for(let s of e){let o=s.replace(/\s+/g," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();if(!n.has(i)&&(n.add(i),r.push(o),r.length>=t))break}return r}function Xr(e){if(e)return{id:e.id,title:e.title,status:e.status}}function Hc(e,t=[]){let n=t.slice(-10);if(n.some(s=>s.status==="failed"))return"failing";if(n.some(s=>s.status==="passed"))return"passing";let r=e.slice(-10).join(`
|
|
106
|
+
`).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(r)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(r)?"passing":"unknown"}function Vc(e){return w(JSON.stringify(e))}function Qr(e){let{project:t,identity:n,state:r}=e,s=r.activeFiles?.at(-1)??r.filesTouched.at(-1),o=r.phases.filter(k=>k.status==="completed").map(k=>k.title),i=r.tasks.filter(k=>k.status==="completed").map(k=>k.title),a=r.phases.filter(k=>k.status!=="completed"&&k.status!=="cancelled").map(k=>k.title),c=r.tasks.filter(k=>k.status!=="completed"&&k.status!=="cancelled").map(k=>k.title),u=new Set(r.tasks.filter(k=>k.status==="completed").map(k=>k.title.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),f=P(r.nextActions.filter(k=>!u.has(k.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),10),m=P([...c,...f],15),d=P(r.tests.slice().reverse(),10),l=P([...(r.activeFiles??[]).slice().reverse(),...r.filesTouched.slice().reverse()],20),g={schema:"toolnet.handoff.v2",version:2,project:{id:t.id,name:t.name},source:{agent:n.agent,nativeSessionId:n.nativeSessionId,sessionKey:n.sessionKey,sequence:e.sequence,reason:e.reason},capturedAt:e.capturedAt??new Date().toISOString(),goal:r.goal,request:r.currentRequest,activity:r.currentActivity,current:{phase:Xr(r.currentPhase),task:Xr(r.currentTask),file:s},completed:{phases:P(o,20),tasks:P(i,30)},remaining:{phases:P(a,20),tasks:P(c,30),todos:m},nextAction:f[0],blockers:P(r.blockers.slice().reverse(),10),decisions:P(r.decisions.slice().reverse(),10),files:{current:s,recent:l,active:P(r.activeFiles??[],10),modified:P(r.modifiedFiles??[],20),created:P(r.createdFiles??[],20),deleted:P(r.deletedFiles??[],20)},tests:{status:Hc(r.tests,r.checks),recent:d,checks:(r.checks??[]).slice(-10).map(k=>({kind:k.kind,status:k.status,command:k.command}))},attention:P(e.attention??[],20),progress:r.progress},{capturedAt:S,source:y,...h}=g;return{...g,stateDigest:Vc(h)}}function Gc(e){return!!(e.currentRequest||e.currentActivity||e.goal||e.plan||e.phases.length>0||e.tasks.length>0||e.nextActions.length>0||e.blockers.length>0||e.decisions.length>0||e.filesTouched.length>0)}function Zr(e,t,n,r,s){if(!Gc(n))return null;let o=qr(e,!1),a=[...o?o.rules.filter(m=>m.mode==="enforce").map(m=>m.text):[],...n.warnings].slice(0,20),c=Qr({project:e,identity:t,state:n,reason:r,sequence:s,attention:a}),u=c.stateDigest;return{version:1,id:w([e.id,t.sessionKey,u].join("|")).slice(0,24),projectId:e.id,projectName:e.name,createdAt:new Date().toISOString(),reason:r,sourceSession:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,sequence:s},currentRequest:n.currentRequest,currentActivity:n.currentActivity,goal:n.goal,plan:n.plan,progress:n.progress,currentPhase:n.currentPhase,currentTask:n.currentTask,incompletePhases:n.phases.filter(m=>m.status!=="completed"&&m.status!=="cancelled"),incompleteTasks:n.tasks.filter(m=>m.status!=="completed"&&m.status!=="cancelled"),nextActions:c.remaining.todos.slice(0,10),blockers:n.blockers.slice(-10),decisions:n.decisions.slice(-10),warnings:n.warnings.slice(-10),attention:a,filesTouched:n.filesTouched.slice(-20),activeFiles:n.activeFiles?.slice(-10),modifiedFiles:n.modifiedFiles?.slice(-20),createdFiles:n.createdFiles?.slice(-20),deletedFiles:n.deletedFiles?.slice(-20),tests:n.tests.slice(-15),checks:n.checks?.slice(-10),stateDigest:u,continuity:c}}function es(e,t){let n=Tt(e.rootPath,".toolnet","work","handoffs");Bc(n,{recursive:!0});let r=Tt(n,`${t.id}.json`);Jc(r)||T(r,t),T(Tt(e.rootPath,".toolnet","work","handoff-latest.json"),t)}function ts(e){let t=Zr(e.project,e.identity,e.state,e.reason,e.sequence);return t?(es(e.project,t),t):null}var nt=class{constructor(t){this.options=t}options;async capture(t,n){let r=Et(this.options.project);r||(r=await Nr(this.options.project,this.options.storage)),r||(r=await Xe(this.options.project,this.options.storage));let s=Zr(this.options.project,this.options.identity,r,t,n);if(!s)return null;es(this.options.project,s);let o=`projects/${this.options.project.id}/work/handoffs/${s.id}.json`;return await this.options.storage.exists(o)||await this.options.storage.put(o,JSON.stringify(s,null,2)+`
|
|
107
|
+
`,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(s,null,2)+`
|
|
108
|
+
`,"application/json"),s}};import{existsSync as Uc,readFileSync as Yc,writeFileSync as Xc}from"node:fs";import{join as Qc}from"node:path";var rs="<!-- TOOLNET:STABLE-WORK:BEGIN -->",Ot="<!-- TOOLNET:STABLE-WORK:END -->";function Rt(e){switch(e.status){case"completed":return"[x]";case"in_progress":return"[~]";case"blocked":return"[!]";case"cancelled":return"[-]";default:return"[ ]"}}function W(e,t){return t.length?["",`${e}:`,...t.map(n=>`- ${n}`)]:[]}function ns(e,t){return t.length?["",`${e}:`,...t.map(n=>`- ${Rt(n)} ${n.title}`)]:[]}function Zc(e){let t=[rs,"# ToolNet Stable Work State","",`Updated: ${e.updatedAt}`];return e.lastSession&&t.push(`Last agent: ${e.lastSession.agent}`,`Last session: ${e.lastSession.nativeSessionId}`),e.currentRequest&&t.push("","Current request:",e.currentRequest),e.currentActivity&&t.push("","Current activity:",e.currentActivity),e.goal&&t.push("","Goal:",e.goal),e.plan&&t.push("","Plan:",e.plan),e.currentPhase&&t.push("","Current phase:",`${Rt(e.currentPhase)} ${e.currentPhase.title}`),e.currentTask&&t.push("","Current task:",`${Rt(e.currentTask)} ${e.currentTask.title}`),t.push(...ns("Phases",e.phases)),t.push(...ns("TODO / Tasks",e.tasks)),t.push(...W("Next actions",e.nextActions)),t.push(...W("Blockers",e.blockers)),t.push(...W("Important decisions",e.decisions)),t.push(...W("Active files",e.activeFiles??[])),t.push(...W("Modified files",e.modifiedFiles??[])),t.push(...W("Created files",e.createdFiles??[])),t.push(...W("Deleted files",e.deletedFiles??[])),t.push(...W("Files touched",e.filesTouched)),t.push(...W("Recent commands",e.commands??[])),t.push(...W("Checks",(e.checks??[]).map(n=>`[${n.status}] ${n.kind}: ${n.command}`))),t.push("","Progress:",`- Phases: ${e.progress.phasesCompleted}/${e.progress.phasesTotal}`,`- Tasks: ${e.progress.tasksCompleted}/${e.progress.tasksTotal}`,`- Blocked: ${e.progress.blocked}`,"","Continuation:","- Resume current unfinished task.","- Never redo completed TODO/Phase unless explicitly requested.","- Ask ToolNet Memory for deeper history only when necessary.",Ot),t.join(`
|
|
109
|
+
`)}function ss(e,t){let n=Qc(e.rootPath,".toolnet","current.md"),r="";if(Uc(n))try{r=Yc(n,"utf8")}catch{r=""}r=r.replace(/<!-- TOOLNET:AUTO-CURRENT:BEGIN -->[\s\S]*?<!-- TOOLNET:AUTO-CURRENT:END -->/gu,"");let s=Zc(t),o=r.indexOf(rs),i=r.indexOf(Ot),a;o>=0&&i>=o?a=[r.slice(0,o).trimEnd(),s,r.slice(i+Ot.length).trimStart()].filter(Boolean).join(`
|
|
110
|
+
|
|
111
|
+
`):a=r.trim()?`${r.trim()}
|
|
112
|
+
|
|
113
|
+
${s}`:s,Xc(n,`${a.trim()}
|
|
114
|
+
`,{encoding:"utf8",mode:384})}import{existsSync as os,mkdirSync as eu,readFileSync as tu}from"node:fs";import{join as Nt}from"node:path";function is(e){return Nt(e.rootPath,".toolnet","memory","checkpoints")}function as(e){return Nt(is(e),"latest.json")}function nu(e){let t=as(e);if(!os(t))return null;try{let n=JSON.parse(tu(t,"utf8"));return n.schema!=="toolnet.memory.checkpoint.v1"||n.project.id!==e.id?null:n}catch{return null}}function ru(e){return["rule","architecture","decision","fix"].includes(e)}function su(e,t){return t.length===0?[]:Fe(e,t).candidates.filter(r=>ru(r.kind)&&r.knowledgeClass!=="transient"&&r.importanceScore>=.65).map(r=>({fingerprint:r.fingerprint,kind:r.kind,content:r.content,knowledgeClass:r.knowledgeClass,importanceScore:r.importanceScore,confidence:r.confidence,createdAt:r.createdAt,agent:e.agent,nativeSessionId:e.nativeSessionId}))}function ou(e,t){let n=new Map;for(let r of[...e,...t]){let s=n.get(r.fingerprint);(!s||r.importanceScore>s.importanceScore)&&n.set(r.fingerprint,r)}return Array.from(n.values()).sort((r,s)=>s.importanceScore-r.importanceScore||s.createdAt.localeCompare(r.createdAt)).slice(0,80)}function iu(e){return{request:e.currentRequest,activity:e.currentActivity,goal:e.goal,phase:e.currentPhase?{title:e.currentPhase.title,status:e.currentPhase.status}:void 0,task:e.currentTask?{title:e.currentTask.title,status:e.currentTask.status}:void 0,phases:e.phases.map(t=>({title:t.title,status:t.status})),tasks:e.tasks.map(t=>({title:t.title,status:t.status})),activeFiles:e.activeFiles??[],modifiedFiles:e.modifiedFiles??[],createdFiles:e.createdFiles??[],deletedFiles:e.deletedFiles??[],checks:e.checks??[],blockers:e.blockers,decisions:e.decisions,nextActions:e.nextActions}}function cs(e,t,n,r){let s=nu(e),o=ou(s?.durableFacts??[],su(t,n)),i=n.at(-1)?.sequence??s?.source.sequence??0,a=r.phases.filter(y=>y.status==="completed").map(y=>y.title),c=r.tasks.filter(y=>y.status==="completed").map(y=>y.title),u=r.phases.filter(y=>y.status!=="completed"&&y.status!=="cancelled").map(y=>y.title),f=r.tasks.filter(y=>y.status!=="completed"&&y.status!=="cancelled").map(y=>y.title),m={work:iu(r),durableFacts:o.map(y=>y.fingerprint).sort()},d=w(JSON.stringify(m)).slice(0,32),l={schema:"toolnet.memory.checkpoint.v1",version:1,project:{id:e.id,name:e.name},source:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,sequence:i},capturedAt:new Date().toISOString(),request:r.currentRequest,activity:r.currentActivity,goal:r.goal,current:{phase:r.currentPhase,task:r.currentTask},completed:{phases:a,tasks:c},remaining:{phases:u,tasks:f},files:{active:r.activeFiles??[],modified:r.modifiedFiles??[],created:r.createdFiles??[],deleted:r.deletedFiles??[]},checks:r.checks??[],blockers:r.blockers.slice(-10),decisions:r.decisions.slice(-15),nextActions:r.nextActions.slice(0,10),durableFacts:o,stateDigest:d},g=is(e);eu(g,{recursive:!0,mode:448});let S=Nt(g,`${d}.json`);return os(S)||T(S,l),T(as(e),l),l}function rt(e,t,n){if(process.env.TOOLNET_LOCAL_CHECKPOINT==="0"||n.length===0)return{updated:!1,observations:0};let r=Ue(t,n);if(r.length===0)return{updated:!1,observations:0};let s=Yr(e,r);ss(e,s),An(e,{agent:t.agent,nativeSessionId:t.nativeSessionId,observations:r,workState:s});try{cs(e,t,n,s)}catch{}try{ts({project:e,identity:t,state:s,reason:"continuous-checkpoint",sequence:n.at(-1)?.sequence??0})}catch{}return{updated:!0,observations:r.length}}var st=class{identity;wal;remote;sanitizer=new B;learner;continuity;semantic;handoff;project;title;metadata;constructor(t){this.project=t.project,this.identity=Ke(t.project,t.agent,t.nativeSessionId),this.title=t.title,this.metadata=this.sanitizer.sanitizeValue(t.metadata??{}),this.wal=new te(this.identity,t.eventContext),this.remote=new $e(t.storage,t.maxEventsPerChunk??100,t.maxChunkBytes??512*1024),this.learner=new Be({project:t.project,storage:t.storage,identity:this.identity,wal:this.wal}),this.continuity=new Qe({project:t.project,storage:t.storage,identity:this.identity,wal:this.wal}),this.semantic=new et({project:t.project,storage:t.storage,identity:this.identity,wal:this.wal}),this.handoff=new nt({project:t.project,storage:t.storage,identity:this.identity})}sanitizeEvent(t){let n=t.provenance?{...t.provenance,metadata:this.sanitizer.sanitizeValue(t.provenance.metadata)}:void 0;return{...t,data:this.sanitizer.sanitizeValue(t.data??{}),provenance:n}}checkpointLocal(t){if(t.length!==0)try{rt(this.project,this.identity,t)}catch{}}start(t={}){let n=this.wal.loadState();return this.record({type:n.lastSequence===0?"session_start":"session_resume",data:t,provenance:{source:this.identity.agent}})}record(t){let n=this.wal.append([this.sanitizeEvent(t)]);return this.checkpointLocal(n),n[0]}recordMany(t){let n=this.wal.append(t.map(r=>this.sanitizeEvent(r)));return this.checkpointLocal(n),n}setSourceCursor(t,n){this.wal.setSourceCursor(t,n)}async flush(){let t=this.wal.readPending(),n=this.wal.loadState(),r=await this.remote.append(this.identity,t.events,n.sourceCursors,{title:this.title,metadata:this.metadata});if(t.events.length>0){let s=t.events[t.events.length-1];this.wal.markRemote(s.sequence,t.endOffset)}if(process.env.TOOLNET_SESSION_LEARNING!=="0")try{await this.learner.learnNew()}catch{}if(process.env.TOOLNET_WORK_CONTINUITY!=="0")try{await this.continuity.learnNew()}catch{}if(process.env.TOOLNET_SEMANTIC_CONTINUITY!=="0")try{await this.semantic.learnNew()}catch{}if(process.env.TOOLNET_SMART_HANDOFF!=="0"&&t.events.length>0)try{let s=t.events[t.events.length-1],o=["session_idle","session_end","session_compact"].includes(s.type)?s.type:"checkpoint";await this.handoff.capture(o,s.sequence)}catch{}return r}async idle(t={}){return this.record({type:"session_idle",data:t,provenance:{source:this.identity.agent}}),this.flush()}async end(t={}){return this.record({type:"session_end",data:t,provenance:{source:this.identity.agent}}),this.flush()}status(){return this.wal.loadState()}recoverRemote(){return this.remote.recover(this.identity)}};var ot=4e3,_t=20,Kt=30,us=4,$t=20;function Wt(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function it(e,t=0){if(t>=us)return typeof e=="string"?e.length>ot?`${e.slice(0,ot)}\u2026`:e:Array.isArray(e)?`[array:${e.length}]`:Wt(e)?`[object:${Object.keys(e).length}]`:e;if(typeof e=="string")return e.length>ot?`${e.slice(0,ot)}\u2026`:e;if(Array.isArray(e)){let n=e.slice(0,_t).map(r=>it(r,t+1));return e.length>_t&&n.push(`[+${e.length-_t} items]`),n}if(Wt(e)){let n={},r=Object.entries(e);for(let[s,o]of r.slice(0,Kt))n[s]=it(o,t+1);return r.length>Kt&&(n.__truncatedKeys=r.length-Kt),n}return e}function Ft(e,t,n=0){if(!(n>us||t.size>=$t)){if(Array.isArray(e)){for(let r of e)if(Ft(r,t,n+1),t.size>=$t)break;return}if(Wt(e))for(let[r,s]of Object.entries(e)){let o=r.toLowerCase().replace(/[^a-z]/g,"");if((o==="path"||o==="filepath"||o==="filename")&&typeof s=="string"&&s.trim()&&t.add(s.trim()),Ft(s,t,n+1),t.size>=$t)break}}}function xe(e){try{return w(Ie(e)).slice(0,20)}catch{return w(String(e)).slice(0,20)}}function au(e){if(typeof e=="number"&&Number.isFinite(e)){let t=new Date(e);if(!Number.isNaN(t.getTime()))return t.toISOString()}if(typeof e=="string"&&e.trim()){let t=new Date(e);if(!Number.isNaN(t.getTime()))return t.toISOString()}return new Date().toISOString()}function cu(e,t){let n=(e??"").toLowerCase();return n==="read"||n==="view"||n.includes("read_file")||n.includes("list_dir")||n.includes("listdir")||n.includes("grep")||n.includes("glob")||n.includes("search")?null:t.length>0&&(n.includes("edit")||n.includes("patch")||n.includes("replace"))?"file_edit":t.length>0&&(n.includes("write")||n.includes("create")||n.includes("delete"))?"file_write":n.includes("bash")||n.includes("shell")||n.includes("terminal")||n.includes("command")||n.includes("execute")?"command":"tool_result"}function Lt(e,t){let r={timestamp:au(e.timestamp),cwd:e.cwd,source:e.agent,provenance:{source:`${e.agent}-hook`}};if(e.event==="SessionStart")return[{...r,type:"session_start",sourceEventId:`${e.agent}:${e.sessionId}:start`,data:{sessionId:e.sessionId,cwd:e.cwd}}];if(e.event==="UserPromptSubmit"){let s=e.prompt?.trim();return s?[{...r,type:"user_prompt",role:"user",sourceEventId:`${e.agent}:${e.sessionId}:prompt:`+xe(s),data:{content:s}}]:[]}if(e.event==="PostToolUse"){let s=new Set;Ft(e.toolInput,s);let o=[...s],i=cu(e.toolName,o);if(!i)return[];let a=it(e.toolInput),c=it(e.toolResponse);return[{...r,type:i,sourceEventId:[e.agent,e.sessionId,"tool",xe({toolName:e.toolName,input:a,response:c})].join(":"),data:{tool:e.toolName,input:a,response:c,files:o},provenance:{source:`${e.agent}-hook`,files:o.length>0?o:void 0}}]}if(e.event==="AssistantMessage"){let s=e.assistantResponse?.trim();return s?[{...r,type:"assistant_message",role:"assistant",sourceEventId:`${e.agent}:${e.sessionId}:assistant:`+xe(s),data:{content:s}}]:[]}if(e.event==="Stop"){let s=[],o=e.assistantResponse?.trim();return o&&s.push({...r,type:"assistant_message",role:"assistant",sourceEventId:`${e.agent}:${e.sessionId}:assistant:`+xe(o),data:{content:o}}),s.push({...r,type:"session_idle",sourceEventId:`${e.agent}:${e.sessionId}:idle:`+xe({sessionId:e.sessionId,response:o??""}),data:{sessionId:e.sessionId}}),s}return[]}function du(e){let t=on(e);if(!t||!uu(lu(t,".toolnet","project.json")))return null;try{return new Ee().detect(t)}catch{return null}}function pu(e,t){let n=Lt(t,e);if(n.length===0)return 0;let r=Ke(e,t.agent,t.sessionId),o=new te(r,{source:t.agent,cwd:t.cwd}).append(n);return rt(e,r,o),o.length}async function mu(e,t,n,r){let s=Pe(),o=vn(kn({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),{attempts:2}),i=new Ne(o,e.id,e.name,e.remote??e.name);await new st({project:e,storage:i,agent:t,nativeSessionId:n,metadata:{source:`${t}-hook`},eventContext:{source:t,cwd:r}}).flush()}async function ls(e,t={}){if(!e.cwd||!e.sessionId)return{active:!1,captured:0,flushed:!1};let n=du(e.cwd);if(!n)return{active:!1,captured:0,flushed:!1};let r=0;try{r=pu(n,e)}catch(o){return{active:!0,projectRoot:n.rootPath,sessionId:e.sessionId,captured:0,flushed:!1,error:o instanceof Error?o.message:String(o)}}if(e.event==="PostToolUse"||e.event==="AssistantMessage"||e.event==="Stop")try{Cn(n)}catch{}if(e.event!=="Stop")return{active:!0,projectRoot:n.rootPath,sessionId:e.sessionId,captured:r,flushed:!1};let s=t.flushSession??mu;try{return await s(n,e.agent,e.sessionId,e.cwd),{active:!0,projectRoot:n.rootPath,sessionId:e.sessionId,captured:r,flushed:!0}}catch(o){return{active:!0,projectRoot:n.rootPath,sessionId:e.sessionId,captured:r,flushed:!1,error:o instanceof Error?o.message:String(o)}}}function ds(e){return typeof e=="string"&&e.trim()?e.trim():void 0}function je(...e){for(let t of e){let n=ds(t);if(n)return n}}function fu(e){switch(ds(e)){case"SessionStart":case"sessionStart":case"session_start":return"SessionStart";case"UserPromptSubmit":case"userPromptSubmit":case"user_prompt_submit":return"UserPromptSubmit";case"PostToolUse":case"postToolUse":case"post_tool_use":return"PostToolUse";case"Stop":case"stop":return"Stop";default:return null}}function ps(e,t=process.env){let n=fu(t.TOOLNET_HOOK_EVENT??e.hookEventName??e.hook_event_name);if(!n)return null;let r=je(e.sessionId,e.session_id,t.GROK_SESSION_ID),s=je(e.cwd,e.workspaceRoot,t.GROK_WORKSPACE_ROOT,t.CLAUDE_PROJECT_DIR);return!r||!s?null:{agent:"grok",event:n,sessionId:r,cwd:s,timestamp:typeof e.timestamp=="string"||typeof e.timestamp=="number"?e.timestamp:void 0,prompt:je(e.prompt),toolName:je(e.toolName,e.tool_name),toolInput:e.toolInput??e.tool_input,toolResponse:e.toolResult??e.tool_result??e.toolResponse,assistantResponse:je(e.response,e.assistantResponse,e.lastAssistantMessage)}}async function ms(e,t={},n=process.env){let r=ps(e,n);return r?ls(r,t):{active:!1,captured:0,flushed:!1}}async function gu(){let e="";for await(let t of process.stdin)e+=t.toString();if(!e.trim())return{};try{return JSON.parse(e)}catch{return{}}}async function yu(){let e=await gu(),t=un(e);if(t==="PreToolUse"||t==="preToolUse"||t==="pre_tool_use"){let n=ln(e);n.blocked&&process.stdout.write(JSON.stringify(dn(n.reason??"ToolNet continuity guard blocked this tool.")));return}await ms(e)}yu().catch(()=>{process.exitCode=0});
|
package/bundle/grok.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import{homedir as yo}from"node:os";import{join as _}from"node:path";function V(o={}){return o.cursorHome??_(o.home??yo(),".cursor")}function I(o={}){return _(V(o),"mcp.json")}function E(o={}){return _(V(o),"hooks.json")}import{existsSync as Co,mkdirSync as bo,readFileSync as Oo,renameSync as wo,rmSync as Fo,writeFileSync as So}from"node:fs";import{dirname as vo}from"node:path";function f(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function d(o,r){if(!Co(o))return{};let n=Oo(o,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(e){throw new Error(`Invalid existing ${r} hooks file: ${e instanceof Error?e.message:String(e)}`)}if(!f(t))throw new Error(`Invalid existing ${r} hooks file: root must be a JSON object.`);return t}function C(o,r){bo(vo(o),{recursive:!0,mode:448});let n=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{So(n,`${JSON.stringify(r,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),wo(n,o)}finally{Fo(n,{force:!0})}}function R(o){return/^[A-Za-z0-9_./:-]+$/u.test(o)?o:`'${o.replace(/'/gu,"'\\''")}'`}var F=[["sessionStart",10],["beforeSubmitPrompt",10],["preToolUse",10],["postToolUse",15],["afterAgentResponse",15],["stop",30]];function K(o){return f(o)&&typeof o.command=="string"&&o.command.includes("session:cursor-hook")}function xo(o,r,n){let e={type:"command",command:`TOOLNET_HOOK_EVENT=${R(o)} ${R(r)} session:cursor-hook`,timeout:n};return o==="preToolUse"&&(e.matcher=".*"),e}function q(o={}){let r=o.hooksFile??E(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=d(r,"Cursor");if(t.version!==void 0&&t.version!==1)throw new Error(`Unsupported existing Cursor hooks version: ${String(t.version)}`);let e=t.hooks;if(e!==void 0&&!f(e))throw new Error("Invalid existing Cursor hooks file: hooks must be an object.");let s=f(e)?{...e}:{};for(let[l,c]of F){let a=s[l];if(a!==void 0&&!Array.isArray(a))throw new Error(`Invalid existing Cursor hooks file: hooks.${l} must be an array.`);let m=Array.isArray(a)?a.filter(p=>!K(p)):[];s[l]=[...m,xo(l,n,c)]}let i={...t,version:1,hooks:s};if(JSON.stringify(t)===JSON.stringify(i))return{hooksFile:r,changed:!1,hookCount:F.length};C(r,i);let g=d(r,"Cursor");if(g.version!==1||!f(g.hooks))throw new Error("Cursor hooks were written but verification failed.");let u=0;for(let[l]of F){let c=g.hooks[l];if(!Array.isArray(c))throw new Error("Cursor hooks were written but verification failed.");u+=c.filter(K).length}if(u!==F.length)throw new Error("Cursor hooks were written but verification failed.");return{hooksFile:r,changed:!0,hookCount:F.length}}import{existsSync as Io,mkdirSync as Eo,readFileSync as Ho,renameSync as No,rmSync as jo,writeFileSync as To}from"node:fs";import{dirname as $o}from"node:path";function k(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function b(o,r){if(!Io(o))return{};let n=Ho(o,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(e){throw new Error(`Invalid existing ${r} MCP config: ${e instanceof Error?e.message:String(e)}`)}if(!k(t))throw new Error(`Invalid existing ${r} MCP config: root must be a JSON object.`);return t}function H(o,r){Eo($o(o),{recursive:!0,mode:448});let n=`${o}.tmp-${process.pid}-${Date.now()}`;try{To(n,`${JSON.stringify(r,null,2)}
|
|
3
|
+
`,{encoding:"utf8",mode:384}),No(n,o)}finally{jo(n,{force:!0})}}function z(o,r){return k(o)?(o.type===void 0||o.type==="stdio")&&o.command===r&&Array.isArray(o.args)&&o.args.length===1&&o.args[0]==="mcp":!1}function Q(o={}){let r=o.configFile??I(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.serverName??"toolnet-memory",e=b(r,"Cursor"),s=e.mcpServers;if(s!==void 0&&!k(s))throw new Error("Invalid existing Cursor MCP config: mcpServers must be an object.");let i=k(s)?{...s}:{};if(z(i[t],n))return{installed:!0,changed:!1,configFile:r,serverName:t,command:n,args:["mcp"]};i[t]={type:"stdio",command:n,args:["mcp"]},H(r,{...e,mcpServers:i});let u=b(r,"Cursor").mcpServers;if(!k(u)||!z(u[t],n))throw new Error("Cursor MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:r,serverName:t,command:n,args:["mcp"]}}function X(o={}){let r=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=Q({binary:r,configFile:o.configFile}),t=q({binary:r,hooksFile:o.hooksFile});return{installed:n.installed,changed:n.changed||t.changed,mcp:n,hooks:t,files:[n.configFile,t.hooksFile]}}import{homedir as Jo}from"node:os";import{join as N}from"node:path";function Z(o={}){return o.copilotHome??process.env.COPILOT_HOME??N(o.home??Jo(),".copilot")}function j(o={}){return N(Z(o),"mcp-config.json")}function Mo(o={}){return N(Z(o),"hooks")}function T(o={}){return N(Mo(o),"toolnet-memory.json")}var S=[["sessionStart",10],["userPromptSubmitted",10],["userPromptTransformed",10],["preToolUse",10],["postToolUse",15],["agentStop",30]];function Go(o){if(typeof o.command=="string")return o.command;if(typeof o.bash=="string")return o.bash}function oo(o){return f(o)&&Go(o)?.includes("session:copilot-hook")===!0}function Ao(o,r,n){let t={type:"command",command:`${r} session:copilot-hook`,env:{TOOLNET_HOOK_EVENT:o},timeoutSec:n};return o==="preToolUse"&&(t.matcher=".*"),t}function ro(o={}){let r=o.hooksFile??T(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=d(r,"GitHub Copilot CLI");if(t.version!==void 0&&t.version!==1)throw new Error(`Unsupported existing GitHub Copilot CLI hooks version: ${String(t.version)}`);let e=t.hooks;if(e!==void 0&&!f(e))throw new Error("Invalid existing GitHub Copilot CLI hooks file: hooks must be an object.");let s=f(e)?{...e}:{};for(let[l,c]of S){let a=s[l];if(a!==void 0&&!Array.isArray(a))throw new Error(`Invalid existing GitHub Copilot CLI hooks file: hooks.${l} must be an array.`);let m=Array.isArray(a)?a.filter(p=>!oo(p)):[];s[l]=[...m,Ao(l,n,c)]}let i={...t,version:1,hooks:s};if(JSON.stringify(t)===JSON.stringify(i))return{hooksFile:r,changed:!1,hookCount:S.length};C(r,i);let g=d(r,"GitHub Copilot CLI");if(g.version!==1||!f(g.hooks))throw new Error("GitHub Copilot CLI hooks were written but verification failed.");let u=0;for(let[l]of S){let c=g.hooks[l];if(!Array.isArray(c))throw new Error("GitHub Copilot CLI hooks were written but verification failed.");u+=c.filter(oo).length}if(u!==S.length)throw new Error("GitHub Copilot CLI hooks were written but verification failed.");return{hooksFile:r,changed:!0,hookCount:S.length}}function no(o,r){return k(o)?(o.type===void 0||o.type==="local"||o.type==="stdio")&&o.command===r&&Array.isArray(o.args)&&o.args.length===1&&o.args[0]==="mcp"&&Array.isArray(o.tools)&&o.tools.length===1&&o.tools[0]==="*":!1}function to(o={}){let r=o.configFile??j(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.serverName??"toolnet-memory",e=b(r,"GitHub Copilot CLI"),s=e.mcpServers;if(s!==void 0&&!k(s))throw new Error("Invalid existing GitHub Copilot CLI MCP config: mcpServers must be an object.");let i=k(s)?{...s}:{};if(no(i[t],n))return{installed:!0,changed:!1,configFile:r,serverName:t,command:n,args:["mcp"]};i[t]={type:"stdio",command:n,args:["mcp"],tools:["*"]},H(r,{...e,mcpServers:i});let u=b(r,"GitHub Copilot CLI").mcpServers;if(!k(u)||!no(u[t],n))throw new Error("GitHub Copilot CLI MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:r,serverName:t,command:n,args:["mcp"]}}function eo(o={}){let r=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=to({binary:r,configFile:o.configFile}),t=ro({binary:r,hooksFile:o.hooksFile});return{installed:n.installed,changed:n.changed||t.changed,mcp:n,hooks:t,files:[n.configFile,t.hooksFile]}}import{existsSync as Do,mkdirSync as Uo,readFileSync as io,renameSync as Bo,rmSync as Wo,writeFileSync as Yo}from"node:fs";import{dirname as Vo}from"node:path";import{homedir as Po}from"node:os";import{join as y}from"node:path";function L(o={}){return o.grokHome??process.env.GROK_HOME??y(o.home??Po(),".grok")}function $(o={}){return y(L(o),"config.toml")}function _o(o={}){return y(L(o),"hooks")}function J(o={}){return y(_o(o),"toolnet-memory.json")}function Ro(o={}){return y(L(o),"skills")}function Lo(o={}){return y(Ro(o),"toolnet-continuity")}function M(o={}){return y(Lo(o),"SKILL.md")}var D=`---
|
|
4
|
+
name: toolnet-continuity
|
|
5
|
+
description: Restore previous ToolNet project work when the user asks to continue, resume, pick up, finish unfinished work, or asks where work stopped.
|
|
6
|
+
when-to-use: continue, resume, pick up, carry on, ti\u1EBFp t\u1EE5c, l\xE0m ti\u1EBFp, l\xE0m n\u1ED1t, \u0111ang l\xE0m \u0111\u1EBFn \u0111\xE2u, d\u1EEBng \u1EDF \u0111\xE2u
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# ToolNet Continuity
|
|
10
|
+
|
|
11
|
+
When the user asks to continue or resume previous work:
|
|
12
|
+
|
|
13
|
+
1. Use the ToolNet Memory MCP server as the continuity source.
|
|
14
|
+
2. Invoke \`memory_agent_ask\` before exploring old history if the current
|
|
15
|
+
ToolNet handoff is missing, stale, or ambiguous.
|
|
16
|
+
3. Prefer \`mode="local"\` for current task, last file, blocker, completed
|
|
17
|
+
work, TODOs, and next action.
|
|
18
|
+
4. Use \`mode="ai"\` only when continuity requires synthesis.
|
|
19
|
+
5. Do not reconstruct previous work from:
|
|
20
|
+
- \`.toolnet/sessions/**\`
|
|
21
|
+
- ToolNet \`events.jsonl\` or \`state.json\`
|
|
22
|
+
- raw transcripts
|
|
23
|
+
- another coding agent's private session/history files
|
|
24
|
+
6. After ToolNet continuity is known, verify current git and repository
|
|
25
|
+
source truth before changing code.
|
|
26
|
+
7. Do not ask the user to repeat context ToolNet already provides.
|
|
27
|
+
|
|
28
|
+
Current repository evidence overrides stale memory.
|
|
29
|
+
`;function Ko(o,r){Uo(Vo(o),{recursive:!0,mode:448});let n=`${o}.toolnet-${process.pid}-${Date.now()}.tmp`;try{Yo(n,r,{encoding:"utf8",mode:384}),Bo(n,o)}finally{Wo(n,{force:!0})}}function so(o={}){let r=o.skillFile??M();if(Do(r)&&io(r,"utf8")===D)return{skillFile:r,changed:!1};if(Ko(r,D),io(r,"utf8")!==D)throw new Error("Grok ToolNet continuity skill was written but verification failed.");return{skillFile:r,changed:!0}}var v=[["SessionStart",10],["UserPromptSubmit",10],["PreToolUse",10],["PostToolUse",15],["Stop",30]];function co(o){return!f(o)||!Array.isArray(o.hooks)?!1:o.hooks.some(r=>f(r)&&typeof r.command=="string"&&r.command.includes("session:grok-hook"))}function qo(o,r,n){let t={hooks:[{type:"command",command:`${r} session:grok-hook`,timeout:n,env:{TOOLNET_HOOK_EVENT:o}}]};return o==="PreToolUse"&&(t.matcher=".*"),t}function lo(o={}){let r=o.hooksFile??J(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=d(r,"Grok Build"),e=t.hooks;if(e!==void 0&&!f(e))throw new Error("Invalid existing Grok Build hooks file: hooks must be an object.");let s=f(e)?{...e}:{};for(let[l,c]of v){let a=s[l];if(a!==void 0&&!Array.isArray(a))throw new Error(`Invalid existing Grok Build hooks file: hooks.${l} must be an array.`);let m=Array.isArray(a)?a.filter(p=>!co(p)):[];s[l]=[...m,qo(l,n,c)]}let i={...t,hooks:s};if(JSON.stringify(t)===JSON.stringify(i))return{hooksFile:r,changed:!1,hookCount:v.length};C(r,i);let g=d(r,"Grok Build");if(!f(g.hooks))throw new Error("Grok Build hooks were written but verification failed.");let u=0;for(let[l]of v){let c=g.hooks[l];if(!Array.isArray(c))throw new Error("Grok Build hooks were written but verification failed.");u+=c.filter(co).length}if(u!==v.length)throw new Error("Grok Build hooks were written but verification failed.");return{hooksFile:r,changed:!0,hookCount:v.length}}import{existsSync as zo,mkdirSync as Qo,readFileSync as Xo,renameSync as Zo,rmSync as or,writeFileSync as rr}from"node:fs";import{dirname as nr}from"node:path";function ao(o){return zo(o)?Xo(o,"utf8"):""}function tr(o,r){Qo(nr(o),{recursive:!0,mode:448});let n=`${o}.tmp-${process.pid}-${Date.now()}`;try{rr(n,r,{encoding:"utf8",mode:384}),Zo(n,o)}finally{or(n,{force:!0})}}function U(o){return o.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}function er(o){return`[mcp_servers."${U(o)}"]`}function ir(o,r){return[er(o),`command = "${U(r)}"`,'args = ["mcp"]',"enabled = true"].join(`
|
|
30
|
+
`)}function sr(o){let r=o.trim();return r.startsWith("[")&&r.includes("]")}function G(o){return o.trim().replace(/\s+/g,"")}function cr(o){return new Set([G(`[mcp_servers.${o}]`),G(`[mcp_servers."${o}"]`),G(`[mcp_servers.'${o}']`)])}function uo(o,r){let n=o.split(/\r?\n/),t=cr(r),e=-1;for(let c=0;c<n.length;c+=1){let a=G(n[c].replace(/\s+#.*$/,""));if(t.has(a)){e=c;break}}if(e<0)return null;let s=n.length;for(let c=e+1;c<n.length;c+=1)if(sr(n[c])){s=c;break}let i=[],g=0;for(let c of n)i.push(g),g+=c.length+1;let u=i[e]??0,l=s>=n.length?o.length:i[s]??o.length;return{start:u,end:l}}function lr(o,r,n){let t=`${ir(r,n)}
|
|
31
|
+
`,e=uo(o,r);if(e){let s=o.slice(0,e.start),i=o.slice(e.end);return`${s}${t}${i.replace(/^\n+/,"")}`}return o.trim()?`${o.replace(/\s*$/,"")}
|
|
32
|
+
|
|
33
|
+
${t}`:t}function go(o,r,n){let t=uo(o,r);if(!t)return!1;let e=o.slice(t.start,t.end);return e.includes(`command = "${U(n)}"`)&&/args\s*=\s*\[\s*"mcp"\s*\]/.test(e)&&/enabled\s*=\s*true/.test(e)}function fo(o={}){let r=o.configFile??$(),n=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=o.serverName??"toolnet-memory",e=ao(r);if(go(e,t,n))return{installed:!0,changed:!1,configFile:r,serverName:t,command:n,args:["mcp"]};let s=lr(e,t,n);tr(r,s);let i=ao(r);if(!go(i,t,n))throw new Error("Grok Build MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:r,serverName:t,command:n,args:["mcp"]}}function mo(o={}){let r=o.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=fo({binary:r,configFile:o.configFile}),t=lo({binary:r,hooksFile:o.hooksFile}),e=so({skillFile:o.skillFile});return{installed:n.installed,changed:n.changed||t.changed||e.changed,mcp:n,hooks:t,skill:e,files:[n.configFile,t.hooksFile,e.skillFile]}}import{existsSync as O,readFileSync as W}from"node:fs";function h(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function x(o){if(!O(o))return{};try{let r=JSON.parse(W(o,"utf8"));return h(r)?{value:r}:{error:"root must be a JSON object"}}catch(r){return{error:r instanceof Error?r.message:String(r)}}}function po(o,r){if(!o||!h(o.mcpServers))return!1;let n=o.mcpServers["toolnet-memory"];return!h(n)||typeof n.command!="string"||!n.command.trim()||!Array.isArray(n.args)||n.args.length!==1||n.args[0]!=="mcp"?!1:!r||Array.isArray(n.tools)&&n.tools.includes("*")}function ko(o,r,n){if(!o||!h(o.hooks))return[];let t=o.hooks;return r.filter(e=>{let s=t[e];return Array.isArray(s)&&s.some(i=>h(i)&&(typeof i.command=="string"&&i.command.includes(n)||typeof i.bash=="string"&&i.bash.includes(n)))})}function ar(o,r){if(!o||!h(o.hooks))return[];let n=o.hooks;return r.filter(t=>{let e=n[t];return Array.isArray(e)&&e.some(s=>!h(s)||!Array.isArray(s.hooks)?!1:s.hooks.some(i=>h(i)&&typeof i.command=="string"&&i.command.includes("session:grok-hook")))})}function gr(o){if(!O(o))return!1;let r=W(o,"utf8"),n=/\[mcp_servers\.(?:"toolnet-memory"|'toolnet-memory'|toolnet-memory)\]/,t=r.search(n);if(t<0)return!1;let e=r.slice(t),s=e.slice(1).search(/\n\s*\[[^\]]+\]/),i=s>=0?e.slice(0,s+1):e;return/command\s*=\s*"[^"]+"/.test(i)&&/args\s*=\s*\[\s*"mcp"\s*\]/.test(i)&&!/enabled\s*=\s*false/.test(i)}function B(o){let r=[];o.mcpError&&r.push(`MCP config: ${o.mcpError}`),o.hookError&&r.push(`Hooks config: ${o.hookError}`);let n=o.mcpConfigured&&o.hooksConfigured&&(o.skill?.configured??!0),t=O(o.configFile)||O(o.hooksFile)||(o.skill?O(o.skill.skillFile):!1),e=r.length>0?"invalid":n?"ready":t?"partial":"not-installed";return{installed:n,state:e,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:r}}function Y(o,r={}){if(o==="cursor"){let l=["sessionStart","beforeSubmitPrompt","preToolUse","postToolUse","afterAgentResponse","stop"],c=r.configFile??I(),a=r.hooksFile??E(),m=x(c),p=x(a),w=p.error?[]:ko(p.value,l,"session:cursor-hook");return B({mcpConfigured:!m.error&&po(m.value,!1),configFile:c,mcpError:m.error,hooksConfigured:l.every(P=>w.includes(P)),hooksFile:a,events:w,hookError:p.error})}if(o==="copilot"){let l=["sessionStart","userPromptSubmitted","userPromptTransformed","preToolUse","postToolUse","agentStop"],c=r.configFile??j(),a=r.hooksFile??T(),m=x(c),p=x(a),w=p.error?[]:ko(p.value,l,"session:copilot-hook");return B({mcpConfigured:!m.error&&po(m.value,!0),configFile:c,mcpError:m.error,hooksConfigured:l.every(P=>w.includes(P)),hooksFile:a,events:w,hookError:p.error})}let n=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"],t=r.configFile??$(),e=r.hooksFile??J(),s=r.skillFile??M(),i=x(e),g=i.error?[]:ar(i.value,n),u=O(s)&&W(s,"utf8").includes("memory_agent_ask");return B({mcpConfigured:gr(t),configFile:t,hooksConfigured:n.every(l=>g.includes(l)),hooksFile:e,events:g,hookError:i.error,skill:{configured:u,skillFile:s}})}var A={cursor:"Cursor CLI",copilot:"GitHub Copilot CLI",grok:"Grok Build"};function ho(o){let r=process.argv.slice(2),n=r.includes("--json");if(r.includes("--status")||r[0]==="status"){let i=Y(o);if(n)console.log(JSON.stringify(i,null,2));else{console.log(`${A[o]} Integration`),console.log("=".repeat(`${A[o]} Integration`.length)),console.log(""),console.log(`State : ${i.state}`),console.log(`MCP : ${i.mcp.configured?"ready":"missing"} \u2014 ${i.mcp.configFile}`),console.log(`Hooks : ${i.hooks.configured?"ready":"missing"} \u2014 ${i.hooks.hooksFile}`),i.skill&&console.log(`Skill : ${i.skill.configured?"ready":"missing"} \u2014 ${i.skill.skillFile}`),i.hooks.events.length>0&&console.log(`Events: ${i.hooks.events.join(", ")}`);for(let g of i.errors)console.log(`Error : ${g}`);console.log("")}i.installed||(process.exitCode=1);return}let e=o==="cursor"?X():o==="copilot"?eo():mo(),s=Y(o);if(!s.installed)throw new Error(`${A[o]} integration installation did not verify successfully (state=${s.state}).`);if(n){console.log(JSON.stringify({installed:!0,changed:e.changed,files:e.files,status:s},null,2));return}console.log(`\u2705 ${A[o]} integration installed`),console.log(`MCP: ${e.mcp.configFile}`),console.log(`Hooks: ${e.hooks.hooksFile}`),s.skill&&console.log(`Skill: ${s.skill.skillFile}`),console.log("Server: toolnet-memory")}try{ho("grok")}catch(o){console.error(o instanceof Error?o.message:String(o)),process.exitCode=1}
|