toolnet-memory 0.3.15 → 0.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +74 -0
- package/.release-target +1 -1
- package/README.md +316 -6
- package/bin/toolnet-memory +12 -0
- package/bundle/agy-hook.js +66 -66
- package/bundle/agy.js +56 -56
- package/bundle/api.js +15 -15
- package/bundle/audit.js +2 -0
- package/bundle/background-refresh.js +7 -7
- package/bundle/claude-hook.js +49 -49
- package/bundle/code-capabilities.js +2 -0
- package/bundle/codex-context.js +29 -29
- package/bundle/codex.js +71 -71
- package/bundle/context-runtime.js +39 -39
- package/bundle/context.js +15 -15
- package/bundle/copilot-hook.js +78 -78
- package/bundle/cursor-hook.js +78 -78
- package/bundle/docker-healthcheck.js +3 -0
- package/bundle/doctor.js +4 -4
- package/bundle/full-index.js +22 -21
- package/bundle/gc.js +5 -3
- package/bundle/graph-cli.js +1 -1
- package/bundle/graph-index.js +5 -4
- package/bundle/graph-ui.js +4 -3
- package/bundle/grok-hook.js +56 -56
- package/bundle/handoff-refresh.js +10 -10
- package/bundle/help-cli.js +4 -4
- package/bundle/impact.js +5 -4
- package/bundle/incremental.js +5 -5
- package/bundle/init.js +36 -35
- package/bundle/kiro-hook.js +85 -85
- package/bundle/learner.js +8 -6
- package/bundle/mcp.js +19 -17
- package/bundle/memory-agent.js +6 -6
- package/bundle/memory-query.js +7 -7
- package/bundle/opencode.js +77 -77
- package/bundle/project-manual.js +7 -7
- package/bundle/public/index.html +51 -2
- package/bundle/recovery-certify.js +9 -9
- package/bundle/runtime.js +16 -13
- package/bundle/semantic.js +6 -5
- package/bundle/service.js +11 -6
- package/bundle/snapshot.js +6 -4
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +46 -46
- package/bundle/work-continuity.js +7 -7
- package/package.json +38 -2
- package/release-manifest.json +143 -4
package/bundle/memory-agent.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
5
|
-
`,{encoding:"utf8",mode:384}),
|
|
1
|
+
import{existsSync as Ae,readFileSync as Ie}from"node:fs";import{join as Re}from"node:path";var ct=new Int32Array(new SharedArrayBuffer(4));import{closeSync as kt,existsSync as se,fsyncSync as bt,mkdirSync as Mt,openSync as St,readFileSync as ie,renameSync as xt,writeFileSync as vt}from"node:fs";import{dirname as Ct,join as ce}from"node:path";var Z=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],X=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function _(n){return n.normalize("NFKC").trim().toLowerCase()}function ee(n){if(n.length===0)return 0;let e=new Map;for(let r of n)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let o=r/n.length;t-=o*Math.log2(o)}return t}function te(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function ne(n,e,t){let r=n.slice(Math.max(0,e-48),e),o=n.slice(t,Math.min(n.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${o}`)}function re(n,e){return n.start<e.end&&e.start<n.end}function P(n){return n.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var M=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=_(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of Z){let c=new RegExp(s.regex.source,s.regex.flags);for(let a of e.matchAll(c))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:s.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=P(t),o=[];for(let s of r)o.some(c=>re(c,s))||o.push(s);return P(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=_(e);return X.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(r)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||te(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||ne(e,o.index,o.index+s.length)&&(ee(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var g=class{scanner;constructor(e={}){this.scanner=new M(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,o=[...t].sort((c,a)=>a.start-c.start),s=new Set;for(let c of o)s.add(c.type),r=r.slice(0,c.start)+`[REDACTED:${c.type}]`+r.slice(c.end);return{text:r,redacted:t.length,secretTypes:[...s].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,o]of Object.entries(e)){let s=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(o)}return t}return e}};var ft=new g;function ae(n){return ce(n.rootPath,".toolnet","work","current.json")}function A(n){let e=ae(n);if(!se(e))return null;try{let t=JSON.parse(ie(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}import{existsSync as ue,mkdirSync as Tt,readFileSync as le,renameSync as Et,writeFileSync as _t}from"node:fs";import{dirname as Ft,join as de}from"node:path";function me(n){return de(n.rootPath,".toolnet","context","session-origin.json")}function I(n){let e=me(n);if(!ue(e))return null;try{let t=JSON.parse(le(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function fe(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function F(n){let e=fe(n),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),r=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return t&&r?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}import{existsSync as Se,mkdirSync as In,readFileSync as xe}from"node:fs";import{join as N}from"node:path";import{existsSync as ge,readFileSync as ye}from"node:fs";import{homedir as he}from"node:os";import{join as ke}from"node:path";function be(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Me(){let n=process.env.TOOLNET_GLOBAL_ENV??ke(he(),".config","toolnet-memory",".env");if(!ge(n))return;let e=ye(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let s=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=be(r.slice(o+1)))}}Me();var fn=new g;function ve(n){return N(n.rootPath,".toolnet","memory","checkpoints")}function we(n){return N(ve(n),"latest.json")}function Ce(n){let e=we(n);if(!Se(e))return null;try{let t=JSON.parse(xe(e,"utf8"));return t.schema!=="toolnet.memory.checkpoint.v1"||t.project.id!==n.id?null:t}catch{return null}}function O(n){return Ce(n)}var Te={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,request:95,activity:90,phase:75,file:65,next_action:55,blocker:45},next_action:{next_action:100,todo:80,task:65,blocker:60,file:40},last_file:{file:100,task:65,next_action:40},blocker:{blocker:100,task:60,next_action:50,file:35},decision:{decision:100,rule:85,architecture:80,task:45,file:30},completed:{completed:100,progress:70,task:30},status:{progress:100,task:85,phase:75,blocker:65,next_action:60},summary:{task:100,request:98,activity:96,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,rule:54,architecture:53,fix:52,progress:50,test:45,goal:35}},Ee={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function _e(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function i(n,e){let t=e.value.replace(/\s+/g," ").trim();t&&n.push({...e,value:t,score:0})}function Pe(n){let e=Re(n.rootPath,".toolnet","work","handoff-latest.json");if(!Ae(e))return null;try{let r=JSON.parse(Ie(e,"utf8")).continuity;return r?.schema!=="toolnet.handoff.v2"||r.project.id!==n.id?null:r}catch{return null}}function Fe(n){let e=O(n);if(!e)return[];let t=[];e.request&&i(t,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&i(t,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&i(t,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&i(t,{kind:"task",value:e.current.task.title,source:"checkpoint"});let r=e.files.active.at(-1);r&&i(t,{kind:"file",value:r,source:"checkpoint"});for(let o of e.nextActions)i(t,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)i(t,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)i(t,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)i(t,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)i(t,{kind:o.kind,value:o.content,source:"checkpoint"});return t}function Ne(n){let e=Pe(n);if(!e)return[];let t=[];i(t,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&i(t,{kind:"request",value:e.request,source:"handoff"}),e.activity&&i(t,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&i(t,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&i(t,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&i(t,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&i(t,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&i(t,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let r of e.blockers)i(t,{kind:"blocker",value:r,source:"handoff"});for(let r of e.decisions)i(t,{kind:"decision",value:r,source:"handoff"});for(let r of e.completed.tasks)i(t,{kind:"completed",value:r,source:"handoff"});for(let r of e.remaining.todos)i(t,{kind:"todo",value:r,source:"handoff"});return i(t,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),i(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),t}function Oe(n){let e=I(n);if(!e)return[];let t=[];return i(t,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&i(t,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&i(t,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&i(t,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&i(t,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&i(t,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&i(t,{kind:"decision",value:e.latestDecision,source:"session-origin"}),t}function je(n){let e=A(n);if(!e)return[];let t=[];e.currentRequest&&i(t,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&i(t,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&i(t,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&i(t,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&i(t,{kind:"task",value:e.currentTask.title,source:"work-state"});let r=e.activeFiles?.at(-1)??e.filesTouched.at(-1);r&&i(t,{kind:"file",value:r,source:"work-state"});for(let o of e.nextActions.slice(0,5))i(t,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))i(t,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))i(t,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(s=>s.status==="completed").slice(-8))i(t,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(s=>s.status!=="completed"&&s.status!=="cancelled").slice(0,8))i(t,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))i(t,{kind:"test",value:o,source:"work-state"});return i(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),t}function Le(n,e){let t=Te[n];return e.map((r,o)=>({...r,score:(t[r.kind]??10)+Ee[r.source]+Math.max(0,5-o*.01)}))}function De(n){let e=new Map;for(let t of n){let r=`${t.kind}:${_e(t.value)}`,o=e.get(r);(!o||t.score>o.score)&&e.set(r,t)}return[...e.values()]}function j(n,e,t={}){let r=F(e),o=[...Fe(n),...Ne(n),...Oe(n),...je(n)],s=De(Le(r,o)).sort((l,m)=>m.score-l.score),c=Math.max(1,t.maxFacts??12),a=Math.max(300,t.maxChars??3200),u=[],d=0;for(let l of s){if(u.length>=c)break;let m=l.kind.length+l.value.length+l.source.length+16;u.length>0&&d+m>a||(u.push(l),d+=m)}return{intent:r,facts:u,context:{project:{id:n.id,name:n.name},intent:r,selectedFacts:u.map(l=>({kind:l.kind,value:l.value,source:l.source}))},stats:{candidates:o.length,selected:u.length,chars:d}}}var L={previous_agent:"Agent tr\u01B0\u1EDBc",request:"Y\xEAu c\u1EA7u hi\u1EC7n t\u1EA1i",activity:"\u0110ang l\xE0m",goal:"M\u1EE5c ti\xEAu",phase:"Phase",task:"Task hi\u1EC7n t\u1EA1i",file:"File hi\u1EC7n t\u1EA1i",todo:"TODO",next_action:"Ti\u1EBFp theo",blocker:"Blocker",decision:"Quy\u1EBFt \u0111\u1ECBnh",rule:"Quy t\u1EAFc",architecture:"Ki\u1EBFn tr\xFAc",fix:"\u0110\xE3 s\u1EEDa",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},D=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],Ke={previous_agent:["previous_agent"],current_task:["request","activity","task","file","next_action"],next_action:["next_action","task","file","todo"],last_file:["file","task","next_action"],blocker:["blocker"],decision:["decision"],completed:["completed"],status:["progress","task","next_action","blocker"],summary:D};function $e(n){let e=n.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)}function ze(n){let e=n.filter(r=>r.source==="handoff");if(e.length===0)return n;let t=n.filter(r=>r.source==="checkpoint"&&["rule","architecture","fix"].includes(r.kind));return[...e,...t]}function We(n){let e=new Set,t=[];for(let r of n){let o=`${r.kind}:${r.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),t.push(r))}return t}function K(n){switch(n){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function qe(n,e){let t=[];for(let r of e){let o=n.filter(s=>s.kind===r).slice(0,K(r));for(let s of o)t.push(`${L[r]}: ${s.value}`)}return t.join(`
|
|
3
|
+
`)}function Ve(n,e){let t=Ke[e]??D,r=[];for(let o of t){let s=n.filter(c=>c.kind===o).slice(0,K(o));for(let c of s)r.push(`${L[o]}: ${c.value}`)}return r.join(`
|
|
4
|
+
`)}function $(n,e){let t=j(n,e,{maxFacts:32,maxChars:6400}),r=We(ze(t.facts)),o=$e(e)?qe(r,["todo","task","next_action","file"]):Ve(r,String(t.intent));return o?{intent:String(t.intent),answer:o,source:r[0]?.source??"none"}:{intent:String(t.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}async function z(n,e){let t=$(n,e);return t.answer?{answer:t.answer,usedAi:!1}:{answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",usedAi:!1}}import{createHash as Qe}from"node:crypto";import{existsSync as v,mkdirSync as Ze,readFileSync as Xe,renameSync as et,writeFileSync as tt}from"node:fs";import{basename as nt,dirname as w,join as b,parse as J,resolve as p}from"node:path";import{createHash as V}from"node:crypto";import{spawnSync as Be}from"node:child_process";var k="git-remote-v1",He=new Set(["github.com","gitlab.com","bitbucket.org"]);function B(n,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(r=>!r||r==="."||r==="..")?null:(He.has(n)&&(t=t.toLowerCase()),t)}function Ge(n){let e;try{e=new URL(n)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let r=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!r?`${t}:${e.port}`:t,s=B(t,e.pathname);return s?`${o}/${s}`:null}function Ye(n){let e=n.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let r=B(t,e[2]??"");return r?`${t}/${r}`:null}function W(n){let e=n.trim();return e?e.includes("://")?Ge(e):Ye(e):null}function Je(n){return V("sha256").update(`${k}:${n}`).digest("hex")}function H(n){return V("sha256").update(`toolnet-project:${k}:${n}`).digest("hex").slice(0,16)}function Ue(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function R(n,e){let t=Be("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function q(n,e){let t=Ue(n);return t?{scheme:k,canonicalRemote:n,fingerprint:Je(n),repositoryName:t,source:e}:null}function G(n){let e=R(n,["remote","get-url","origin"]);if(e){let o=W(e);if(o)return q(o,"origin")}let t=R(n,["remote"]);if(!t)return null;let r=new Set;for(let o of t.split(/\r?\n/u).map(s=>s.trim()).filter(Boolean)){let s=R(n,["remote","get-url",o]);if(!s)continue;let c=W(s);c&&r.add(c)}return r.size!==1?null:q([...r][0],"unique-remote")}var U=".toolnet",rt="project.json";function ot(n){return Qe("sha256").update(n).digest("hex").slice(0,16)}function y(n){return b(n,U,rt)}function Q(n){return v(y(n))}function Y(n,e){let t=p(n),r=J(t).root;for(;;){if(Q(t))return t;if(t===r||e&&t===p(e))break;let o=w(t);if(o===t)break;t=o}return null}function T(n){let e=p(n),t=J(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>v(b(e,s))))return e;if(e===t)break;let o=w(e);if(o===e)break;e=o}return p(n)}function S(n){let e;try{e=JSON.parse(Xe(n,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${n}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:w(w(n)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function x(n,e){let t=b(n,U);Ze(t,{recursive:!0});let r=y(n),o=`${r}.tmp-${process.pid}`;tt(o,JSON.stringify(e,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),et(o,r)}function f(n,e){return{id:n.id,name:n.name,remote:n.remote,rootPath:e,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}function E(n){return{version:1,scheme:k,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function st(n){let e=n.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var C=class{adopt(e,t){let r=T(p(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(Q(r)){let a=S(y(r));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return f(a,r)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=E(t.gitIdentity));let c={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:r,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return x(r,c),f(c,r)}recordGitIdentity(e,t,r={}){let o=this.requireExisting(e),s=y(o.rootPath),c=S(s),a=st(c);if(a&&a!==t.fingerprint&&!r.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${a}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let u=c.metadata?.toolnetIdentity;return u&&typeof u=="object"&&!Array.isArray(u)&&u.fingerprint===t.fingerprint||(c.metadata={...c.metadata,toolnetIdentity:E(t)},c.updatedAt=new Date().toISOString(),x(o.rootPath,c)),f(c,o.rootPath)}findExisting(e=process.cwd()){let t=p(e),r=T(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>v(b(r,u))),c=Y(t,s?r:void 0);if(!c)return null;let a=S(y(c));return f(a,c)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=p(e),r=T(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>v(b(r,m))),c=Y(t,s?r:void 0);if(c){let m=y(c),h=S(m);return h.rootPath!==c&&(h.rootPath=c,h.updatedAt=new Date().toISOString(),x(c,h)),f(h,c)}let a=new Date().toISOString(),u=nt(r),d=G(r),l={version:1,id:d?H(d.canonicalRemote):ot(r),name:u,remote:d?.repositoryName??u,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:d?{toolnetIdentity:E(d)}:void 0};return x(r,l),f(l,r)}};async function it(){let n=process.argv.slice(2).join(" ").trim();if(!n){console.error('Usage: toolnet-memory ask "<question>"'),process.exitCode=1;return}let e;try{e=new C().requireExisting(process.cwd())}catch(r){if(r instanceof Error&&r.message==="PROJECT_NOT_INITIALIZED"){console.error("PROJECT_NOT_INITIALIZED"),process.exitCode=1;return}throw r}let t=await z(e,n);process.stdout.write(`${t.answer}
|
|
6
6
|
`),process.env.TOOLNET_MEMORY_AGENT_DEBUG==="1"&&process.stderr.write(["",`[ToolNet Memory Agent] local=${t.usedAi?"no":"yes"}`].filter(Boolean).join(`
|
|
7
7
|
`)+`
|
|
8
|
-
`)}
|
|
8
|
+
`)}it().catch(n=>{console.error(n instanceof Error?n.message:String(n)),process.exitCode=1});
|
package/bundle/memory-query.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import*as
|
|
2
|
-
`)}function
|
|
3
|
-
${
|
|
4
|
-
[truncated]`:i;return{intent:
|
|
5
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):
|
|
6
|
-
`,{encoding:"utf8",mode:384}),
|
|
7
|
-
`)}
|
|
1
|
+
import*as m from"fs";import*as d from"path";function I(n){let t=d.resolve(n),e=d.parse(t).root;for(;t!==e;){let r=d.join(t,".toolnet");if(m.existsSync(r)&&m.statSync(r).isDirectory())return t;t=d.dirname(t)}return null}import{existsSync as ce,readFileSync as ae}from"node:fs";import{join as ue}from"node:path";var nt=new Int32Array(new SharedArrayBuffer(4));import{closeSync as pt,existsSync as X,fsyncSync as mt,mkdirSync as gt,openSync as yt,readFileSync as ee,renameSync as ht,writeFileSync as kt}from"node:fs";import{dirname as St,join as te}from"node:path";var B=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],q=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function _(n){return n.normalize("NFKC").trim().toLowerCase()}function J(n){if(n.length===0)return 0;let t=new Map;for(let r of n)t.set(r,(t.get(r)??0)+1);let e=0;for(let r of t.values()){let o=r/n.length;e-=o*Math.log2(o)}return e}function Y(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function U(n,t,e){let r=n.slice(Math.max(0,t-48),t),o=n.slice(e,Math.min(n.length,e+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${o}`)}function Z(n,t){return n.start<t.end&&t.start<n.end}function O(n){return n.sort((t,e)=>t.start!==e.start?t.start-e.start:e.end-e.start-(t.end-t.start))}var S=class{allowValues=new Set;enableEntropyHeuristic;constructor(t={}){for(let e of t.allowValues??[]){let r=_(e);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=t.enableEntropyHeuristic??!0}scan(t){let e=[];for(let i of B){let s=new RegExp(i.regex.source,i.regex.flags);for(let c of t.matchAll(s))c.index===void 0||!c[0]||this.allowed(c[0])||e.push({type:i.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:i.confidence})}this.enableEntropyHeuristic&&e.push(...this.entropyMatches(t));let r=O(e),o=[];for(let i of r)o.some(s=>Z(s,i))||o.push(i);return O(o)}hasSecrets(t){return this.scan(t).length>0}allowed(t){let e=_(t);return q.has(e)?!0:this.allowValues.has(e)}entropyMatches(t){let e=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of t.matchAll(r)){if(o.index===void 0||!o[0])continue;let i=o[0];this.allowed(i)||Y(i)||!/[A-Za-z]/u.test(i)||!/[0-9]/u.test(i)||U(t,o.index,o.index+i.length)&&(J(i)<3.7||e.push({type:"high_entropy_secret",value:i,start:o.index,end:o.index+i.length,confidence:"heuristic"}))}return e}};var b=class{scanner;constructor(t={}){this.scanner=new S(t)}sanitize(t){let e=this.scanner.scan(t);if(e.length===0)return{text:t,redacted:0,secretTypes:[]};let r=t,o=[...e].sort((s,c)=>c.start-s.start),i=new Set;for(let s of o)i.add(s.type),r=r.slice(0,s.start)+`[REDACTED:${s.type}]`+r.slice(s.end);return{text:r,redacted:e.length,secretTypes:[...i].sort()}}sanitizeValue(t){if(typeof t=="string")return this.sanitize(t).text;if(Array.isArray(t))return t.map(e=>this.sanitizeValue(e));if(t&&typeof t=="object"){let e={};for(let[r,o]of Object.entries(t)){let i=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(i.includes("password")||i.includes("passwd")||i==="pwd"||i.includes("secret")||i.includes("token")||i.includes("cookie")||i.includes("authorization")||i.includes("apikey")||i.includes("accesskey")||i.includes("privatekey")||i.includes("clientsecret")||i.includes("credential")){e[r]="[REDACTED]";continue}e[r]=this.sanitizeValue(o)}return e}return t}};var at=new b;function ne(n){return te(n.rootPath,".toolnet","work","current.json")}function j(n){let t=ne(n);if(!X(t))return null;try{let e=JSON.parse(ee(t,"utf8"));return e.version!==1||e.projectId!==n.id?null:e}catch{return null}}import{existsSync as re,mkdirSync as At,readFileSync as oe,renameSync as Mt,writeFileSync as Rt}from"node:fs";import{dirname as Ct,join as se}from"node:path";function ie(n){return se(n.rootPath,".toolnet","context","session-origin.json")}function P(n){let t=ie(n);if(!re(t))return null;try{let e=JSON.parse(oe(t,"utf8"));return e.version!==1||e.projectId!==n.id?null:e}catch{return null}}function de(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function le(n){let t=de(n),e=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(t),r=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(t);return e&&r?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(t)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(t)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(t)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(t)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(t)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(t)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(t)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(t)?"status":"summary"}function fe(n){let t=ue(n.rootPath,".toolnet","context","handoff.md");if(!ce(t))return null;try{let e=ae(t,"utf8").trim();return e||null}catch{return null}}function pe(n,t=5){return n.slice(0,t).map(e=>`- ${e}`).join(`
|
|
2
|
+
`)}function N(n,t){let e=le(t),r=P(n),o=j(n);switch(e){case"previous_agent":{if(r)return{intent:e,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${r.agent}. Session: ${r.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(r?.currentTask){let s=[`Task hi\u1EC7n t\u1EA1i: ${r.currentTask}.`];return r.lastTouchedFile&&s.push(`File g\u1EA7n nh\u1EA5t: ${r.lastTouchedFile}.`),r.latestNextAction&&s.push(`Ti\u1EBFp theo: ${r.latestNextAction}.`),{intent:e,answer:s.join(" "),source:"session-origin"}}if(o?.currentTask)return{intent:e,answer:`Task hi\u1EC7n t\u1EA1i: ${o.currentTask.title} (${o.currentTask.status}).`,source:"work-state"};break}case"next_action":{let s=r?.latestNextAction??o?.nextActions?.[0];if(s)return{intent:e,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${s}.`,source:r?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let s=r?.lastTouchedFile??o?.filesTouched?.at(-1);if(s)return{intent:e,answer:`File g\u1EA7n nh\u1EA5t \u0111\u01B0\u1EE3c nh\u1EAFc ho\u1EB7c s\u1EEDa: ${s}.`,source:r?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let s=r?.latestBlocker??o?.blockers?.at(-1);return s?{intent:e,answer:`Blocker hi\u1EC7n t\u1EA1i: ${s}.`,source:r?.latestBlocker?"session-origin":"work-state"}:{intent:e,answer:"Hi\u1EC7n ToolNet ch\u01B0a ghi nh\u1EADn blocker n\xE0o.",source:o?"work-state":"none"}}case"decision":{let s=r?.latestDecision??o?.decisions?.at(-1);if(s)return{intent:e,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${s}.`,source:r?.latestDecision?"session-origin":"work-state"};break}case"completed":{let s=o?.tasks?.filter(c=>c.status==="completed").map(c=>c.title)??[];if(s.length)return{intent:e,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
|
|
3
|
+
${pe(s,8)}`,source:"work-state"};break}case"status":{if(o){let s=[`Progress: ${o.progress.tasksCompleted}/${o.progress.tasksTotal} task ho\xE0n th\xE0nh.`];return o.currentTask&&s.push(`\u0110ang l\xE0m: ${o.currentTask.title}.`),o.progress.blocked>0&&s.push(`Blocked: ${o.progress.blocked}.`),{intent:e,answer:s.join(" "),source:"work-state"}}break}case"summary":{if(r||o){let s=[];r&&s.push(`Agent tr\u01B0\u1EDBc: ${r.agent}.`);let c=r?.currentTask??o?.currentTask?.title;c&&s.push(`Task hi\u1EC7n t\u1EA1i: ${c}.`);let a=r?.lastTouchedFile??o?.filesTouched?.at(-1);a&&s.push(`File g\u1EA7n nh\u1EA5t: ${a}.`);let u=r?.latestNextAction??o?.nextActions?.[0];u&&s.push(`Ti\u1EBFp theo: ${u}.`);let y=r?.latestBlocker??o?.blockers?.at(-1);y&&s.push(`Blocker: ${y}.`);let p=r?.latestDecision??o?.decisions?.at(-1);return p&&s.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${p}.`),{intent:e,answer:s.join(" "),source:r?"session-origin":"work-state"}}break}}let i=fe(n);if(i){let s=i.length>900?`${i.slice(0,900)}
|
|
4
|
+
[truncated]`:i;return{intent:e,answer:s,source:"handoff"}}return{intent:e,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}import{existsSync as me,readFileSync as ge}from"node:fs";import{homedir as ye}from"node:os";import{join as he}from"node:path";function ke(n){let t=n.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
|
|
5
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function xe(){let n=process.env.TOOLNET_GLOBAL_ENV??he(ye(),".config","toolnet-memory",".env");if(!me(n))return;let t=ge(n,"utf8");for(let e of t.split(/\r?\n/)){let r=e.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let i=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=ke(r.slice(o+1)))}}xe();import{createHash as Re}from"node:crypto";import{existsSync as A,mkdirSync as Ee,readFileSync as Ce,renameSync as Te,writeFileSync as Ie}from"node:fs";import{basename as _e,dirname as M,join as x,parse as V,resolve as f}from"node:path";import{createHash as F}from"node:crypto";import{spawnSync as Se}from"node:child_process";var k="git-remote-v1",be=new Set(["github.com","gitlab.com","bitbucket.org"]);function L(n,t){let e=t.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!e||e==="."||e===".."||e.split("/").some(r=>!r||r==="."||r==="..")?null:(be.has(n)&&(e=e.toLowerCase()),e)}function we(n){let t;try{t=new URL(n)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(t.protocol))return null;let e=t.hostname.trim().toLowerCase();if(!e)return null;let r=t.protocol==="https:"&&t.port==="443"||t.protocol==="http:"&&t.port==="80"||t.protocol==="ssh:"&&t.port==="22",o=t.port&&!r?`${e}:${t.port}`:e,i=L(e,t.pathname);return i?`${o}/${i}`:null}function ve(n){let t=n.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!t)return null;let e=t[1]?.trim().toLowerCase();if(!e||e.length===1)return null;let r=L(e,t[2]??"");return r?`${e}/${r}`:null}function $(n){let t=n.trim();return t?t.includes("://")?we(t):ve(t):null}function Ae(n){return F("sha256").update(`${k}:${n}`).digest("hex")}function W(n){return F("sha256").update(`toolnet-project:${k}:${n}`).digest("hex").slice(0,16)}function Me(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function E(n,t){let e=Se("git",["-C",n,...t],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return e.error||e.status!==0?null:e.stdout?.trim()||null}function D(n,t){let e=Me(n);return e?{scheme:k,canonicalRemote:n,fingerprint:Ae(n),repositoryName:e,source:t}:null}function K(n){let t=E(n,["remote","get-url","origin"]);if(t){let o=$(t);if(o)return D(o,"origin")}let e=E(n,["remote"]);if(!e)return null;let r=new Set;for(let o of e.split(/\r?\n/u).map(i=>i.trim()).filter(Boolean)){let i=E(n,["remote","get-url",o]);if(!i)continue;let s=$(i);s&&r.add(s)}return r.size!==1?null:D([...r][0],"unique-remote")}var G=".toolnet",Oe="project.json";function je(n){return Re("sha256").update(n).digest("hex").slice(0,16)}function g(n){return x(n,G,Oe)}function H(n){return A(g(n))}function z(n,t){let e=f(n),r=V(e).root;for(;;){if(H(e))return e;if(e===r||t&&e===f(t))break;let o=M(e);if(o===e)break;e=o}return null}function C(n){let t=f(n),e=V(t).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(i=>A(x(t,i))))return t;if(t===e)break;let o=M(t);if(o===t)break;t=o}return f(n)}function w(n){let t;try{t=JSON.parse(Ce(n,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${n}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:M(M(n)),createdAt:typeof e.createdAt=="string"?e.createdAt:r,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:r,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function v(n,t){let e=x(n,G);Ee(e,{recursive:!0});let r=g(n),o=`${r}.tmp-${process.pid}`;Ie(o,JSON.stringify(t,null,2)+`
|
|
6
|
+
`,{encoding:"utf8",mode:384}),Te(o,r)}function l(n,t){return{id:n.id,name:n.name,remote:n.remote,rootPath:t,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}function T(n){return{version:1,scheme:k,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function Pe(n){let t=n.metadata?.toolnetIdentity;if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return typeof e.fingerprint=="string"?e.fingerprint:null}var R=class{adopt(t,e){let r=C(f(t));if(!e.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!e.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!e.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(H(r)){let c=w(g(r));if(c.id!==e.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${c.id}`,`requested=${e.id}`].join(" "));return l(c,r)}let o=new Date().toISOString(),i={...e.metadata};e.gitIdentity&&(i.toolnetIdentity=T(e.gitIdentity));let s={version:1,id:e.id.trim(),name:e.name.trim(),remote:e.remote.trim(),rootPath:r,createdAt:e.createdAt??o,updatedAt:o,graphVersion:e.graphVersion??0,memoryVersion:e.memoryVersion??0,metadata:Object.keys(i).length?i:void 0};return v(r,s),l(s,r)}recordGitIdentity(t,e,r={}){let o=this.requireExisting(t),i=g(o.rootPath),s=w(i),c=Pe(s);if(c&&c!==e.fingerprint&&!r.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${c}`,`current=${e.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let a=s.metadata?.toolnetIdentity;return a&&typeof a=="object"&&!Array.isArray(a)&&a.fingerprint===e.fingerprint||(s.metadata={...s.metadata,toolnetIdentity:T(e)},s.updatedAt=new Date().toISOString(),v(o.rootPath,s)),l(s,o.rootPath)}findExisting(t=process.cwd()){let e=f(t),r=C(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(a=>A(x(r,a))),s=z(e,i?r:void 0);if(!s)return null;let c=w(g(s));return l(c,s)}requireExisting(t=process.cwd()){let e=this.findExisting(t);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");return e}detect(t=process.cwd()){let e=f(t),r=C(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>A(x(r,p))),s=z(e,i?r:void 0);if(s){let p=g(s),h=w(p);return h.rootPath!==s&&(h.rootPath=s,h.updatedAt=new Date().toISOString(),v(s,h)),l(h,s)}let c=new Date().toISOString(),a=_e(r),u=K(r),y={version:1,id:u?W(u.canonicalRemote):je(r),name:a,remote:u?.repositoryName??a,rootPath:r,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0,metadata:u?{toolnetIdentity:T(u)}:void 0};return v(r,y),l(y,r)}};function Ne(){let n=process.argv.slice(2).join(" ").trim();if(!n){console.error('Usage: toolnet-memory ask "<question>"'),process.exitCode=1;return}let t=process.cwd(),e=I(t);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let r=new R().detect(e);if(!r){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let o=N(r,n);process.stdout.write(`${o.answer}
|
|
7
|
+
`)}Ne();
|