toolnet-memory 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -4
- package/README.md +428 -202
- package/bin/toolnet-memory +15 -42
- package/bundle/agy-hook.js +47 -47
- package/bundle/agy.js +31 -31
- package/bundle/api.js +15 -52
- package/bundle/auto-integrate.js +34 -33
- package/bundle/claude-hook.js +9 -9
- package/bundle/codex.js +28 -28
- package/bundle/config.js +17 -12
- package/bundle/context-runtime.js +9 -9
- package/bundle/context.js +12 -12
- package/bundle/continuity-certify.js +13 -50
- package/bundle/copilot-hook.js +13 -13
- package/bundle/cursor-hook.js +13 -13
- package/bundle/doctor.js +4 -6
- package/bundle/full-index.js +21 -22
- package/bundle/graph-index.js +3 -3
- package/bundle/graph-ui.js +3 -3
- package/bundle/grok-hook.js +13 -13
- package/bundle/help-cli.js +4 -4
- package/bundle/impact.js +3 -3
- package/bundle/incremental.js +3 -3
- package/bundle/init.js +37 -36
- package/bundle/kilo.js +2 -0
- package/bundle/kiro-hook.js +14 -14
- package/bundle/learner.js +4 -4
- package/bundle/mcp.js +18 -56
- package/bundle/memory-agent.js +7 -47
- package/bundle/opencode.js +27 -27
- package/bundle/project-manual.js +2 -2
- package/bundle/recovery-certify.js +13 -53
- package/bundle/runtime.js +11 -11
- package/bundle/semantic.js +5 -6
- package/bundle/snapshot.js +3 -3
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +2 -0
- package/bundle/work-continuity.js +5 -5
- package/package.json +1 -3
- package/bundle/model-cli.js +0 -2
- package/bundle/provider.js +0 -6
- package/bundle/setup.js +0 -1159
package/bundle/api.js
CHANGED
|
@@ -1,52 +1,15 @@
|
|
|
1
|
-
import"dotenv/config";import{existsSync as
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function
|
|
3
|
-
`,{encoding:"utf8",mode:384}),Zr(o,n)}function Ge(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var X=class{detect(e=process.cwd()){let t=_(e),n=an(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>Se(Z(n,u))),s=sn(t,i?n:void 0);if(s){let u=Ae(s),f=cn(u);return f.rootPath!==s&&(f.rootPath=s,f.updatedAt=new Date().toISOString(),We(s,f)),Ge(f,s)}let a=new Date().toISOString(),c=tn(n),d={version:1,id:nn(n),name:c,remote:c,rootPath:n,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return We(n,d),Ge(d,n)}};import{randomUUID as An}from"node:crypto";var un=[{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}],ee=class{scan(e){let t=[];for(let n of un){let o=new RegExp(n.regex.source,n.regex.flags);for(let i of e.matchAll(o))t.push({type:n.type,value:i[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var I=class{scanner=new ee;sanitize(e){let t=e,n=this.scanner.scan(e),o=new Set;for(let i of n)o.add(i.type),t=t.split(i.value).join(`[REDACTED:${i.type}]`);return{text:t,redacted:n.length,secretTypes:[...o]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[n,o]of Object.entries(e)){let i=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");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")?t[n]="[REDACTED]":t[n]=this.sanitizeValue(o)}return t}return e}};var ln=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),dn=new Set(["d\xF9ng","s\u1EED","d\u1EE5ng","use","using","the","a","an","cho","v\xE0","l\xE0","c\u1EE7a","to","for","with","quy\u1EBFt","\u0111\u1ECBnh"]);function ze(r){return new Set(r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!dn.has(e)))}function mn(r,e){let t=ze(r),n=ze(e);if(t.size===0||n.size===0)return 0;let o=0;for(let s of t)n.has(s)&&o++;let i=new Set([...t,...n]).size;return o/i}function Ve(r){return new Set(r.tags.filter(e=>!ln.has(e.toLowerCase())))}var te=class{findSuperseded(e,t){if(e.type!=="rule"&&e.type!=="decision")return[];let n=typeof e.metadata?.topic=="string"?e.metadata.topic:void 0,o=Ve(e);return t.filter(i=>{if(i.id===e.id||i.projectId!==e.projectId||i.type!==e.type||i.metadata?.supersededBy)return!1;let s=typeof i.metadata?.topic=="string"?i.metadata.topic:void 0;if(n&&s&&n===s)return!0;let a=Ve(i);for(let c of o)if(a.has(c))return!0;return mn(e.content,i.content)>=.6})}};var pn=new Set(["code","decision","rule","todo","summary"]);function fn(r){return r.normalize("NFKC").toLowerCase().replace(/[“”"'`]/gu,"").replace(/[.!?]+$/gu,"").replace(/\s+/gu," ").trim()}function qe(r){return r.tags.includes("class:permanent")?4:r.tags.includes("class:task")?3:r.tags.includes("class:session")?2:r.tags.includes("class:transient")?1:0}function gn(r,e){let t=qe(e)-qe(r);if(t!==0)return t;let n=e.importanceScore-r.importanceScore;if(n!==0)return n;let o=e.updatedAt.localeCompare(r.updatedAt);if(o!==0)return o;let i=e.createdAt.localeCompare(r.createdAt);return i!==0?i:r.id.localeCompare(e.id)}function Je(r){let e=new Set,t=[];for(let n of r){let o=n.trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();e.has(i)||(e.add(i),t.push(o))}return t}function Ye(r){let e=new Map;for(let o of r){if(!pn.has(o.type)||o.metadata?.supersededBy)continue;let i=fn(o.content);if(!i)continue;let s=[o.projectId,o.type,i].join("\0"),a=e.get(s)??[];a.push(o),e.set(s,a)}let t=[],n=0;for(let o of e.values()){if(o.length<2)continue;let i=[...o].sort(gn),s=i[0];if(!s)continue;let a=i.slice(1);t.push({canonicalId:s.id,duplicateIds:a.map(c=>c.id),mergedTags:Je(i.flatMap(c=>c.tags)),mergedSources:Je(i.map(c=>c.source))}),n+=a.length}return{groups:t,duplicates:n}}function Me(r){if(r.tags.includes("class:permanent"))return"permanent";if(r.tags.includes("class:task"))return"task";if(r.tags.includes("class:session"))return"session";if(r.tags.includes("class:transient"))return"transient"}function yn(r,e){let t=new Date(r.updatedAt).getTime();return Number.isFinite(t)?Math.max(0,(e-t)/864e5):0}function hn(r){let e=Me(r);if(e==="permanent")return 730;if(e==="task")return 180;if(e==="session")return 45;if(e==="transient")return 7;switch(r.type){case"rule":return 730;case"decision":return 365;case"code":return 180;case"todo":return 120;case"summary":return 45;case"activity":return 14}}function kn(r){return Me(r)==="permanent"||r.type==="rule"||r.type==="decision"||r.importance==="critical"}function vn(r){let e=r.normalize("NFKC").toLowerCase().trim();return e.length<8?!0:[/^ok(?:ay)?[.!]?$/u,/^done[.!]?$/u,/^thanks?[.!]?$/u,/^test(?:ing)?[.!]?$/u,/^npm notice\b/u,/^changed \d+ packages?/u,/^packages? are looking for funding/u].some(t=>t.test(e))}function Qe(r,e=Date.now()){let t=50,n=[],o=Me(r);switch(o==="permanent"?(t+=25,n.push("permanent project knowledge")):o==="task"?(t+=15,n.push("active task knowledge")):o==="session"?(t+=2,n.push("session-scoped knowledge")):o==="transient"&&(t-=25,n.push("transient knowledge")),r.importance){case"critical":t+=25,n.push("critical importance");break;case"high":t+=15,n.push("high importance");break;case"normal":break;case"temporary":t-=15,n.push("temporary importance");break}(r.type==="rule"||r.type==="decision")&&(t+=10,n.push("durable knowledge type"));let i=r.content.trim().length;i<12?(t-=30,n.push("very short content")):i<30?(t-=10,n.push("limited context")):i<=1200?(t+=8,n.push("useful context density")):i>5e3&&(t-=15,n.push("excessively large memory")),vn(r.content)&&(t-=35,n.push("matches transient/noise pattern"));let s=r.metadata?.consolidation;s&&typeof s=="object"&&Array.isArray(s.sources)&&s.sources.length>1&&(t+=10,n.push("confirmed across multiple sources"));let a=yn(r,e)>=hn(r);a&&(t-=15,n.push("stale for lifecycle class"));let c=kn(r);t=Math.max(0,Math.min(100,Math.round(t)));let d;t>=80?d="trusted":t>=55?d="useful":t>=30?d="weak":d="noise";let u=r.importance==="temporary"||r.type==="activity"||o==="transient";return{score:t,tier:d,stale:a,protected:c,pruneEligible:!c&&(d==="noise"&&u||a&&(d==="noise"||d==="weak")),reasons:n}}var wn={critical:100,high:75,normal:50,temporary:20},bn={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function Xe(r,e,t=new Date){let n;if(e==="temporary"&&(n=30),r==="activity"&&(n=Math.min(n??14,14)),r==="summary"&&(n=Math.min(n??30,30)),!!n)return new Date(t.getTime()+n*864e5).toISOString()}function xe(r,e=Date.now()){return r.expiresAt?new Date(r.expiresAt).getTime()<=e:!1}function Sn(r){return!!r.metadata?.supersededBy}function Pe(r,e=Date.now()){return!xe(r,e)&&!Sn(r)}function j(r,e=Date.now()){if(!Pe(r,e))return 0;let t=wn[r.importance];if(r.importance==="critical")return t;let n=bn[r.type]??180,i=Math.max(0,e-new Date(r.updatedAt).getTime())/864e5,s=Math.pow(.5,i/n);return t*s}var re=class{memories=new Map;sanitizer=new I;conflicts=new te;remember(e){let t=new Date().toISOString(),n=this.sanitizer.sanitize(e.content.trim()).text,o=e.importance??He(e.type,n),i={id:An(),projectId:e.projectId,type:e.type,content:n,importance:o,importanceScore:$e(o),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??Xe(e.type,o,new Date(t)),metadata:this.sanitizer.sanitizeValue(e.metadata)},s=this.conflicts.findSuperseded(i,this.list(e.projectId));if(s.length){i.metadata={...i.metadata??{},supersedes:s.map(a=>a.id)};for(let a of s)a.updatedAt=t,a.metadata={...a.metadata??{},supersededBy:i.id,supersededAt:t},this.memories.set(a.id,a)}return this.memories.set(i.id,i),i}importRecords(e){let t=0;for(let n of e)n?.id&&(this.memories.set(n.id,n),t++);return t}exportProject(e){return this.listAll(e)}get(e){return this.memories.get(e)}delete(e){return this.memories.delete(e)}listAll(e){return[...this.memories.values()].filter(t=>t.projectId===e).sort((t,n)=>n.createdAt.localeCompare(t.createdAt))}list(e){return this.listAll(e).filter(t=>Pe(t))}recent(e,t=10){return this.list(e).slice(0,t)}byType(e,t){return this.list(e).filter(n=>n.type===t)}search(e){let t=e.query.trim().toLowerCase(),n=e.limit??10,o=t.split(/\s+/).filter(Boolean);return this.list(e.projectId).filter(i=>{if(e.types&&!e.types.includes(i.type))return!1;let s=j(i);return!(e.minImportanceScore&&s<e.minImportanceScore||e.tags?.length&&!e.tags.some(c=>i.tags.includes(c)))}).map(i=>{let s=i.content.toLowerCase(),a=o.filter(u=>s.includes(u)).length,c=o.length===0?0:a/o.length,d=j(i)/500;return{memory:i,score:c+d,source:"memory"}}).filter(i=>t.length===0||i.score>0).sort((i,s)=>s.score-i.score).slice(0,n)}consolidate(e,t=Date.now()){let n=Ye(this.list(e)),o=[],i=0;for(let s of n.groups){let a=this.memories.get(s.canonicalId);if(a){a.tags=s.mergedTags,a.metadata={...a.metadata??{},consolidation:{version:1,consolidatedAt:new Date(t).toISOString(),mergedIds:s.duplicateIds,sources:s.mergedSources}},this.memories.set(a.id,a),o.push(a.id);for(let c of s.duplicateIds)this.memories.delete(c)&&(i+=1)}}return{groupsConsolidated:o.length,duplicatesRemoved:i,canonicalIds:o}}reviewLifecycle(e,t=Date.now()){let n={reviewed:0,trusted:0,useful:0,weak:0,noise:0,stale:0,protected:0,pruned:0};for(let o of this.list(e)){let i=Qe(o,t);n.reviewed+=1,n[i.tier]+=1,i.stale&&(n.stale+=1),i.protected&&(n.protected+=1),o.metadata={...o.metadata??{},lifecycle:{version:1,reviewedAt:new Date(t).toISOString(),qualityScore:i.score,tier:i.tier,stale:i.stale,protected:i.protected,reasons:i.reasons}},this.memories.set(o.id,o),i.pruneEligible&&this.memories.delete(o.id)&&(n.pruned+=1)}return n}pruneExpired(e,t=Date.now()){let n=0;for(let[o,i]of this.memories)i.projectId===e&&xe(i,t)&&(this.memories.delete(o),n++);return n}pruneSuperseded(e,t=30,n=Date.now()){let o=0,i=t*864e5;for(let[s,a]of this.memories){if(a.projectId!==e)continue;let c=a.metadata?.supersededAt;if(typeof c!="string")continue;n-new Date(c).getTime()>=i&&(this.memories.delete(s),o++)}return o}clearProject(e){let t=0;for(let[n,o]of this.memories)o.projectId===e&&(this.memories.delete(n),t++);return t}};function Ce(r){return r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}var ne=class{score(e,t){let n=Ce(e),o=Ce([t.content,...t.tags??[],t.type].join(" "));if(n.length===0||o.length===0)return 0;let i=new Map;for(let a of o)i.set(a,(i.get(a)??0)+1);let s=0;for(let a of n){let c=i.get(a)??0;c!==0&&(s+=1+Math.log(1+c))}return s/n.length}};function Ze(r,e=Date.now()){let t=r.updatedAt??r.createdAt,n=new Date(t).getTime();if(!Number.isFinite(n))return 0;let o=Math.max(0,e-n)/864e5;return Math.exp(-Math.LN2*o/30)}function et(r){return j(r)/100}var Mn={rule:1,decision:.9,todo:.8,summary:.6,activity:.3};function tt(r){return Mn[r]??.4}var oe=class{analyze(e){let t=e.toLowerCase(),n=[];return(t.includes("quy\u1EBFt \u0111\u1ECBnh")||t.includes("decision")||t.includes("\u0111\xE3 ch\u1ECDn"))&&n.push("decision"),(t.includes("todo")||t.includes("c\u1EA7n l\xE0m")||t.includes("ti\u1EBFp theo")||t.includes("ch\u01B0a xong"))&&n.push("todo"),(t.includes("quy t\u1EAFc")||t.includes("rule")||t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c"))&&n.push("rule"),(t.includes("t\xF3m t\u1EAFt")||t.includes("summary")||t.includes("\u0111\xE3 l\xE0m"))&&n.push("summary"),{query:e,preferredTypes:n}}};var ie=class{bm25=new ne;analyzer=new oe;search(e,t,n={}){let o=n.topK??8,i=n.minScore??.05,s=this.analyzer.analyze(e),a=[];for(let c of t){if(n.types?.length&&!n.types.includes(c.type))continue;let d=this.bm25.score(e,c),u=Ze(c),f=et(c),h=tt(c.type);s.preferredTypes.includes(c.type)&&(h=Math.min(1,h+.25));let k=d*.55+f*.2+u*.15+h*.1;d<=0||k<i||a.push({memory:c,score:k,scores:{keyword:d,recency:u,importance:f,type:h}})}return a.sort((c,d)=>d.score-c.score).slice(0,o)}};var se=class{build(e,t=6e3){let n=[],o=0;for(let i of e){let s=i.memory,a=[`[${s.type.toUpperCase()}]`,s.content].join(" ");if(o+a.length>t)break;n.push(a),o+=a.length}return n.join(`
|
|
4
|
-
`)}};var
|
|
5
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ut(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};var A=["hub:read","teams:write","agents:write","acl:manage","loadouts:write","observability:read","wiki:read","wiki:write","governance:read","governance:write"];var lt="hub/state.v1.json";function Qn(r,e){let t=new Date().toISOString();return{schema:"toolnet.memory-hub.v1",version:1,ownerPrincipal:e,project:{id:r.id,name:r.name,remote:r.remote??r.name},teams:[],agents:[],acl:[{principal:e,role:"owner",scopes:[...A],createdAt:t,updatedAt:t}],loadouts:[],observability:{requests:0,mutations:0,errors:0,events:[]},createdAt:t,updatedAt:t}}function Xn(r,e){let t=JSON.parse(r);if(t.schema!=="toolnet.memory-hub.v1"||t.version!==1||!t.project||t.project.id!==e.id||!Array.isArray(t.teams)||!Array.isArray(t.agents)||!Array.isArray(t.acl)||!Array.isArray(t.loadouts)||!t.observability||!Array.isArray(t.observability.events))throw new Error("Invalid ToolNet Memory Hub state");return t}var de=class{constructor(e,t,n){this.storage=e;this.project=t;this.ownerPrincipal=n}storage;project;ownerPrincipal;async load(){let e=await this.storage.getText(lt);if(!e){let t=Qn(this.project,this.ownerPrincipal);return await this.save(t),t}return Xn(e,this.project)}async save(e){await this.storage.put(lt,JSON.stringify(e,null,2),"application/json")}};import{randomUUID as Ee}from"node:crypto";var dt=["memory_search","memory_agent_ask","skill_memory_search","context_offload_read","wiki_search","wiki_read","knowledge_governance_status"],v=class extends Error{constructor(t,n){super(t);this.statusCode=n}statusCode};function Zn(r){return r==="owner"||r==="admin"?[...A]:["hub:read"]}function Te(r){return[...new Set(r.map(e=>e.trim()).filter(Boolean))]}function eo(r){return structuredClone(r)}var me=class{constructor(e,t=100){this.store=e;this.maxEvents=t}store;maxEvents;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}async mutate(e){let t,n=this.queue.then(async()=>{let o=await this.ensureState();t=e(o),o.updatedAt=new Date().toISOString(),await this.store.save(o)});return this.queue=n.then(()=>{},()=>{}),await n,t}grantFor(e,t){return e.acl.find(n=>n.principal===t)}async authorize(e,t){let n=await this.ensureState(),o=this.grantFor(n,e);return!!(o&&(o.role==="owner"||o.role==="admin"||o.scopes.includes(t)))}async requireScope(e,t){if(!await this.authorize(e,t))throw new v(`Principal '${e}' lacks '${t}'`,403)}event(e,t,n,o){return{id:Ee(),kind:e,action:t,principal:n,ok:o,timestamp:new Date().toISOString()}}pushEvent(e,t){e.observability.events.push(t),e.observability.events.length>this.maxEvents&&(e.observability.events=e.observability.events.slice(-this.maxEvents)),e.observability.lastActivityAt=t.timestamp}mutation(e,t,n){e.observability.mutations+=1,this.pushEvent(e,this.event("mutation",t,n,!0))}async summary(e){await this.requireScope(e,"hub:read");let t=await this.ensureState();return{schema:t.schema,project:{...t.project},teams:t.teams.length,agents:t.agents.length,aclGrants:t.acl.length,loadouts:t.loadouts.length,updatedAt:t.updatedAt}}async listTeams(e){return await this.requireScope(e,"hub:read"),structuredClone((await this.ensureState()).teams)}async createTeam(e,t){return await this.requireScope(e,"teams:write"),this.mutate(n=>{let o=new Date().toISOString(),i=t.id?.trim()||`team-${Ee().slice(0,8)}`;if(n.teams.some(a=>a.id===i))throw new v(`Team already exists: ${i}`,409);let s={id:i,name:t.name.trim(),...t.description?.trim()?{description:t.description.trim()}:{},createdAt:o,updatedAt:o};return n.teams.push(s),this.mutation(n,`team:create:${i}`,e),structuredClone(s)})}async listAgents(e){return await this.requireScope(e,"hub:read"),structuredClone((await this.ensureState()).agents)}async createAgent(e,t){return await this.requireScope(e,"agents:write"),this.mutate(n=>{let o=new Date().toISOString(),i=t.id?.trim()||`agent-${Ee().slice(0,8)}`;if(n.agents.some(c=>c.id===i))throw new v(`Agent already exists: ${i}`,409);let s=Te(t.teamIds??[]);for(let c of s)if(!n.teams.some(d=>d.id===c))throw new v(`Team not found: ${c}`,404);let a={id:i,name:t.name.trim(),...t.kind?.trim()?{kind:t.kind.trim()}:{},teamIds:s,...t.metadata?{metadata:structuredClone(t.metadata)}:{},createdAt:o,updatedAt:o};return n.agents.push(a),n.loadouts.push({agentId:i,tools:[...dt],memoryMode:"local",skillMemory:!0,contextOffload:!0,maxContextChars:6400,updatedAt:o}),this.mutation(n,`agent:create:${i}`,e),structuredClone(a)})}async listAcl(e){return await this.requireScope(e,"acl:manage"),structuredClone((await this.ensureState()).acl)}async grantAcl(e,t){return await this.requireScope(e,"acl:manage"),this.mutate(n=>{let o=new Date().toISOString(),i=Te(t.scopes??Zn(t.role));for(let c of i)if(!A.includes(c))throw new v(`Unknown Memory Hub scope: ${c}`,400);let s=n.acl.find(c=>c.principal===t.principal);if(s)return s.role=t.role,s.scopes=[...i],s.updatedAt=o,this.mutation(n,`acl:update:${t.principal}`,e),structuredClone(s);let a={principal:t.principal,role:t.role,scopes:[...i],createdAt:o,updatedAt:o};return n.acl.push(a),this.mutation(n,`acl:grant:${t.principal}`,e),structuredClone(a)})}async revokeAcl(e,t){await this.requireScope(e,"acl:manage"),await this.mutate(n=>{if(t===n.ownerPrincipal)throw new v("Memory Hub owner ACL cannot be revoked",409);let o=n.acl.length;if(n.acl=n.acl.filter(i=>i.principal!==t),n.acl.length===o)throw new v(`ACL principal not found: ${t}`,404);this.mutation(n,`acl:revoke:${t}`,e)})}async listLoadouts(e){return await this.requireScope(e,"hub:read"),structuredClone((await this.ensureState()).loadouts)}async getLoadout(e,t){await this.requireScope(e,"hub:read");let n=(await this.ensureState()).loadouts.find(o=>o.agentId===t);if(!n)throw new v(`Agent loadout not found: ${t}`,404);return structuredClone(n)}async setLoadout(e,t){return await this.requireScope(e,"loadouts:write"),this.mutate(n=>{if(!n.agents.some(s=>s.id===t.agentId))throw new v(`Agent not found: ${t.agentId}`,404);let o=new Date().toISOString(),i=n.loadouts.find(s=>s.agentId===t.agentId);return i||(i={agentId:t.agentId,tools:[...dt],memoryMode:"local",skillMemory:!0,contextOffload:!0,maxContextChars:6400,updatedAt:o},n.loadouts.push(i)),t.tools&&(i.tools=Te(t.tools)),t.memoryMode&&(i.memoryMode=t.memoryMode),t.skillMemory!==void 0&&(i.skillMemory=t.skillMemory),t.contextOffload!==void 0&&(i.contextOffload=t.contextOffload),t.maxContextChars!==void 0&&(i.maxContextChars=t.maxContextChars),i.updatedAt=o,this.mutation(n,`loadout:set:${t.agentId}`,e),structuredClone(i)})}async observability(e){return await this.requireScope(e,"observability:read"),structuredClone((await this.ensureState()).observability)}async recordRequest(e){await this.mutate(t=>{let n=e.statusCode<400;t.observability.requests+=1,n||(t.observability.errors+=1);let o={...this.event("request",`${e.method} ${e.path}`,e.principal,n),statusCode:e.statusCode,durationMs:Math.max(0,Math.floor(e.durationMs))};this.pushEvent(t,o)})}async snapshot(){return eo(await this.ensureState())}};var mt="wiki/state.v1.json";function to(r){let e=new Date().toISOString();return{schema:"toolnet.wiki.v1",version:1,projectId:r.id,pages:[],revisions:[],createdAt:e,updatedAt:e}}function ro(r,e){let t=JSON.parse(r);if(t.schema!=="toolnet.wiki.v1"||t.version!==1||t.projectId!==e.id||!Array.isArray(t.pages)||!Array.isArray(t.revisions))throw new Error("Invalid ToolNet Wiki state");return t}var L=class{constructor(e,t){this.storage=e;this.project=t}storage;project;async load(){let e=await this.storage.getText(mt);if(!e){let t=to(this.project);return await this.save(t),t}return ro(e,this.project)}async save(e){await this.storage.put(mt,JSON.stringify(e,null,2),"application/json")}};import{randomUUID as gt}from"node:crypto";var g=class extends Error{constructor(t,n){super(t);this.statusCode=n}statusCode};function D(r){let e=new Set,t=[];for(let n of r){let o=n.replace(/\s+/gu," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();e.has(i)||(e.add(i),t.push(o))}return t}function F(r){let e=r.normalize("NFKD").replace(/[\u0300-\u036f]/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,120);if(!e)throw new g("Invalid Wiki slug",400);return e}function pt(r){let e=[];for(let t of r.matchAll(/\[\[([^\[\]]+)\]\]/gu)){let n=t[1]?.trim();n&&e.push(F(n))}return D(e)}function no(r){return r.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_-]+/u).map(e=>e.trim()).filter(e=>e.length>=2)}function ft(r){return{id:`revision-${gt()}`,pageId:r.id,slug:r.slug,revision:r.revision,title:r.title,...r.summary?{summary:r.summary}:{},content:r.content,tags:[...r.tags],links:[...r.links],createdAt:r.updatedAt}}function x(r){return structuredClone(r)}var $=class{constructor(e){this.store=e}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(e){let t,n=this.queue.then(async()=>{let o=await this.ensureState();t=e(o),o.updatedAt=new Date().toISOString(),await this.store.save(o)});return this.queue=n.then(()=>{},()=>{}),await n,t}async summary(){let e=await this.ensureState(),t=new Set(e.pages.flatMap(n=>n.links));return{schema:"toolnet.wiki-summary.v1",projectId:e.projectId,pages:e.pages.length,revisions:e.revisions.length,tags:D(e.pages.flatMap(n=>n.tags)).sort((n,o)=>n.localeCompare(o)),links:e.pages.reduce((n,o)=>n+o.links.length,0),orphanPages:e.pages.filter(n=>n.links.length===0&&!t.has(n.slug)).length,automatedPages:e.pages.filter(n=>n.tags.some(o=>o.startsWith("toolnet-auto-"))).length,updatedAt:e.updatedAt}}async listPages(){let e=await this.ensureState();return x([...e.pages].sort((t,n)=>t.title.localeCompare(n.title)))}async getPage(e){let t=await this.ensureState(),n=F(e),o=t.pages.find(i=>i.slug===n||i.id===e);if(!o)throw new g(`Wiki page not found: ${e}`,404);return x(o)}async createPage(e){return this.mutate(t=>{let n=e.title.trim(),o=e.content.trim();if(!n)throw new g("Wiki title is required",400);let i=F(e.slug??n);if(t.pages.some(c=>c.slug===i))throw new g(`Wiki page already exists: ${i}`,409);let s=new Date().toISOString(),a={id:`wiki-${gt()}`,slug:i,title:n,...e.summary?.trim()?{summary:e.summary.trim()}:{},content:o,tags:D(e.tags??[]),links:pt(o),revision:1,createdAt:s,updatedAt:s};return t.pages.push(a),t.revisions.push(ft(a)),x(a)})}async updatePage(e,t){return this.mutate(n=>{let o=F(e),i=n.pages.find(s=>s.slug===o||s.id===e);if(!i)throw new g(`Wiki page not found: ${e}`,404);if(t.title!==void 0){let s=t.title.trim();if(!s)throw new g("Wiki title is required",400);i.title=s}if(t.summary!==void 0){let s=t.summary.trim();s?i.summary=s:delete i.summary}return t.content!==void 0&&(i.content=t.content.trim(),i.links=pt(i.content)),t.tags!==void 0&&(i.tags=D(t.tags)),i.revision+=1,i.updatedAt=new Date().toISOString(),n.revisions.push(ft(i)),x(i)})}async history(e){let t=await this.getPage(e),n=await this.ensureState();return x(n.revisions.filter(o=>o.pageId===t.id).sort((o,i)=>i.revision-o.revision))}async backlinks(e){let t=await this.getPage(e),n=await this.ensureState();return x(n.pages.filter(o=>o.links.includes(t.slug)).sort((o,i)=>o.title.localeCompare(i.title)))}async search(e,t=10){let n=await this.ensureState(),o=D(no(e));if(o.length===0)return[];let i=Math.max(1,Math.min(20,Math.floor(t))),s=[];for(let a of n.pages){let c=a.title.toLowerCase(),d=a.slug.toLowerCase(),u=a.summary?.toLowerCase()??"",f=a.content.toLowerCase(),h=a.tags.map(b=>b.toLowerCase()),k=0;for(let b of o)d===b&&(k+=12),c===b&&(k+=10),c.includes(b)&&(k+=6),d.includes(b)&&(k+=5),h.some(we=>we===b)?k+=5:h.some(we=>we.includes(b))&&(k+=3),u.includes(b)&&(k+=2),f.includes(b)&&(k+=1);k>0&&s.push({page:x(a),score:k})}return s.sort((a,c)=>c.score-a.score||c.page.updatedAt.localeCompare(a.page.updatedAt)).slice(0,i)}};import{createHash as oo,randomUUID as yt}from"node:crypto";var ht="wiki/governance.v1.json",bt="toolnet.knowledge-governance.v1",kt=500,H={autoApproveThreshold:.86,criticalApproveThreshold:.94,staleAfterDays:90};function io(r,e=0,t=1){return Math.max(e,Math.min(t,r))}function Re(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/gu," ").trim()}function vt(r){return oo("sha256").update(r.normalize("NFKC").replace(/\s+/gu," ").trim()).digest("hex")}function so(r){let e=[r.title,r.summary??"",r.content.slice(0,2e3),...r.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(e)}function ao(r){let e=r.sourceType==="skill"?.96:r.sourceType==="memory"?.94:.88,t=r.tags.map(n=>n.toLowerCase());return(t.includes("permanent")||t.includes("task"))&&(e+=.03),r.content.length>=200&&(e+=.02),r.content.length<80&&(e-=.05),r.title.length<4&&(e-=.05),io(e)}function wt(r){let e=new Date().toISOString();return{schema:bt,version:1,projectId:r,policy:{...H},reviews:[],audit:[],createdAt:e,updatedAt:e}}function St(r){let e=r.autoApproveThreshold??H.autoApproveThreshold,t=r.criticalApproveThreshold??H.criticalApproveThreshold,n=r.staleAfterDays??H.staleAfterDays;if(!Number.isFinite(e)||e<.5||e>1)throw new g("Invalid autoApproveThreshold",400);if(!Number.isFinite(t)||t<.5||t>1)throw new g("Invalid criticalApproveThreshold",400);if(!Number.isInteger(n)||n<1||n>3650)throw new g("Invalid staleAfterDays",400);return{autoApproveThreshold:e,criticalApproveThreshold:t,staleAfterDays:n}}var W=class{constructor(e,t){this.storage=e;this.project=t}storage;project;async load(){let e=await this.storage.getText(ht);if(!e){let t=wt(this.project.id);return await this.save(t),t}try{let t=JSON.parse(e);if(t.schema!==bt||t.version!==1||t.projectId!==this.project.id||!Array.isArray(t.reviews)||!Array.isArray(t.audit))throw new Error("invalid");return{...t,policy:St(t.policy??H)}}catch{let t=wt(this.project.id);return await this.save(t),t}}async save(e){await this.storage.put(ht,JSON.stringify(e,null,2),"application/json")}},G=class{constructor(e){this.store=e}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}audit(e,t,n,o={}){e.audit.push({id:yt(),action:t,principal:n,...o.reviewId?{reviewId:o.reviewId}:{},...o.sourceKey?{sourceKey:o.sourceKey}:{},timestamp:new Date().toISOString(),...o.metadata?{metadata:o.metadata}:{}}),e.audit.length>kt&&(e.audit=e.audit.slice(-kt))}async mutate(e){let t,n=this.queue.then(async()=>{let o=await this.ensureState();t=await e(o),o.updatedAt=new Date().toISOString(),await this.store.save(o)});return this.queue=n.then(()=>{},()=>{}),await n,t}async policy(){return{...(await this.ensureState()).policy}}async setPolicy(e,t){return this.mutate(n=>(n.policy=St({...n.policy,...e}),this.audit(n,"policy:update",t,{metadata:{...n.policy}}),{...n.policy}))}async summary(){let e=await this.ensureState(),t=n=>e.reviews.filter(o=>o.status===n).length;return{schema:"toolnet.knowledge-governance-summary.v1",projectId:e.projectId,pending:t("pending"),approved:t("approved"),rejected:t("rejected"),superseded:t("superseded"),criticalPending:e.reviews.filter(n=>n.status==="pending"&&n.risk==="critical").length,conflictPending:e.reviews.filter(n=>n.status==="pending"&&n.risk==="conflict").length,auditEvents:e.audit.length,policy:{...e.policy},updatedAt:e.updatedAt}}async listReviews(e){let t=await this.ensureState();return structuredClone(t.reviews.filter(n=>!e||n.status===e).sort((n,o)=>o.updatedAt.localeCompare(n.updatedAt)))}async auditLog(e=100){let t=await this.ensureState(),n=Math.max(1,Math.min(500,Math.floor(e)));return structuredClone(t.audit.slice(-n).reverse())}async assess(e,t){let n=await this.ensureState(),o=ao(e),i=Re(e.title),s=t.filter(u=>u.slug!==e.slug&&Re(u.title)===i&&vt(u.content)!==vt(e.content)).map(u=>u.slug),a=so(e),c=[];o<n.policy.autoApproveThreshold&&c.push(`confidence:${o.toFixed(2)}`),a&&o<n.policy.criticalApproveThreshold&&c.push("critical-knowledge"),s.length>0&&c.push("conflicting-knowledge");let d=s.length>0?"conflict":a?"critical":"normal";return{confidence:o,risk:d,requiresReview:s.length>0||o<n.policy.autoApproveThreshold||a&&o<n.policy.criticalApproveThreshold,reasons:c,conflicts:s}}async gate(e,t){let n=await this.assess(e,t);return this.mutate(o=>{let i=o.reviews.find(c=>c.sourceKey===e.sourceKey&&c.digest===e.digest);if(i?.status==="approved")return{allowed:!0,mode:"review-approved",assessment:n,review:structuredClone(i)};if(i?.status==="rejected")return{allowed:!1,mode:"rejected",assessment:n,review:structuredClone(i)};if(!n.requiresReview)return this.audit(o,"knowledge:auto-approved","system",{sourceKey:e.sourceKey,metadata:{confidence:n.confidence,risk:n.risk}}),{allowed:!0,mode:"auto-approved",assessment:n};if(i?.status==="pending")return{allowed:!1,mode:"pending-review",assessment:n,review:structuredClone(i)};let s=new Date().toISOString(),a={id:yt(),sourceKey:e.sourceKey,sourceType:e.sourceType,slug:e.slug,marker:e.marker,digest:e.digest,title:e.title,...e.summary?{summary:e.summary}:{},content:e.content,tags:[...new Set([...e.tags,e.marker])],confidence:n.confidence,risk:n.risk,reasons:[...n.reasons],conflicts:[...n.conflicts],status:"pending",createdAt:s,updatedAt:s};return o.reviews.push(a),this.audit(o,"knowledge:review-requested","system",{reviewId:a.id,sourceKey:a.sourceKey,metadata:{confidence:a.confidence,risk:a.risk}}),{allowed:!1,mode:"pending-review",assessment:n,review:structuredClone(a)}})}async markApplied(e,t){await this.mutate(n=>{let o=n.reviews.find(i=>i.sourceKey===e&&i.digest===t&&i.status==="approved");o&&(o.appliedAt=new Date().toISOString(),o.updatedAt=o.appliedAt,this.audit(n,"knowledge:applied",o.reviewedBy??"system",{reviewId:o.id,sourceKey:e}))})}async decide(e,t,n){return this.mutate(async o=>{let i=o.reviews.find(d=>d.id===e);if(!i)throw new g(`Governance review not found: ${e}`,404);if(i.status!=="pending")throw new g("Governance review is already resolved",409);let s=new Date().toISOString();if(i.reviewedAt=s,i.reviewedBy=t.principal,i.updatedAt=s,t.note?.trim()&&(i.reviewNote=t.note.trim()),t.action==="reject")return i.status="rejected",this.audit(o,"knowledge:rejected",t.principal,{reviewId:e,sourceKey:i.sourceKey}),structuredClone(i);if(t.action==="supersede")return i.status="superseded",t.targetReviewId&&(i.supersededBy=t.targetReviewId),this.audit(o,"knowledge:superseded",t.principal,{reviewId:e,sourceKey:i.sourceKey,metadata:{targetReviewId:t.targetReviewId}}),structuredClone(i);if(t.action==="merge"){if(!t.targetReviewId)throw new g("targetReviewId is required for merge",400);let d=o.reviews.find(u=>u.id===t.targetReviewId);if(!d)throw new g("Merge target review not found",404);return i.status="superseded",i.mergedInto=d.id,this.audit(o,"knowledge:merged",t.principal,{reviewId:e,sourceKey:i.sourceKey,metadata:{targetReviewId:d.id}}),structuredClone(i)}i.status="approved";let c=(await n.listPages()).find(d=>d.slug===i.slug);if(c&&!c.tags.includes(i.marker))throw new g(`Wiki page '${i.slug}' is manually managed`,409);return c?await n.updatePage(i.slug,{title:i.title,summary:i.summary??"",content:i.content,tags:i.tags}):await n.createPage({slug:i.slug,title:i.title,...i.summary?{summary:i.summary}:{},content:i.content,tags:i.tags}),i.appliedAt=s,this.audit(o,"knowledge:approved",t.principal,{reviewId:e,sourceKey:i.sourceKey}),structuredClone(i)})}async quality(e){let t=await this.ensureState(),n=await e.listPages(),o=Date.now(),i=t.policy.staleAfterDays*864e5,s=n.map(u=>{let f=o-Date.parse(u.updatedAt);return{slug:u.slug,title:u.title,updatedAt:u.updatedAt,ageDays:Math.max(0,Math.floor(f/864e5)),stale:Number.isFinite(f)&&f>i}}).filter(u=>u.stale).map(({stale:u,...f})=>f),a=new Map;for(let u of n){let f=Re(u.title),h=a.get(f)??[];h.push(u),a.set(f,h)}let c=[...a.entries()].filter(([,u])=>u.length>1).map(([u,f])=>({title:u,pages:f.map(h=>h.slug)})),d=t.reviews.filter(u=>u.status==="pending");return{schema:"toolnet.knowledge-quality.v1",totalPages:n.length,automatedPages:n.filter(u=>u.tags.some(f=>f.startsWith("toolnet-auto-"))).length,manualPages:n.filter(u=>!u.tags.some(f=>f.startsWith("toolnet-auto-"))).length,stalePages:s,duplicateTitles:c,pendingReviews:d.length,lowConfidenceReviews:d.filter(u=>u.confidence<t.policy.autoApproveThreshold).length,conflicts:d.filter(u=>u.risk==="conflict").length,generatedAt:new Date().toISOString()}}};import{timingSafeEqual as Pi}from"node:crypto";import{createServer as Ci}from"node:http";function At(r){return{ok:!0,service:"toolnet-memory",schema:"toolnet.api-health.v1",project:{id:r.id,name:r.name,remote:r.remote??r.name}}}function Mt(r){return{schema:"toolnet.api-project.v1",project:{id:r.id,name:r.name,remote:r.remote??r.name,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,createdAt:r.createdAt,updatedAt:r.updatedAt}}}import{z as Gt}from"zod";import{existsSync as Mo,readFileSync as xo}from"node:fs";import{join as Po}from"node:path";import{existsSync as co,mkdirSync as fc,readFileSync as uo,renameSync as gc,writeFileSync as yc}from"node:fs";import{dirname as kc,join as lo}from"node:path";function mo(r){return lo(r.rootPath,".toolnet","work","current.json")}function Oe(r){let e=mo(r);if(!co(e))return null;try{let t=JSON.parse(uo(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as po,mkdirSync as bc,readFileSync as fo,renameSync as Sc,writeFileSync as Ac}from"node:fs";import{dirname as xc,join as go}from"node:path";function yo(r){return go(r.rootPath,".toolnet","context","session-origin.json")}function _e(r){let e=yo(r);if(!po(e))return null;try{let t=JSON.parse(fo(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ho(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function pe(r){let e=ho(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),n=/(?:đ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&&n?"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 vo,mkdirSync as su,readFileSync as wo}from"node:fs";import{join as xt}from"node:path";var qc=new I;function bo(r){return xt(r.rootPath,".toolnet","memory","checkpoints")}function So(r){return xt(bo(r),"latest.json")}function Ao(r){let e=So(r);if(!vo(e))return null;try{let t=JSON.parse(wo(e,"utf8"));return t.schema!=="toolnet.memory.checkpoint.v1"||t.project.id!==r.id?null:t}catch{return null}}function Pt(r){return Ao(r)}var Co={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}},Io={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function Eo(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function m(r,e){let t=e.value.replace(/\s+/g," ").trim();t&&r.push({...e,value:t,score:0})}function To(r){let e=Po(r.rootPath,".toolnet","work","handoff-latest.json");if(!Mo(e))return null;try{let n=JSON.parse(xo(e,"utf8")).continuity;return n?.schema!=="toolnet.handoff.v2"||n.project.id!==r.id?null:n}catch{return null}}function Ro(r){let e=Pt(r);if(!e)return[];let t=[];e.request&&m(t,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&m(t,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&m(t,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&m(t,{kind:"task",value:e.current.task.title,source:"checkpoint"});let n=e.files.active.at(-1);n&&m(t,{kind:"file",value:n,source:"checkpoint"});for(let o of e.nextActions)m(t,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)m(t,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)m(t,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)m(t,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)m(t,{kind:o.kind,value:o.content,source:"checkpoint"});return t}function Oo(r){let e=To(r);if(!e)return[];let t=[];m(t,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&m(t,{kind:"request",value:e.request,source:"handoff"}),e.activity&&m(t,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&m(t,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&m(t,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&m(t,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&m(t,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&m(t,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let n of e.blockers)m(t,{kind:"blocker",value:n,source:"handoff"});for(let n of e.decisions)m(t,{kind:"decision",value:n,source:"handoff"});for(let n of e.completed.tasks)m(t,{kind:"completed",value:n,source:"handoff"});for(let n of e.remaining.todos)m(t,{kind:"todo",value:n,source:"handoff"});return m(t,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),m(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),t}function _o(r){let e=_e(r);if(!e)return[];let t=[];return m(t,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&m(t,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&m(t,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&m(t,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&m(t,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&m(t,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&m(t,{kind:"decision",value:e.latestDecision,source:"session-origin"}),t}function jo(r){let e=Oe(r);if(!e)return[];let t=[];e.currentRequest&&m(t,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&m(t,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&m(t,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&m(t,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&m(t,{kind:"task",value:e.currentTask.title,source:"work-state"});let n=e.activeFiles?.at(-1)??e.filesTouched.at(-1);n&&m(t,{kind:"file",value:n,source:"work-state"});for(let o of e.nextActions.slice(0,5))m(t,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))m(t,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))m(t,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(i=>i.status==="completed").slice(-8))m(t,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(i=>i.status!=="completed"&&i.status!=="cancelled").slice(0,8))m(t,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))m(t,{kind:"test",value:o,source:"work-state"});return m(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),t}function Ko(r,e){let t=Co[r];return e.map((n,o)=>({...n,score:(t[n.kind]??10)+Io[n.source]+Math.max(0,5-o*.01)}))}function No(r){let e=new Map;for(let t of r){let n=`${t.kind}:${Eo(t.value)}`,o=e.get(n);(!o||t.score>o.score)&&e.set(n,t)}return[...e.values()]}function E(r,e,t={}){let n=pe(e),o=[...Ro(r),...Oo(r),..._o(r),...jo(r)],i=No(Ko(n,o)).sort((u,f)=>f.score-u.score),s=Math.max(1,t.maxFacts??12),a=Math.max(300,t.maxChars??3200),c=[],d=0;for(let u of i){if(c.length>=s)break;let f=u.kind.length+u.value.length+u.source.length+16;c.length>0&&d+f>a||(c.push(u),d+=f)}return{intent:n,facts:c,context:{project:{id:r.id,name:r.name},intent:n,selectedFacts:c.map(u=>({kind:u.kind,value:u.value,source:u.source}))},stats:{candidates:o.length,selected:c.length,chars:d}}}var Ct={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"},It=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],Lo={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:It};function Do(r){let e=r.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 Fo(r){let e=r.filter(n=>n.source==="handoff");if(e.length===0)return r;let t=r.filter(n=>n.source==="checkpoint"&&["rule","architecture","fix"].includes(n.kind));return[...e,...t]}function $o(r){let e=new Set,t=[];for(let n of r){let o=`${n.kind}:${n.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),t.push(n))}return t}function Et(r){switch(r){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function Ho(r,e){let t=[];for(let n of e){let o=r.filter(i=>i.kind===n).slice(0,Et(n));for(let i of o)t.push(`${Ct[n]}: ${i.value}`)}return t.join(`
|
|
6
|
-
`)}function
|
|
7
|
-
`)}function
|
|
8
|
-
|
|
9
|
-
`)}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Your job is to help another coding AI continue work from previous sessions.
|
|
16
|
-
|
|
17
|
-
Rules:
|
|
18
|
-
|
|
19
|
-
1. Answer only from the supplied ToolNet project memory.
|
|
20
|
-
2. Never invent completed work, files, blockers, decisions, or test results.
|
|
21
|
-
3. Prefer the latest session/work state over old information.
|
|
22
|
-
4. Be concise.
|
|
23
|
-
5. Do not dump raw JSON or full memory files.
|
|
24
|
-
6. Tell the coding agent exactly:
|
|
25
|
-
- what the previous agent was doing,
|
|
26
|
-
- what is already completed,
|
|
27
|
-
- what remains unfinished,
|
|
28
|
-
- what file was last touched,
|
|
29
|
-
- what should be done next,
|
|
30
|
-
when those facts are available.
|
|
31
|
-
7. If information is missing, say it is not recorded.
|
|
32
|
-
8. Do not explain ToolNet internals unless asked.
|
|
33
|
-
9. Do not repeat irrelevant history.
|
|
34
|
-
10. Respond in the same language as the question.
|
|
35
|
-
|
|
36
|
-
Think of yourself as the project's memory coworker talking directly to another AI.
|
|
37
|
-
`.trim()},{role:"user",content:`
|
|
38
|
-
Question from coding agent:
|
|
39
|
-
|
|
40
|
-
${e}
|
|
41
|
-
|
|
42
|
-
ToolNet selected memory:
|
|
43
|
-
|
|
44
|
-
${o}
|
|
45
|
-
|
|
46
|
-
Answer the coding agent directly.
|
|
47
|
-
`.trim()}]}),a=s.text.trim();return a?{answer:a,provider:s.provider,model:s.model,usedAi:!0}:{answer:n.answer,usedAi:!1}}catch{return{answer:n.answer,usedAi:!1}}}import{existsSync as Yo,mkdirSync as Qo,readFileSync as Xo,renameSync as Zo,rmSync as ei,writeFileSync as ti}from"node:fs";import{join as $t}from"node:path";var ri=720*60*1e3;function Ht(r){return $t(r.rootPath,".toolnet","context","memory-agent-conversation.json")}function q(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function ni(r){let e=q(r);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(t=>t.test(e))}function oi(r){if(ni(r))return!1;let e=q(r),t=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(n=>n.test(e))?!0:t.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function ii(r,e,t){let n=Ht(r);if(!Yo(n))return null;try{let o=JSON.parse(Xo(n,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==r.id||!Array.isArray(o.focus))return null;let i=Date.parse(o.updatedAt);return!Number.isFinite(i)||e-i>t?null:o}catch{return null}}function si(r,e=8){let t=new Set,n=[];for(let o of r){let i=o.value.replace(/\s+/gu," ").trim();if(!i)continue;let s=[o.kind,q(i)].join(":");if(!t.has(s)&&(t.add(s),n.push({...o,value:i}),n.length>=e))break}return n}function ai(r,e){let t=Ht(r),n=$t(r.rootPath,".toolnet","context");Qo(n,{recursive:!0,mode:448});let o=`${t}.${process.pid}.tmp`;try{ti(o,JSON.stringify(e,null,2)+`
|
|
48
|
-
`,{encoding:"utf8",mode:384}),Zo(o,t)}finally{ei(o,{force:!0})}}function ci(r){return r.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
|
|
49
|
-
`)}function ui(r,e){return r.priorFocus.find(t=>t.kind===e)?.value}function Ne(r){if(!r.usedPriorFocus||r.currentIntent!=="summary"||r.priorFocus.length===0)return null;let e=q(r.originalQuestion),t=/^(?:tại sao|vì sao|sao vậy|why|why so|why that)\b/u.test(e),n=/^(?:rồi sao|sau đó|tiếp thì sao|thế tiếp theo|then what|what next)\b/u.test(e),o=t?["decision","blocker","next_action","task","file"]:n?["next_action","todo","task","blocker","file","decision"]:["task","next_action","file","decision","blocker"],i={task:"Task li\xEAn quan",next_action:"Vi\u1EC7c ti\u1EBFp theo",file:"File li\xEAn quan",decision:"Quy\u1EBFt \u0111\u1ECBnh li\xEAn quan",blocker:"Blocker",todo:"TODO"},s=[];for(let a of o){let c=ui(r,a);if(c&&(s.push(`${i[a]??a}: ${c}.`),t&&s.length>=2||!t&&s.length>=3))break}return s.length===0?null:{answer:s.join(" "),intent:"summary",source:"conversation-focus"}}function li(r){let e=q(r);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)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function Wt(r,e,t={}){let n=t.now??Date.now(),o=t.maxAgeMs??ri,i=ii(r,n,o),s=!!(i&&i.focus.length>0&&oi(e)&&!li(e)),a=s&&i?[e.trim(),"","Previous ToolNet Memory conversation focus:",ci(i),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
|
|
50
|
-
`):e.trim(),c=pe(e),u=E(r,a,{maxFacts:8,maxChars:1800}).facts.map(h=>({kind:h.kind,value:h.value,source:h.source})),f=si(s&&i?[...u,...i.focus]:u);return ai(r,{schema:"toolnet.memory-conversation.v1",version:1,projectId:r.id,updatedAt:new Date(n).toISOString(),lastIntent:c,focus:f}),{question:a,originalQuestion:e,usedPriorFocus:s,previousIntent:i?.lastIntent,currentIntent:c,priorFocus:i?.focus??[],focusCount:f.length}}var tl={question:Gt.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:Gt.enum(["ai","local"]).optional().describe("ai uses ToolNet Memory Agent with configured LLM fallback chain. local returns deterministic local memory only.")};async function Ut(r,e){let t=Wt(r.project,e.question);if(e.mode==="local"){let o=Ne(t);if(o)return{answer:o.answer,mode:"local",usedAi:!1,source:o.source,intent:o.intent};let i=U(r.project,t.originalQuestion);return{answer:i.answer,mode:"local",usedAi:!1,source:i.source,intent:i.intent}}let n=await Ft(r.project,t.question);if(!n.usedAi){let o=Ne(t);if(o)return{answer:o.answer,mode:"ai",usedAi:!1,provider:n.provider,model:n.model}}return{answer:n.answer,mode:"ai",usedAi:n.usedAi,provider:n.provider,model:n.model}}import{z as Qt}from"zod";import{chmodSync as ol,existsSync as Bt,mkdirSync as il,readFileSync as zt,renameSync as sl,writeFileSync as al}from"node:fs";import{dirname as ul,join as J}from"node:path";var Vt="toolnet.context-offload.v1",di="toolnet.context-offload-asset.v1";function qt(r){return J(r,".toolnet","offload")}function Jt(r){return J(qt(r),"assets")}function mi(r){return J(qt(r),"graph.json")}function Le(){return{schema:Vt,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function pi(r){let e=mi(r);if(!Bt(e))return Le();try{let t=JSON.parse(zt(e,"utf8"));return t.schema!==Vt||t.version!==1||!Array.isArray(t.nodes)?Le():t}catch{return Le()}}function fi(r,e){let t=e.trim().toLowerCase();if(!/^[a-f0-9]{8,64}$/u.test(t))throw new Error("Invalid context offload asset reference.");if(t.length===64&&Bt(J(Jt(r),`${t}.json`)))return t;let n=pi(r).nodes.map(o=>o.id).filter(o=>o.startsWith(t));if(n.length===0)throw new Error(`Context offload asset not found: ${e}`);if(n.length>1)throw new Error(`Ambiguous context offload asset reference: ${e}`);return n[0]}function Yt(r,e,t=6e3){let n=fi(r,e),o=zt(J(Jt(r),`${n}.json`),"utf8"),i=JSON.parse(o);if(i.schema!==di||i.version!==1||i.assetId!==n)throw new Error(`Invalid context offload asset: ${e}`);let s=Math.max(200,Math.min(2e4,Math.floor(t)));return{assetId:n,kind:i.event.type,bytes:Buffer.byteLength(o,"utf8"),truncated:o.length>s,content:o.length>s?`${o.slice(0,s)}
|
|
51
|
-
[truncated]`:o}}var pl={assetId:Qt.string().regex(/^[a-f0-9]{8,64}$/iu).describe("Asset reference from the ToolNet Context Offload Graph."),maxChars:Qt.number().int().min(200).max(2e4).optional().describe("Maximum asset characters to return. Defaults to 6000.")};async function Xt(r,e){return Yt(r.project.rootPath,e.assetId,e.maxChars??6e3)}async function Zt(r,e){return{schema:"toolnet.api-memory-ask.v1",result:await Ut({project:r},e)}}async function er(r,e){return{schema:"toolnet.api-context-offload.v1",result:await Xt({project:r},e)}}import{z as tr}from"zod";var vl={query:tr.string(),limit:tr.number().int().min(1).max(20).optional()};async function rr(r,e){return r.retrieval.search(r.project.id,e.query,{topK:e.limit??8}).map(n=>({id:n.memory.id,type:n.memory.type,content:n.memory.content,importance:n.memory.importance,score:n.score,tags:n.memory.tags}))}import{z as ir}from"zod";import{chmodSync as Sl,existsSync as gi,mkdirSync as Al,readFileSync as yi,readdirSync as hi,renameSync as Ml,statSync as ki,writeFileSync as xl}from"node:fs";import{join as nr}from"node:path";var vi="toolnet.skill-memory.v1";function wi(r,e=Number.MAX_SAFE_INTEGER){let t=new Set,n=[];for(let o of r){let i=o.replace(/\s+/gu," ").trim();if(!i)continue;let s=i.normalize("NFKC").toLowerCase();if(!t.has(s)&&(t.add(s),n.push(i),n.length>=e))break}return n}function bi(r){return nr(r.rootPath,".toolnet","memory","skills")}function Si(r,e){if(!r||typeof r!="object")return!1;let t=r;return t.schema===vi&&t.version===1&&t.projectId===e&&typeof t.id=="string"&&typeof t.task=="string"&&Array.isArray(t.steps)&&Array.isArray(t.verification)&&Array.isArray(t.files)}function Ai(r){let e=bi(r);if(!gi(e))return[];if(!ki(e).isDirectory())return[];let t=[];for(let n of hi(e)){if(!n.endsWith(".json"))continue;let o=nr(e,n);try{let i=JSON.parse(yi(o,"utf8"));Si(i,r.id)&&t.push(i)}catch{}}return t.sort((n,o)=>{let i=o.createdAt.localeCompare(n.createdAt);return i!==0?i:n.id.localeCompare(o.id)})}function Mi(r){return wi(r.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_./-]+/gu).filter(e=>e.length>=2),32)}function xi(r,e){let t=e.normalize("NFKC").toLowerCase().trim();if(!t)return 0;if(r.id.toLowerCase()===t||r.fingerprint.toLowerCase()===t)return 1e3;let n=[r.title,r.task,r.summary,...r.steps,...r.verification,...r.files].join(`
|
|
52
|
-
`).normalize("NFKC").toLowerCase(),o=0;r.task.normalize("NFKC").toLowerCase().includes(t)&&(o+=40),r.title.normalize("NFKC").toLowerCase().includes(t)&&(o+=30);for(let i of Mi(t))n.includes(i)&&(o+=5),r.task.normalize("NFKC").toLowerCase().includes(i)&&(o+=4),r.files.some(s=>s.toLowerCase().includes(i))&&(o+=3);return o}function or(r,e,t=5){let n=Math.max(1,Math.min(10,Math.floor(t)));return Ai(r).map(o=>({...o,score:xi(o,e)})).filter(o=>o.score>0).sort((o,i)=>i.score!==o.score?i.score-o.score:i.createdAt.localeCompare(o.createdAt)).slice(0,n)}var Tl={query:ir.string().min(2).max(500).describe("Task, problem, file, command or workflow to match against successful reusable Skill Memory SOPs."),limit:ir.number().int().min(1).max(10).optional().describe("Maximum matching reusable SOPs to return. Default 5.")};async function sr(r,e){let t=or(r.project,e.query,e.limit??5);return{schema:"toolnet.skill-memory-search.v1",query:e.query,count:t.length,matches:t}}async function ar(r,e,t){return{schema:"toolnet.api-memory-search.v1",results:await rr({project:r,retrieval:e},t)}}async function cr(r,e){return{schema:"toolnet.api-skill-search.v1",result:await sr({project:r},e)}}function Y(r){if(!r||typeof r!="object"||Array.isArray(r))throw new Error("Invalid Memory Hub request");return r}function S(r,e,t=1,n=200){if(typeof r!="string"||r.trim().length<t||r.trim().length>n)throw new Error(`Invalid ${e}`);return r.trim()}function ur(r,e,t=500){if(r!==void 0)return S(r,e,1,t)}function De(r,e,t=64){if(r!==void 0){if(!Array.isArray(r)||r.length>t||r.some(n=>typeof n!="string"||!n.trim()))throw new Error(`Invalid ${e}`);return r.map(n=>n.trim())}}async function lr(r,e){return{schema:"toolnet.api-hub-summary.v1",hub:await r.summary(e)}}async function dr(r,e){return{schema:"toolnet.api-hub-teams.v1",teams:await r.listTeams(e)}}async function mr(r,e,t){let n=Y(t),o={...n.id!==void 0?{id:S(n.id,"team id",2,100)}:{},name:S(n.name,"team name",2,100),...n.description!==void 0?{description:ur(n.description,"team description",500)}:{}};return{schema:"toolnet.api-hub-team.v1",team:await r.createTeam(e,o)}}async function pr(r,e){return{schema:"toolnet.api-hub-agents.v1",agents:await r.listAgents(e)}}async function fr(r,e,t){let n=Y(t),o={...n.id!==void 0?{id:S(n.id,"agent id",2,100)}:{},name:S(n.name,"agent name",2,100),...n.kind!==void 0?{kind:ur(n.kind,"agent kind",100)}:{},...n.teamIds!==void 0?{teamIds:De(n.teamIds,"teamIds",64)}:{},...n.metadata&&typeof n.metadata=="object"&&!Array.isArray(n.metadata)?{metadata:n.metadata}:{}};return{schema:"toolnet.api-hub-agent.v1",agent:await r.createAgent(e,o)}}async function gr(r,e){return{schema:"toolnet.api-hub-acl.v1",grants:await r.listAcl(e)}}async function yr(r,e,t){let n=Y(t),o=S(n.role,"role",4,20);if(!["owner","admin","member","viewer"].includes(o))throw new Error("Invalid role");let i=De(n.scopes,"scopes",A.length);if(i?.some(a=>!A.includes(a)))throw new Error("Invalid Memory Hub scope");let s={principal:S(n.principal,"principal",1,120),role:o,...i?{scopes:i}:{}};return{schema:"toolnet.api-hub-acl-grant.v1",grant:await r.grantAcl(e,s)}}async function hr(r,e,t){let n=Y(t),o=S(n.principal,"principal",1,120);return await r.revokeAcl(e,o),{schema:"toolnet.api-hub-acl-revoke.v1",principal:o,revoked:!0}}async function kr(r,e){return{schema:"toolnet.api-hub-loadouts.v1",loadouts:await r.listLoadouts(e)}}async function vr(r,e,t){let n=Y(t),o=n.maxContextChars;if(o!==void 0&&(!Number.isInteger(o)||o<500||o>5e4))throw new Error("Invalid maxContextChars");let i=n.memoryMode;if(i!==void 0&&i!=="local"&&i!=="ai")throw new Error("Invalid memoryMode");if(n.skillMemory!==void 0&&typeof n.skillMemory!="boolean")throw new Error("Invalid skillMemory");if(n.contextOffload!==void 0&&typeof n.contextOffload!="boolean")throw new Error("Invalid contextOffload");let s={agentId:S(n.agentId,"agentId",2,100),...n.tools!==void 0?{tools:De(n.tools,"tools",64)}:{},...i?{memoryMode:i}:{},...n.skillMemory!==void 0?{skillMemory:n.skillMemory}:{},...n.contextOffload!==void 0?{contextOffload:n.contextOffload}:{},...o!==void 0?{maxContextChars:o}:{}};return{schema:"toolnet.api-hub-loadout.v1",loadout:await r.setLoadout(e,s)}}async function wr(r,e){return{schema:"toolnet.api-hub-observability.v1",observability:await r.observability(e)}}async function M(r,e,t){if(!await r.authorize(e,t))throw new g(`Principal '${e}' lacks '${t}'`,403)}function br(r){if(!r||typeof r!="object"||Array.isArray(r))throw new g("Invalid Wiki request",400);return r}function Fe(r,e,t){if(typeof r!="string"||!r.trim()||r.length>t)throw new g(`Invalid ${e}`,400);return r.trim()}function Sr(r,e,t){if(r!==void 0){if(typeof r!="string"||r.length>t)throw new g(`Invalid ${e}`,400);return r}}function Ar(r){if(r!==void 0){if(!Array.isArray(r)||r.length>50||r.some(e=>typeof e!="string"||e.length>100))throw new g("Invalid Wiki tags",400);return r}}async function Mr(r,e,t){return await M(e,t,"wiki:read"),{schema:"toolnet.api-wiki-summary.v1",wiki:await r.summary()}}async function xr(r,e,t){return await M(e,t,"wiki:read"),{schema:"toolnet.api-wiki-pages.v1",pages:await r.listPages()}}async function Pr(r,e,t,n){await M(e,t,"wiki:write");let o=br(n),i={...o.slug!==void 0?{slug:Fe(o.slug,"Wiki slug",120)}:{},title:Fe(o.title,"Wiki title",200),...o.summary!==void 0?{summary:Sr(o.summary,"Wiki summary",1e3)}:{},content:typeof o.content=="string"?o.content:"",...o.tags!==void 0?{tags:Ar(o.tags)}:{}};return{schema:"toolnet.api-wiki-page.v1",page:await r.createPage(i)}}async function Cr(r,e,t,n){return await M(e,t,"wiki:read"),{schema:"toolnet.api-wiki-page.v1",page:await r.getPage(n)}}async function Ir(r,e,t,n,o){await M(e,t,"wiki:write");let i=br(o),s={...i.title!==void 0?{title:Fe(i.title,"Wiki title",200)}:{},...i.summary!==void 0?{summary:Sr(i.summary,"Wiki summary",1e3)}:{},...i.content!==void 0?{content:typeof i.content=="string"?i.content:(()=>{throw new g("Invalid Wiki content",400)})()}:{},...i.tags!==void 0?{tags:Ar(i.tags)}:{}};return{schema:"toolnet.api-wiki-page.v1",page:await r.updatePage(n,s)}}async function Er(r,e,t,n,o){return await M(e,t,"wiki:read"),{schema:"toolnet.api-wiki-search.v1",query:n,results:await r.search(n,o)}}async function Tr(r,e,t,n){return await M(e,t,"wiki:read"),{schema:"toolnet.api-wiki-history.v1",revisions:await r.history(n)}}async function Rr(r,e,t,n){return await M(e,t,"wiki:read"),{schema:"toolnet.api-wiki-backlinks.v1",pages:await r.backlinks(n)}}async function C(r,e,t){if(!await r.authorize(e,t))throw new g(`Principal '${e}' lacks '${t}'`,403)}function Or(r){if(!r||typeof r!="object"||Array.isArray(r))throw new g("Invalid governance request",400);return r}async function _r(r,e,t){return await C(e,t,"governance:read"),{schema:"toolnet.api-governance-summary.v1",governance:await r.summary()}}async function jr(r,e,t,n){if(await C(e,t,"governance:read"),n&&!new Set(["pending","approved","rejected","superseded"]).has(n))throw new g("Invalid review status",400);return{schema:"toolnet.api-governance-reviews.v1",reviews:await r.listReviews(n)}}async function Kr(r,e,t,n,o,i){await C(t,n,"governance:write");let s=Or(i),a=s.action;if(a!=="approve"&&a!=="reject"&&a!=="supersede"&&a!=="merge")throw new g("Invalid governance action",400);if(s.note!==void 0&&typeof s.note!="string")throw new g("Invalid review note",400);if(s.targetReviewId!==void 0&&typeof s.targetReviewId!="string")throw new g("Invalid targetReviewId",400);return{schema:"toolnet.api-governance-review.v1",review:await r.decide(o,{action:a,principal:n,...typeof s.note=="string"?{note:s.note}:{},...typeof s.targetReviewId=="string"?{targetReviewId:s.targetReviewId}:{}},e)}}async function Nr(r,e,t,n){return await C(t,n,"governance:read"),{schema:"toolnet.api-knowledge-quality.v1",quality:await r.quality(e)}}async function Lr(r,e,t){return await C(e,t,"governance:read"),{schema:"toolnet.api-governance-policy.v1",policy:await r.policy()}}async function Dr(r,e,t,n){await C(e,t,"governance:write");let o=Or(n),i={};if(o.autoApproveThreshold!==void 0){if(typeof o.autoApproveThreshold!="number")throw new g("Invalid autoApproveThreshold",400);i.autoApproveThreshold=o.autoApproveThreshold}if(o.criticalApproveThreshold!==void 0){if(typeof o.criticalApproveThreshold!="number")throw new g("Invalid criticalApproveThreshold",400);i.criticalApproveThreshold=o.criticalApproveThreshold}if(o.staleAfterDays!==void 0){if(typeof o.staleAfterDays!="number")throw new g("Invalid staleAfterDays",400);i.staleAfterDays=o.staleAfterDays}return{schema:"toolnet.api-governance-policy.v1",policy:await r.setPolicy(i,t)}}async function Fr(r,e,t,n){return await C(e,t,"governance:read"),{schema:"toolnet.api-governance-audit.v1",events:await r.auditLog(n)}}function Ii(r){let e=r.headers["x-toolnet-principal"];return(Array.isArray(e)?e[0]:e)?.trim()||"anonymous"}function Ei(r,e){if(!e)return!0;let t=r.headers.authorization;if(!t?.startsWith("Bearer "))return!1;let n=Buffer.from(t.slice(7)),o=Buffer.from(e);return n.length===o.length&&Pi(n,o)}function p(r,e,t){r.statusCode=e,r.setHeader("content-type","application/json; charset=utf-8"),r.setHeader("cache-control","no-store"),r.end(JSON.stringify(t))}async function w(r){let e=[],t=0;for await(let n of r){let o=Buffer.isBuffer(n)?n:Buffer.from(n);if(t+=o.length,t>16384)throw new Error("Request body too large");e.push(o)}return e.length===0?{}:JSON.parse(Buffer.concat(e).toString("utf8"))}function Ti(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.question!="string"||e.question.length<2||e.question.length>4e3||e.mode!==void 0&&e.mode!=="ai"&&e.mode!=="local"?null:{question:e.question,...e.mode?{mode:e.mode}:{}}}function Ri(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.query!="string"||e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>20)?null:{query:e.query,...e.limit!==void 0?{limit:e.limit}:{}}}function Oi(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.query!="string"||e.query.length<2||e.query.length>500||e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>10)?null:{query:e.query,...e.limit!==void 0?{limit:e.limit}:{}}}function _i(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.assetId!="string"||!/^[a-f0-9]{8,64}$/iu.test(e.assetId)||e.maxChars!==void 0&&(!Number.isInteger(e.maxChars)||e.maxChars<200||e.maxChars>2e4)?null:{assetId:e.assetId,...e.maxChars!==void 0?{maxChars:e.maxChars}:{}}}function $r(r){return Ci(async(e,t)=>{try{let n=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`),o=Ii(e),i=Date.now();if(t.once("finish",()=>{r.hub&&r.hub.recordRequest({method:e.method??"GET",path:n.pathname,principal:o,statusCode:t.statusCode,durationMs:Date.now()-i}).catch(()=>{})}),n.pathname.startsWith("/v1/")&&!Ei(e,r.token)){p(t,401,{error:"Unauthorized"});return}if(e.method==="GET"&&n.pathname==="/v1/health"){p(t,200,At(r.project));return}if(e.method==="GET"&&n.pathname==="/v1/project"){p(t,200,Mt(r.project));return}if(e.method==="POST"&&n.pathname==="/v1/memory/ask"){let u=Ti(await w(e));if(!u){p(t,400,{error:"Invalid memory ask request"});return}p(t,200,await Zt(r.project,u));return}if(e.method==="POST"&&n.pathname==="/v1/memory/search"){let u=Ri(await w(e));if(!u){p(t,400,{error:"Invalid memory search request"});return}p(t,200,await ar(r.project,r.retrieval,u));return}if(e.method==="POST"&&n.pathname==="/v1/skills/search"){let u=Oi(await w(e));if(!u){p(t,400,{error:"Invalid skill search request"});return}p(t,200,await cr(r.project,u));return}if(e.method==="POST"&&n.pathname==="/v1/offload/read"){let u=_i(await w(e));if(!u){p(t,400,{error:"Invalid context offload request"});return}p(t,200,await er(r.project,u));return}if(n.pathname.startsWith("/v1/hub")&&!r.hub){p(t,503,{error:"Memory Hub unavailable"});return}if(e.method==="GET"&&n.pathname==="/v1/hub"){p(t,200,await lr(r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/hub/teams"){p(t,200,await dr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/teams"){p(t,201,await mr(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/agents"){p(t,200,await pr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/agents"){p(t,201,await fr(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/acl"){p(t,200,await gr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/acl/grant"){p(t,200,await yr(r.hub,o,await w(e)));return}if(e.method==="POST"&&n.pathname==="/v1/hub/acl/revoke"){p(t,200,await hr(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/loadouts"){p(t,200,await kr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/loadouts"){p(t,200,await vr(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/observability"){p(t,200,await wr(r.hub,o));return}if(n.pathname.startsWith("/v1/wiki")&&(!r.wiki||!r.hub)){p(t,503,{error:"Wiki unavailable"});return}if(e.method==="GET"&&n.pathname==="/v1/wiki"){p(t,200,await Mr(r.wiki,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/wiki/pages"){p(t,200,await xr(r.wiki,r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/wiki/pages"){p(t,201,await Pr(r.wiki,r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/wiki/search"){let u=n.searchParams.get("q")??"",f=Number(n.searchParams.get("limit")??10),h=Number.isInteger(f)?Math.max(1,Math.min(20,f)):10;p(t,200,await Er(r.wiki,r.hub,o,u,h));return}let s=/^\/v1\/wiki\/pages\/([^/]+)\/history$/u.exec(n.pathname);if(e.method==="GET"&&s){p(t,200,await Tr(r.wiki,r.hub,o,decodeURIComponent(s[1])));return}let a=/^\/v1\/wiki\/pages\/([^/]+)\/backlinks$/u.exec(n.pathname);if(e.method==="GET"&&a){p(t,200,await Rr(r.wiki,r.hub,o,decodeURIComponent(a[1])));return}let c=/^\/v1\/wiki\/pages\/([^/]+)$/u.exec(n.pathname);if(e.method==="GET"&&c){p(t,200,await Cr(r.wiki,r.hub,o,decodeURIComponent(c[1])));return}if(e.method==="PUT"&&c){p(t,200,await Ir(r.wiki,r.hub,o,decodeURIComponent(c[1]),await w(e)));return}if(n.pathname.startsWith("/v1/governance")&&(!r.governance||!r.wiki||!r.hub)){p(t,503,{error:"Knowledge Governance unavailable"});return}if(e.method==="GET"&&n.pathname==="/v1/governance"){p(t,200,await _r(r.governance,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/governance/reviews"){p(t,200,await jr(r.governance,r.hub,o,n.searchParams.get("status")??void 0));return}let d=/^\/v1\/governance\/reviews\/([^/]+)$/u.exec(n.pathname);if(e.method==="POST"&&d){p(t,200,await Kr(r.governance,r.wiki,r.hub,o,decodeURIComponent(d[1]),await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/governance/quality"){p(t,200,await Nr(r.governance,r.wiki,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/governance/policy"){p(t,200,await Lr(r.governance,r.hub,o));return}if(e.method==="PUT"&&n.pathname==="/v1/governance/policy"){p(t,200,await Dr(r.governance,r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/governance/audit"){let u=Number(n.searchParams.get("limit")??100),f=Number.isInteger(u)?Math.max(1,Math.min(500,u)):100;p(t,200,await Fr(r.governance,r.hub,o,f));return}p(t,404,{error:"Not found"})}catch(n){if(n instanceof v||n instanceof g){p(t,n.statusCode,{error:n.message});return}if(n instanceof Error&&n.message.startsWith("Invalid ")){p(t,400,{error:n.message});return}p(t,500,{error:n instanceof Error?n.message:String(n)})}})}var Hr=process.env.TOOLNET_API_HOST??"127.0.0.1",Wr=Number(process.env.TOOLNET_API_PORT??9750);async function ji(){let r=be(),e=new X().detect(),t=it({provider:r.storage.provider,r2:r.storage.r2,s3:r.storage.s3,huggingface:r.storage.huggingface,localRoot:r.storage.localRoot}),n=at(t,{attempts:Number(process.env.TOOLNET_STORAGE_RETRIES??3)}),o=new le(n,e.id,e.name,e.remote??e.name),i=new de(o,e,process.env.TOOLNET_HUB_OWNER?.trim()||"owner"),s=new me(i,Number(process.env.TOOLNET_HUB_MAX_EVENTS??100));await s.initialize();let a=new L(o,e),c=new $(a);await c.initialize();let d=new G(new W(o,e));await d.initialize();let u=new re,f=new ue(o);u.importRecords(await f.load(e.id));let h=new ae(u);$r({project:e,retrieval:h,token:process.env.TOOLNET_API_TOKEN?.trim()||void 0,hub:s,wiki:c,governance:d}).listen(Wr,Hr,()=>{console.log("ToolNet Memory API"),console.log(`Project: ${e.name}`),console.log(`Listening: http://${Hr}:${Wr}`)})}ji().catch(r=>{console.error(r),process.exit(1)});
|
|
1
|
+
import"dotenv/config";import{existsSync as Pr,readFileSync as Ir}from"node:fs";import{homedir as Tr}from"node:os";import{join as Rr}from"node:path";function jr(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Er(){let r=process.env.TOOLNET_GLOBAL_ENV??Rr(Tr(),".config","toolnet-memory",".env");if(!Pr(r))return;let e=Ir(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let i=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=jr(n.slice(o+1)))}}Er();function T(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function R(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function le(){return{memory:{autoCapture:T(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:T(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:T(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:T(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:R(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:R(process.env.MEMORY_RERANK_TOP,10),finalContext:R(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:R(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:T(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:R(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}var Or={critical:100,high:75,normal:50,temporary:20};function Pe(r){return Or[r]}function Ie(r,e){let t=e.toLowerCase();return t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c")||t.includes("must not")||t.includes("critical")?"critical":r==="rule"||r==="decision"?"high":r==="todo"?"normal":r==="activity"||r==="summary"?"temporary":"normal"}import{createHash as _r}from"node:crypto";import{existsSync as de,mkdirSync as Kr,readFileSync as $r,renameSync as Nr,writeFileSync as Fr}from"node:fs";import{basename as Hr,dirname as V,join as B,parse as je,resolve as j}from"node:path";var Ee=".toolnet",Lr="project.json";function Dr(r){return _r("sha256").update(r).digest("hex").slice(0,16)}function me(r){return B(r,Ee,Lr)}function Wr(r){return de(me(r))}function zr(r,e){let t=j(r),n=je(t).root;for(;;){if(Wr(t))return t;if(t===n||e&&t===j(e))break;let o=V(t);if(o===t)break;t=o}return null}function Gr(r){let e=j(r),t=je(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>de(B(e,i))))return e;if(e===t)break;let o=V(e);if(o===e)break;e=o}return j(r)}function Vr(r){let e;try{e=JSON.parse($r(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:V(V(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function Te(r,e){let t=B(r,Ee);Kr(t,{recursive:!0});let n=me(r),o=`${n}.tmp-${process.pid}`;Fr(o,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),Nr(o,n)}function Re(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var q=class{detect(e=process.cwd()){let t=j(e),n=Gr(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>de(B(n,u))),s=zr(t,i?n:void 0);if(s){let u=me(s),p=Vr(u);return p.rootPath!==s&&(p.rootPath=s,p.updatedAt=new Date().toISOString(),Te(s,p)),Re(p,s)}let a=new Date().toISOString(),c=Hr(n),l={version:1,id:Dr(n),name:c,remote:c,rootPath:n,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return Te(n,l),Re(l,n)}};import{randomUUID as an}from"node:crypto";var qr=[{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}],U=class{scan(e){let t=[];for(let n of qr){let o=new RegExp(n.regex.source,n.regex.flags);for(let i of e.matchAll(o))t.push({type:n.type,value:i[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var C=class{scanner=new U;sanitize(e){let t=e,n=this.scanner.scan(e),o=new Set;for(let i of n)o.add(i.type),t=t.split(i.value).join(`[REDACTED:${i.type}]`);return{text:t,redacted:n.length,secretTypes:[...o]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[n,o]of Object.entries(e)){let i=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");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")?t[n]="[REDACTED]":t[n]=this.sanitizeValue(o)}return t}return e}};var Br=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),Ur=new Set(["d\xF9ng","s\u1EED","d\u1EE5ng","use","using","the","a","an","cho","v\xE0","l\xE0","c\u1EE7a","to","for","with","quy\u1EBFt","\u0111\u1ECBnh"]);function Oe(r){return new Set(r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!Ur.has(e)))}function Jr(r,e){let t=Oe(r),n=Oe(e);if(t.size===0||n.size===0)return 0;let o=0;for(let s of t)n.has(s)&&o++;let i=new Set([...t,...n]).size;return o/i}function _e(r){return new Set(r.tags.filter(e=>!Br.has(e.toLowerCase())))}var J=class{findSuperseded(e,t){if(e.type!=="rule"&&e.type!=="decision")return[];let n=typeof e.metadata?.topic=="string"?e.metadata.topic:void 0,o=_e(e);return t.filter(i=>{if(i.id===e.id||i.projectId!==e.projectId||i.type!==e.type||i.metadata?.supersededBy)return!1;let s=typeof i.metadata?.topic=="string"?i.metadata.topic:void 0;if(n&&s&&n===s)return!0;let a=_e(i);for(let c of o)if(a.has(c))return!0;return Jr(e.content,i.content)>=.6})}};var Qr=new Set(["code","decision","rule","todo","summary"]);function Yr(r){return r.normalize("NFKC").toLowerCase().replace(/[“”"'`]/gu,"").replace(/[.!?]+$/gu,"").replace(/\s+/gu," ").trim()}function Ke(r){return r.tags.includes("class:permanent")?4:r.tags.includes("class:task")?3:r.tags.includes("class:session")?2:r.tags.includes("class:transient")?1:0}function Xr(r,e){let t=Ke(e)-Ke(r);if(t!==0)return t;let n=e.importanceScore-r.importanceScore;if(n!==0)return n;let o=e.updatedAt.localeCompare(r.updatedAt);if(o!==0)return o;let i=e.createdAt.localeCompare(r.createdAt);return i!==0?i:r.id.localeCompare(e.id)}function $e(r){let e=new Set,t=[];for(let n of r){let o=n.trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();e.has(i)||(e.add(i),t.push(o))}return t}function Ne(r){let e=new Map;for(let o of r){if(!Qr.has(o.type)||o.metadata?.supersededBy)continue;let i=Yr(o.content);if(!i)continue;let s=[o.projectId,o.type,i].join("\0"),a=e.get(s)??[];a.push(o),e.set(s,a)}let t=[],n=0;for(let o of e.values()){if(o.length<2)continue;let i=[...o].sort(Xr),s=i[0];if(!s)continue;let a=i.slice(1);t.push({canonicalId:s.id,duplicateIds:a.map(c=>c.id),mergedTags:$e(i.flatMap(c=>c.tags)),mergedSources:$e(i.map(c=>c.source))}),n+=a.length}return{groups:t,duplicates:n}}function pe(r){if(r.tags.includes("class:permanent"))return"permanent";if(r.tags.includes("class:task"))return"task";if(r.tags.includes("class:session"))return"session";if(r.tags.includes("class:transient"))return"transient"}function Zr(r,e){let t=new Date(r.updatedAt).getTime();return Number.isFinite(t)?Math.max(0,(e-t)/864e5):0}function en(r){let e=pe(r);if(e==="permanent")return 730;if(e==="task")return 180;if(e==="session")return 45;if(e==="transient")return 7;switch(r.type){case"rule":return 730;case"decision":return 365;case"code":return 180;case"todo":return 120;case"summary":return 45;case"activity":return 14}}function tn(r){return pe(r)==="permanent"||r.type==="rule"||r.type==="decision"||r.importance==="critical"}function rn(r){let e=r.normalize("NFKC").toLowerCase().trim();return e.length<8?!0:[/^ok(?:ay)?[.!]?$/u,/^done[.!]?$/u,/^thanks?[.!]?$/u,/^test(?:ing)?[.!]?$/u,/^npm notice\b/u,/^changed \d+ packages?/u,/^packages? are looking for funding/u].some(t=>t.test(e))}function Fe(r,e=Date.now()){let t=50,n=[],o=pe(r);switch(o==="permanent"?(t+=25,n.push("permanent project knowledge")):o==="task"?(t+=15,n.push("active task knowledge")):o==="session"?(t+=2,n.push("session-scoped knowledge")):o==="transient"&&(t-=25,n.push("transient knowledge")),r.importance){case"critical":t+=25,n.push("critical importance");break;case"high":t+=15,n.push("high importance");break;case"normal":break;case"temporary":t-=15,n.push("temporary importance");break}(r.type==="rule"||r.type==="decision")&&(t+=10,n.push("durable knowledge type"));let i=r.content.trim().length;i<12?(t-=30,n.push("very short content")):i<30?(t-=10,n.push("limited context")):i<=1200?(t+=8,n.push("useful context density")):i>5e3&&(t-=15,n.push("excessively large memory")),rn(r.content)&&(t-=35,n.push("matches transient/noise pattern"));let s=r.metadata?.consolidation;s&&typeof s=="object"&&Array.isArray(s.sources)&&s.sources.length>1&&(t+=10,n.push("confirmed across multiple sources"));let a=Zr(r,e)>=en(r);a&&(t-=15,n.push("stale for lifecycle class"));let c=tn(r);t=Math.max(0,Math.min(100,Math.round(t)));let l;t>=80?l="trusted":t>=55?l="useful":t>=30?l="weak":l="noise";let u=r.importance==="temporary"||r.type==="activity"||o==="transient";return{score:t,tier:l,stale:a,protected:c,pruneEligible:!c&&(l==="noise"&&u||a&&(l==="noise"||l==="weak")),reasons:n}}var nn={critical:100,high:75,normal:50,temporary:20},on={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function He(r,e,t=new Date){let n;if(e==="temporary"&&(n=30),r==="activity"&&(n=Math.min(n??14,14)),r==="summary"&&(n=Math.min(n??30,30)),!!n)return new Date(t.getTime()+n*864e5).toISOString()}function fe(r,e=Date.now()){return r.expiresAt?new Date(r.expiresAt).getTime()<=e:!1}function sn(r){return!!r.metadata?.supersededBy}function ge(r,e=Date.now()){return!fe(r,e)&&!sn(r)}function E(r,e=Date.now()){if(!ge(r,e))return 0;let t=nn[r.importance];if(r.importance==="critical")return t;let n=on[r.type]??180,i=Math.max(0,e-new Date(r.updatedAt).getTime())/864e5,s=Math.pow(.5,i/n);return t*s}var Q=class{memories=new Map;sanitizer=new C;conflicts=new J;remember(e){let t=new Date().toISOString(),n=this.sanitizer.sanitize(e.content.trim()).text,o=e.importance??Ie(e.type,n),i={id:an(),projectId:e.projectId,type:e.type,content:n,importance:o,importanceScore:Pe(o),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??He(e.type,o,new Date(t)),metadata:this.sanitizer.sanitizeValue(e.metadata)},s=this.conflicts.findSuperseded(i,this.list(e.projectId));if(s.length){i.metadata={...i.metadata??{},supersedes:s.map(a=>a.id)};for(let a of s)a.updatedAt=t,a.metadata={...a.metadata??{},supersededBy:i.id,supersededAt:t},this.memories.set(a.id,a)}return this.memories.set(i.id,i),i}importRecords(e){let t=0;for(let n of e)n?.id&&(this.memories.set(n.id,n),t++);return t}exportProject(e){return this.listAll(e)}get(e){return this.memories.get(e)}delete(e){return this.memories.delete(e)}listAll(e){return[...this.memories.values()].filter(t=>t.projectId===e).sort((t,n)=>n.createdAt.localeCompare(t.createdAt))}list(e){return this.listAll(e).filter(t=>ge(t))}recent(e,t=10){return this.list(e).slice(0,t)}byType(e,t){return this.list(e).filter(n=>n.type===t)}search(e){let t=e.query.trim().toLowerCase(),n=e.limit??10,o=t.split(/\s+/).filter(Boolean);return this.list(e.projectId).filter(i=>{if(e.types&&!e.types.includes(i.type))return!1;let s=E(i);return!(e.minImportanceScore&&s<e.minImportanceScore||e.tags?.length&&!e.tags.some(c=>i.tags.includes(c)))}).map(i=>{let s=i.content.toLowerCase(),a=o.filter(u=>s.includes(u)).length,c=o.length===0?0:a/o.length,l=E(i)/500;return{memory:i,score:c+l,source:"memory"}}).filter(i=>t.length===0||i.score>0).sort((i,s)=>s.score-i.score).slice(0,n)}consolidate(e,t=Date.now()){let n=Ne(this.list(e)),o=[],i=0;for(let s of n.groups){let a=this.memories.get(s.canonicalId);if(a){a.tags=s.mergedTags,a.metadata={...a.metadata??{},consolidation:{version:1,consolidatedAt:new Date(t).toISOString(),mergedIds:s.duplicateIds,sources:s.mergedSources}},this.memories.set(a.id,a),o.push(a.id);for(let c of s.duplicateIds)this.memories.delete(c)&&(i+=1)}}return{groupsConsolidated:o.length,duplicatesRemoved:i,canonicalIds:o}}reviewLifecycle(e,t=Date.now()){let n={reviewed:0,trusted:0,useful:0,weak:0,noise:0,stale:0,protected:0,pruned:0};for(let o of this.list(e)){let i=Fe(o,t);n.reviewed+=1,n[i.tier]+=1,i.stale&&(n.stale+=1),i.protected&&(n.protected+=1),o.metadata={...o.metadata??{},lifecycle:{version:1,reviewedAt:new Date(t).toISOString(),qualityScore:i.score,tier:i.tier,stale:i.stale,protected:i.protected,reasons:i.reasons}},this.memories.set(o.id,o),i.pruneEligible&&this.memories.delete(o.id)&&(n.pruned+=1)}return n}pruneExpired(e,t=Date.now()){let n=0;for(let[o,i]of this.memories)i.projectId===e&&fe(i,t)&&(this.memories.delete(o),n++);return n}pruneSuperseded(e,t=30,n=Date.now()){let o=0,i=t*864e5;for(let[s,a]of this.memories){if(a.projectId!==e)continue;let c=a.metadata?.supersededAt;if(typeof c!="string")continue;n-new Date(c).getTime()>=i&&(this.memories.delete(s),o++)}return o}clearProject(e){let t=0;for(let[n,o]of this.memories)o.projectId===e&&(this.memories.delete(n),t++);return t}};function ye(r){return r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}var Y=class{score(e,t){let n=ye(e),o=ye([t.content,...t.tags??[],t.type].join(" "));if(n.length===0||o.length===0)return 0;let i=new Map;for(let a of o)i.set(a,(i.get(a)??0)+1);let s=0;for(let a of n){let c=i.get(a)??0;c!==0&&(s+=1+Math.log(1+c))}return s/n.length}};function Le(r,e=Date.now()){let t=r.updatedAt??r.createdAt,n=new Date(t).getTime();if(!Number.isFinite(n))return 0;let o=Math.max(0,e-n)/864e5;return Math.exp(-Math.LN2*o/30)}function De(r){return E(r)/100}var cn={rule:1,decision:.9,todo:.8,summary:.6,activity:.3};function We(r){return cn[r]??.4}var X=class{analyze(e){let t=e.toLowerCase(),n=[];return(t.includes("quy\u1EBFt \u0111\u1ECBnh")||t.includes("decision")||t.includes("\u0111\xE3 ch\u1ECDn"))&&n.push("decision"),(t.includes("todo")||t.includes("c\u1EA7n l\xE0m")||t.includes("ti\u1EBFp theo")||t.includes("ch\u01B0a xong"))&&n.push("todo"),(t.includes("quy t\u1EAFc")||t.includes("rule")||t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c"))&&n.push("rule"),(t.includes("t\xF3m t\u1EAFt")||t.includes("summary")||t.includes("\u0111\xE3 l\xE0m"))&&n.push("summary"),{query:e,preferredTypes:n}}};var Z=class{bm25=new Y;analyzer=new X;search(e,t,n={}){let o=n.topK??8,i=n.minScore??.05,s=this.analyzer.analyze(e),a=[];for(let c of t){if(n.types?.length&&!n.types.includes(c.type))continue;let l=this.bm25.score(e,c),u=Le(c),p=De(c),g=We(c.type);s.preferredTypes.includes(c.type)&&(g=Math.min(1,g+.25));let y=l*.55+p*.2+u*.15+g*.1;l<=0||y<i||a.push({memory:c,score:y,scores:{keyword:l,recency:u,importance:p,type:g}})}return a.sort((c,l)=>l.score-c.score).slice(0,o)}};var ee=class{build(e,t=6e3){let n=[],o=0;for(let i of e){let s=i.memory,a=[`[${s.type.toUpperCase()}]`,s.content].join(" ");if(o+a.length>t)break;n.push(a),o+=a.length}return n.join(`
|
|
4
|
+
`)}};var te=class{constructor(e){this.memory=e}memory;searcher=new Z;contextBuilder=new ee;search(e,t,n={}){return this.searcher.search(t,this.memory.list(e),n)}context(e,t,n={}){let o=this.search(e,t,n);return this.contextBuilder.build(o)}};import{homedir as jn}from"node:os";import{join as En}from"node:path";import{DeleteObjectCommand as un,GetObjectCommand as ln,HeadObjectCommand as dn,ListObjectsV2Command as mn,PutObjectCommand as pn,S3Client as fn}from"@aws-sdk/client-s3";import{getSignedUrl as gn}from"@aws-sdk/s3-request-presigner";var re=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new fn({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new pn({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await gn(this.client,new ln({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new dn({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new un({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new mn({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let i of o.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as ze,mkdir as yn,readFile as hn,readdir as kn,rm as vn,stat as Ge,writeFile as wn}from"node:fs/promises";import{dirname as bn,join as Sn,relative as Ve,resolve as xn}from"node:path";var O=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return xn(this.root,t)}async put(e,t){let n=this.path(e);await yn(bn(n),{recursive:!0}),await wn(n,t)}async get(e){try{return await hn(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await ze(this.path(e)),!0}catch{return!1}}async delete(e){await vn(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await ze(t)}catch{return n}let o=async s=>{let a=await kn(s,{withFileTypes:!0});for(let c of a){let l=Sn(s,c.name);if(c.isDirectory()){await o(l);continue}let u=await Ge(l);n.push({key:Ve(this.root,l),size:u.size,updatedAt:u.mtime.toISOString()})}},i=await Ge(t);return i.isDirectory()?await o(t):n.push({key:Ve(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),n}};import{DeleteObjectCommand as Mn,GetObjectCommand as An,HeadObjectCommand as Cn,ListObjectsV2Command as Pn,PutObjectCommand as In,S3Client as Tn}from"@aws-sdk/client-s3";import{getSignedUrl as Rn}from"@aws-sdk/s3-request-presigner";var _=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Tn({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new In({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Rn(this.client,new An({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Cn({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Mn({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Pn({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let i of o.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};function he(r,e){return console.warn(e),new O(r)}function qe(r){let e=r.localRoot??En(jn(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new _({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):he(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new _({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):he(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new re({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):he(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new O(e)}var ne=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let n=JSON.parse(t);if(!Array.isArray(n))throw new Error("Invalid memory snapshot");return n}async save(e,t){let n=JSON.stringify(t,null,2);await this.storage.put(this.key(e),n,"application/json")}};function On(r){return new Promise(e=>setTimeout(e,r))}async function Be(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,i;for(let s=1;s<=t;s++)try{return await r()}catch(a){if(i=a,s>=t)break;let c=Math.min(o,n*2**(s-1)),l=Math.floor(Math.random()*Math.max(1,c*.2));await On(c+l)}throw i}var _n=new Set(["put","get","getText","delete","list"]);function Ue(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:_n.has(n)?(...i)=>Be(()=>Promise.resolve(o.apply(t,i)),e):o.bind(t)}})}function Je(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Qe(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var oe=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=Je(o??n),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),n=t,o=await this.provider.getText(e);if(o){let s;try{s=JSON.parse(o)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof s.id=="string"&&s.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${s.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof s.createdAt=="string"&&(n=s.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
|
|
5
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Qe(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};var b=["hub:read","teams:write","agents:write","acl:manage","loadouts:write","observability:read","wiki:read","wiki:write","governance:read","governance:write"];var Ye="hub/state.v1.json";function Kn(r,e){let t=new Date().toISOString();return{schema:"toolnet.memory-hub.v1",version:1,ownerPrincipal:e,project:{id:r.id,name:r.name,remote:r.remote??r.name},teams:[],agents:[],acl:[{principal:e,role:"owner",scopes:[...b],createdAt:t,updatedAt:t}],loadouts:[],observability:{requests:0,mutations:0,errors:0,events:[]},createdAt:t,updatedAt:t}}function $n(r,e){let t=JSON.parse(r);if(t.schema!=="toolnet.memory-hub.v1"||t.version!==1||!t.project||t.project.id!==e.id||!Array.isArray(t.teams)||!Array.isArray(t.agents)||!Array.isArray(t.acl)||!Array.isArray(t.loadouts)||!t.observability||!Array.isArray(t.observability.events))throw new Error("Invalid ToolNet Memory Hub state");return t}var ie=class{constructor(e,t,n){this.storage=e;this.project=t;this.ownerPrincipal=n}storage;project;ownerPrincipal;async load(){let e=await this.storage.getText(Ye);if(!e){let t=Kn(this.project,this.ownerPrincipal);return await this.save(t),t}return $n(e,this.project)}async save(e){await this.storage.put(Ye,JSON.stringify(e,null,2),"application/json")}};import{randomUUID as ke}from"node:crypto";var Xe=["memory_search","memory_agent_ask","skill_memory_search","context_offload_read","wiki_search","wiki_read","knowledge_governance_status"],h=class extends Error{constructor(t,n){super(t);this.statusCode=n}statusCode};function Nn(r){return r==="owner"||r==="admin"?[...b]:["hub:read"]}function ve(r){return[...new Set(r.map(e=>e.trim()).filter(Boolean))]}function Fn(r){return structuredClone(r)}var se=class{constructor(e,t=100){this.store=e;this.maxEvents=t}store;maxEvents;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}async mutate(e){let t,n=this.queue.then(async()=>{let o=await this.ensureState();t=e(o),o.updatedAt=new Date().toISOString(),await this.store.save(o)});return this.queue=n.then(()=>{},()=>{}),await n,t}grantFor(e,t){return e.acl.find(n=>n.principal===t)}async authorize(e,t){let n=await this.ensureState(),o=this.grantFor(n,e);return!!(o&&(o.role==="owner"||o.role==="admin"||o.scopes.includes(t)))}async requireScope(e,t){if(!await this.authorize(e,t))throw new h(`Principal '${e}' lacks '${t}'`,403)}event(e,t,n,o){return{id:ke(),kind:e,action:t,principal:n,ok:o,timestamp:new Date().toISOString()}}pushEvent(e,t){e.observability.events.push(t),e.observability.events.length>this.maxEvents&&(e.observability.events=e.observability.events.slice(-this.maxEvents)),e.observability.lastActivityAt=t.timestamp}mutation(e,t,n){e.observability.mutations+=1,this.pushEvent(e,this.event("mutation",t,n,!0))}async summary(e){await this.requireScope(e,"hub:read");let t=await this.ensureState();return{schema:t.schema,project:{...t.project},teams:t.teams.length,agents:t.agents.length,aclGrants:t.acl.length,loadouts:t.loadouts.length,updatedAt:t.updatedAt}}async listTeams(e){return await this.requireScope(e,"hub:read"),structuredClone((await this.ensureState()).teams)}async createTeam(e,t){return await this.requireScope(e,"teams:write"),this.mutate(n=>{let o=new Date().toISOString(),i=t.id?.trim()||`team-${ke().slice(0,8)}`;if(n.teams.some(a=>a.id===i))throw new h(`Team already exists: ${i}`,409);let s={id:i,name:t.name.trim(),...t.description?.trim()?{description:t.description.trim()}:{},createdAt:o,updatedAt:o};return n.teams.push(s),this.mutation(n,`team:create:${i}`,e),structuredClone(s)})}async listAgents(e){return await this.requireScope(e,"hub:read"),structuredClone((await this.ensureState()).agents)}async createAgent(e,t){return await this.requireScope(e,"agents:write"),this.mutate(n=>{let o=new Date().toISOString(),i=t.id?.trim()||`agent-${ke().slice(0,8)}`;if(n.agents.some(c=>c.id===i))throw new h(`Agent already exists: ${i}`,409);let s=ve(t.teamIds??[]);for(let c of s)if(!n.teams.some(l=>l.id===c))throw new h(`Team not found: ${c}`,404);let a={id:i,name:t.name.trim(),...t.kind?.trim()?{kind:t.kind.trim()}:{},teamIds:s,...t.metadata?{metadata:structuredClone(t.metadata)}:{},createdAt:o,updatedAt:o};return n.agents.push(a),n.loadouts.push({agentId:i,tools:[...Xe],memoryMode:"local",skillMemory:!0,contextOffload:!0,maxContextChars:6400,updatedAt:o}),this.mutation(n,`agent:create:${i}`,e),structuredClone(a)})}async listAcl(e){return await this.requireScope(e,"acl:manage"),structuredClone((await this.ensureState()).acl)}async grantAcl(e,t){return await this.requireScope(e,"acl:manage"),this.mutate(n=>{let o=new Date().toISOString(),i=ve(t.scopes??Nn(t.role));for(let c of i)if(!b.includes(c))throw new h(`Unknown Memory Hub scope: ${c}`,400);let s=n.acl.find(c=>c.principal===t.principal);if(s)return s.role=t.role,s.scopes=[...i],s.updatedAt=o,this.mutation(n,`acl:update:${t.principal}`,e),structuredClone(s);let a={principal:t.principal,role:t.role,scopes:[...i],createdAt:o,updatedAt:o};return n.acl.push(a),this.mutation(n,`acl:grant:${t.principal}`,e),structuredClone(a)})}async revokeAcl(e,t){await this.requireScope(e,"acl:manage"),await this.mutate(n=>{if(t===n.ownerPrincipal)throw new h("Memory Hub owner ACL cannot be revoked",409);let o=n.acl.length;if(n.acl=n.acl.filter(i=>i.principal!==t),n.acl.length===o)throw new h(`ACL principal not found: ${t}`,404);this.mutation(n,`acl:revoke:${t}`,e)})}async listLoadouts(e){return await this.requireScope(e,"hub:read"),structuredClone((await this.ensureState()).loadouts)}async getLoadout(e,t){await this.requireScope(e,"hub:read");let n=(await this.ensureState()).loadouts.find(o=>o.agentId===t);if(!n)throw new h(`Agent loadout not found: ${t}`,404);return structuredClone(n)}async setLoadout(e,t){return await this.requireScope(e,"loadouts:write"),this.mutate(n=>{if(!n.agents.some(s=>s.id===t.agentId))throw new h(`Agent not found: ${t.agentId}`,404);let o=new Date().toISOString(),i=n.loadouts.find(s=>s.agentId===t.agentId);return i||(i={agentId:t.agentId,tools:[...Xe],memoryMode:"local",skillMemory:!0,contextOffload:!0,maxContextChars:6400,updatedAt:o},n.loadouts.push(i)),t.tools&&(i.tools=ve(t.tools)),t.memoryMode&&(i.memoryMode=t.memoryMode),t.skillMemory!==void 0&&(i.skillMemory=t.skillMemory),t.contextOffload!==void 0&&(i.contextOffload=t.contextOffload),t.maxContextChars!==void 0&&(i.maxContextChars=t.maxContextChars),i.updatedAt=o,this.mutation(n,`loadout:set:${t.agentId}`,e),structuredClone(i)})}async observability(e){return await this.requireScope(e,"observability:read"),structuredClone((await this.ensureState()).observability)}async recordRequest(e){await this.mutate(t=>{let n=e.statusCode<400;t.observability.requests+=1,n||(t.observability.errors+=1);let o={...this.event("request",`${e.method} ${e.path}`,e.principal,n),statusCode:e.statusCode,durationMs:Math.max(0,Math.floor(e.durationMs))};this.pushEvent(t,o)})}async snapshot(){return Fn(await this.ensureState())}};var Ze="wiki/state.v1.json";function Hn(r){let e=new Date().toISOString();return{schema:"toolnet.wiki.v1",version:1,projectId:r.id,pages:[],revisions:[],createdAt:e,updatedAt:e}}function Ln(r,e){let t=JSON.parse(r);if(t.schema!=="toolnet.wiki.v1"||t.version!==1||t.projectId!==e.id||!Array.isArray(t.pages)||!Array.isArray(t.revisions))throw new Error("Invalid ToolNet Wiki state");return t}var K=class{constructor(e,t){this.storage=e;this.project=t}storage;project;async load(){let e=await this.storage.getText(Ze);if(!e){let t=Hn(this.project);return await this.save(t),t}return Ln(e,this.project)}async save(e){await this.storage.put(Ze,JSON.stringify(e,null,2),"application/json")}};import{randomUUID as rt}from"node:crypto";var f=class extends Error{constructor(t,n){super(t);this.statusCode=n}statusCode};function $(r){let e=new Set,t=[];for(let n of r){let o=n.replace(/\s+/gu," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();e.has(i)||(e.add(i),t.push(o))}return t}function N(r){let e=r.normalize("NFKD").replace(/[\u0300-\u036f]/gu,"").toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,120);if(!e)throw new f("Invalid Wiki slug",400);return e}function et(r){let e=[];for(let t of r.matchAll(/\[\[([^\[\]]+)\]\]/gu)){let n=t[1]?.trim();n&&e.push(N(n))}return $(e)}function Dn(r){return r.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_-]+/u).map(e=>e.trim()).filter(e=>e.length>=2)}function tt(r){return{id:`revision-${rt()}`,pageId:r.id,slug:r.slug,revision:r.revision,title:r.title,...r.summary?{summary:r.summary}:{},content:r.content,tags:[...r.tags],links:[...r.links],createdAt:r.updatedAt}}function M(r){return structuredClone(r)}var F=class{constructor(e){this.store=e}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(e){let t,n=this.queue.then(async()=>{let o=await this.ensureState();t=e(o),o.updatedAt=new Date().toISOString(),await this.store.save(o)});return this.queue=n.then(()=>{},()=>{}),await n,t}async summary(){let e=await this.ensureState(),t=new Set(e.pages.flatMap(n=>n.links));return{schema:"toolnet.wiki-summary.v1",projectId:e.projectId,pages:e.pages.length,revisions:e.revisions.length,tags:$(e.pages.flatMap(n=>n.tags)).sort((n,o)=>n.localeCompare(o)),links:e.pages.reduce((n,o)=>n+o.links.length,0),orphanPages:e.pages.filter(n=>n.links.length===0&&!t.has(n.slug)).length,automatedPages:e.pages.filter(n=>n.tags.some(o=>o.startsWith("toolnet-auto-"))).length,updatedAt:e.updatedAt}}async listPages(){let e=await this.ensureState();return M([...e.pages].sort((t,n)=>t.title.localeCompare(n.title)))}async getPage(e){let t=await this.ensureState(),n=N(e),o=t.pages.find(i=>i.slug===n||i.id===e);if(!o)throw new f(`Wiki page not found: ${e}`,404);return M(o)}async createPage(e){return this.mutate(t=>{let n=e.title.trim(),o=e.content.trim();if(!n)throw new f("Wiki title is required",400);let i=N(e.slug??n);if(t.pages.some(c=>c.slug===i))throw new f(`Wiki page already exists: ${i}`,409);let s=new Date().toISOString(),a={id:`wiki-${rt()}`,slug:i,title:n,...e.summary?.trim()?{summary:e.summary.trim()}:{},content:o,tags:$(e.tags??[]),links:et(o),revision:1,createdAt:s,updatedAt:s};return t.pages.push(a),t.revisions.push(tt(a)),M(a)})}async updatePage(e,t){return this.mutate(n=>{let o=N(e),i=n.pages.find(s=>s.slug===o||s.id===e);if(!i)throw new f(`Wiki page not found: ${e}`,404);if(t.title!==void 0){let s=t.title.trim();if(!s)throw new f("Wiki title is required",400);i.title=s}if(t.summary!==void 0){let s=t.summary.trim();s?i.summary=s:delete i.summary}return t.content!==void 0&&(i.content=t.content.trim(),i.links=et(i.content)),t.tags!==void 0&&(i.tags=$(t.tags)),i.revision+=1,i.updatedAt=new Date().toISOString(),n.revisions.push(tt(i)),M(i)})}async history(e){let t=await this.getPage(e),n=await this.ensureState();return M(n.revisions.filter(o=>o.pageId===t.id).sort((o,i)=>i.revision-o.revision))}async backlinks(e){let t=await this.getPage(e),n=await this.ensureState();return M(n.pages.filter(o=>o.links.includes(t.slug)).sort((o,i)=>o.title.localeCompare(i.title)))}async search(e,t=10){let n=await this.ensureState(),o=$(Dn(e));if(o.length===0)return[];let i=Math.max(1,Math.min(20,Math.floor(t))),s=[];for(let a of n.pages){let c=a.title.toLowerCase(),l=a.slug.toLowerCase(),u=a.summary?.toLowerCase()??"",p=a.content.toLowerCase(),g=a.tags.map(v=>v.toLowerCase()),y=0;for(let v of o)l===v&&(y+=12),c===v&&(y+=10),c.includes(v)&&(y+=6),l.includes(v)&&(y+=5),g.some(ue=>ue===v)?y+=5:g.some(ue=>ue.includes(v))&&(y+=3),u.includes(v)&&(y+=2),p.includes(v)&&(y+=1);y>0&&s.push({page:M(a),score:y})}return s.sort((a,c)=>c.score-a.score||c.page.updatedAt.localeCompare(a.page.updatedAt)).slice(0,i)}};import{createHash as Wn,randomUUID as nt}from"node:crypto";var ot="wiki/governance.v1.json",ct="toolnet.knowledge-governance.v1",it=500,H={autoApproveThreshold:.86,criticalApproveThreshold:.94,staleAfterDays:90};function zn(r,e=0,t=1){return Math.max(e,Math.min(t,r))}function we(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/gu," ").trim()}function st(r){return Wn("sha256").update(r.normalize("NFKC").replace(/\s+/gu," ").trim()).digest("hex")}function Gn(r){let e=[r.title,r.summary??"",r.content.slice(0,2e3),...r.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(e)}function Vn(r){let e=r.sourceType==="skill"?.96:r.sourceType==="memory"?.94:.88,t=r.tags.map(n=>n.toLowerCase());return(t.includes("permanent")||t.includes("task"))&&(e+=.03),r.content.length>=200&&(e+=.02),r.content.length<80&&(e-=.05),r.title.length<4&&(e-=.05),zn(e)}function at(r){let e=new Date().toISOString();return{schema:ct,version:1,projectId:r,policy:{...H},reviews:[],audit:[],createdAt:e,updatedAt:e}}function ut(r){let e=r.autoApproveThreshold??H.autoApproveThreshold,t=r.criticalApproveThreshold??H.criticalApproveThreshold,n=r.staleAfterDays??H.staleAfterDays;if(!Number.isFinite(e)||e<.5||e>1)throw new f("Invalid autoApproveThreshold",400);if(!Number.isFinite(t)||t<.5||t>1)throw new f("Invalid criticalApproveThreshold",400);if(!Number.isInteger(n)||n<1||n>3650)throw new f("Invalid staleAfterDays",400);return{autoApproveThreshold:e,criticalApproveThreshold:t,staleAfterDays:n}}var L=class{constructor(e,t){this.storage=e;this.project=t}storage;project;async load(){let e=await this.storage.getText(ot);if(!e){let t=at(this.project.id);return await this.save(t),t}try{let t=JSON.parse(e);if(t.schema!==ct||t.version!==1||t.projectId!==this.project.id||!Array.isArray(t.reviews)||!Array.isArray(t.audit))throw new Error("invalid");return{...t,policy:ut(t.policy??H)}}catch{let t=at(this.project.id);return await this.save(t),t}}async save(e){await this.storage.put(ot,JSON.stringify(e,null,2),"application/json")}},D=class{constructor(e){this.store=e}store;state;queue=Promise.resolve();async initialize(){await this.ensureState()}async ensureState(){return this.state||(this.state=await this.store.load()),this.state}audit(e,t,n,o={}){e.audit.push({id:nt(),action:t,principal:n,...o.reviewId?{reviewId:o.reviewId}:{},...o.sourceKey?{sourceKey:o.sourceKey}:{},timestamp:new Date().toISOString(),...o.metadata?{metadata:o.metadata}:{}}),e.audit.length>it&&(e.audit=e.audit.slice(-it))}async mutate(e){let t,n=this.queue.then(async()=>{let o=await this.ensureState();t=await e(o),o.updatedAt=new Date().toISOString(),await this.store.save(o)});return this.queue=n.then(()=>{},()=>{}),await n,t}async policy(){return{...(await this.ensureState()).policy}}async setPolicy(e,t){return this.mutate(n=>(n.policy=ut({...n.policy,...e}),this.audit(n,"policy:update",t,{metadata:{...n.policy}}),{...n.policy}))}async summary(){let e=await this.ensureState(),t=n=>e.reviews.filter(o=>o.status===n).length;return{schema:"toolnet.knowledge-governance-summary.v1",projectId:e.projectId,pending:t("pending"),approved:t("approved"),rejected:t("rejected"),superseded:t("superseded"),criticalPending:e.reviews.filter(n=>n.status==="pending"&&n.risk==="critical").length,conflictPending:e.reviews.filter(n=>n.status==="pending"&&n.risk==="conflict").length,auditEvents:e.audit.length,policy:{...e.policy},updatedAt:e.updatedAt}}async listReviews(e){let t=await this.ensureState();return structuredClone(t.reviews.filter(n=>!e||n.status===e).sort((n,o)=>o.updatedAt.localeCompare(n.updatedAt)))}async auditLog(e=100){let t=await this.ensureState(),n=Math.max(1,Math.min(500,Math.floor(e)));return structuredClone(t.audit.slice(-n).reverse())}async assess(e,t){let n=await this.ensureState(),o=Vn(e),i=we(e.title),s=t.filter(u=>u.slug!==e.slug&&we(u.title)===i&&st(u.content)!==st(e.content)).map(u=>u.slug),a=Gn(e),c=[];o<n.policy.autoApproveThreshold&&c.push(`confidence:${o.toFixed(2)}`),a&&o<n.policy.criticalApproveThreshold&&c.push("critical-knowledge"),s.length>0&&c.push("conflicting-knowledge");let l=s.length>0?"conflict":a?"critical":"normal";return{confidence:o,risk:l,requiresReview:s.length>0||o<n.policy.autoApproveThreshold||a&&o<n.policy.criticalApproveThreshold,reasons:c,conflicts:s}}async gate(e,t){let n=await this.assess(e,t);return this.mutate(o=>{let i=o.reviews.find(c=>c.sourceKey===e.sourceKey&&c.digest===e.digest);if(i?.status==="approved")return{allowed:!0,mode:"review-approved",assessment:n,review:structuredClone(i)};if(i?.status==="rejected")return{allowed:!1,mode:"rejected",assessment:n,review:structuredClone(i)};if(!n.requiresReview)return this.audit(o,"knowledge:auto-approved","system",{sourceKey:e.sourceKey,metadata:{confidence:n.confidence,risk:n.risk}}),{allowed:!0,mode:"auto-approved",assessment:n};if(i?.status==="pending")return{allowed:!1,mode:"pending-review",assessment:n,review:structuredClone(i)};let s=new Date().toISOString(),a={id:nt(),sourceKey:e.sourceKey,sourceType:e.sourceType,slug:e.slug,marker:e.marker,digest:e.digest,title:e.title,...e.summary?{summary:e.summary}:{},content:e.content,tags:[...new Set([...e.tags,e.marker])],confidence:n.confidence,risk:n.risk,reasons:[...n.reasons],conflicts:[...n.conflicts],status:"pending",createdAt:s,updatedAt:s};return o.reviews.push(a),this.audit(o,"knowledge:review-requested","system",{reviewId:a.id,sourceKey:a.sourceKey,metadata:{confidence:a.confidence,risk:a.risk}}),{allowed:!1,mode:"pending-review",assessment:n,review:structuredClone(a)}})}async markApplied(e,t){await this.mutate(n=>{let o=n.reviews.find(i=>i.sourceKey===e&&i.digest===t&&i.status==="approved");o&&(o.appliedAt=new Date().toISOString(),o.updatedAt=o.appliedAt,this.audit(n,"knowledge:applied",o.reviewedBy??"system",{reviewId:o.id,sourceKey:e}))})}async decide(e,t,n){return this.mutate(async o=>{let i=o.reviews.find(l=>l.id===e);if(!i)throw new f(`Governance review not found: ${e}`,404);if(i.status!=="pending")throw new f("Governance review is already resolved",409);let s=new Date().toISOString();if(i.reviewedAt=s,i.reviewedBy=t.principal,i.updatedAt=s,t.note?.trim()&&(i.reviewNote=t.note.trim()),t.action==="reject")return i.status="rejected",this.audit(o,"knowledge:rejected",t.principal,{reviewId:e,sourceKey:i.sourceKey}),structuredClone(i);if(t.action==="supersede")return i.status="superseded",t.targetReviewId&&(i.supersededBy=t.targetReviewId),this.audit(o,"knowledge:superseded",t.principal,{reviewId:e,sourceKey:i.sourceKey,metadata:{targetReviewId:t.targetReviewId}}),structuredClone(i);if(t.action==="merge"){if(!t.targetReviewId)throw new f("targetReviewId is required for merge",400);let l=o.reviews.find(u=>u.id===t.targetReviewId);if(!l)throw new f("Merge target review not found",404);return i.status="superseded",i.mergedInto=l.id,this.audit(o,"knowledge:merged",t.principal,{reviewId:e,sourceKey:i.sourceKey,metadata:{targetReviewId:l.id}}),structuredClone(i)}i.status="approved";let c=(await n.listPages()).find(l=>l.slug===i.slug);if(c&&!c.tags.includes(i.marker))throw new f(`Wiki page '${i.slug}' is manually managed`,409);return c?await n.updatePage(i.slug,{title:i.title,summary:i.summary??"",content:i.content,tags:i.tags}):await n.createPage({slug:i.slug,title:i.title,...i.summary?{summary:i.summary}:{},content:i.content,tags:i.tags}),i.appliedAt=s,this.audit(o,"knowledge:approved",t.principal,{reviewId:e,sourceKey:i.sourceKey}),structuredClone(i)})}async quality(e){let t=await this.ensureState(),n=await e.listPages(),o=Date.now(),i=t.policy.staleAfterDays*864e5,s=n.map(u=>{let p=o-Date.parse(u.updatedAt);return{slug:u.slug,title:u.title,updatedAt:u.updatedAt,ageDays:Math.max(0,Math.floor(p/864e5)),stale:Number.isFinite(p)&&p>i}}).filter(u=>u.stale).map(({stale:u,...p})=>p),a=new Map;for(let u of n){let p=we(u.title),g=a.get(p)??[];g.push(u),a.set(p,g)}let c=[...a.entries()].filter(([,u])=>u.length>1).map(([u,p])=>({title:u,pages:p.map(g=>g.slug)})),l=t.reviews.filter(u=>u.status==="pending");return{schema:"toolnet.knowledge-quality.v1",totalPages:n.length,automatedPages:n.filter(u=>u.tags.some(p=>p.startsWith("toolnet-auto-"))).length,manualPages:n.filter(u=>!u.tags.some(p=>p.startsWith("toolnet-auto-"))).length,stalePages:s,duplicateTitles:c,pendingReviews:l.length,lowConfidenceReviews:l.filter(u=>u.confidence<t.policy.autoApproveThreshold).length,conflicts:l.filter(u=>u.risk==="conflict").length,generatedAt:new Date().toISOString()}}};import{timingSafeEqual as fi}from"node:crypto";import{createServer as gi}from"node:http";function lt(r){return{ok:!0,service:"toolnet-memory",schema:"toolnet.api-health.v1",project:{id:r.id,name:r.name,remote:r.remote??r.name}}}function dt(r){return{schema:"toolnet.api-project.v1",project:{id:r.id,name:r.name,remote:r.remote??r.name,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,createdAt:r.createdAt,updatedAt:r.updatedAt}}}import{z as xe}from"zod";import{existsSync as ao,readFileSync as co}from"node:fs";import{join as uo}from"node:path";import{existsSync as qn,mkdirSync as rc,readFileSync as Bn,renameSync as nc,writeFileSync as oc}from"node:fs";import{dirname as sc,join as Un}from"node:path";function Jn(r){return Un(r.rootPath,".toolnet","work","current.json")}function be(r){let e=Jn(r);if(!qn(e))return null;try{let t=JSON.parse(Bn(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as Qn,mkdirSync as uc,readFileSync as Yn,renameSync as lc,writeFileSync as dc}from"node:fs";import{dirname as pc,join as Xn}from"node:path";function Zn(r){return Xn(r.rootPath,".toolnet","context","session-origin.json")}function Se(r){let e=Zn(r);if(!Qn(e))return null;try{let t=JSON.parse(Yn(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function eo(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function ae(r){let e=eo(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),n=/(?:đ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&&n?"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 ro,mkdirSync as Uc,readFileSync as no}from"node:fs";import{join as mt}from"node:path";var $c=new C;function oo(r){return mt(r.rootPath,".toolnet","memory","checkpoints")}function io(r){return mt(oo(r),"latest.json")}function so(r){let e=io(r);if(!ro(e))return null;try{let t=JSON.parse(no(e,"utf8"));return t.schema!=="toolnet.memory.checkpoint.v1"||t.project.id!==r.id?null:t}catch{return null}}function pt(r){return so(r)}var lo={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}},mo={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function po(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function d(r,e){let t=e.value.replace(/\s+/g," ").trim();t&&r.push({...e,value:t,score:0})}function fo(r){let e=uo(r.rootPath,".toolnet","work","handoff-latest.json");if(!ao(e))return null;try{let n=JSON.parse(co(e,"utf8")).continuity;return n?.schema!=="toolnet.handoff.v2"||n.project.id!==r.id?null:n}catch{return null}}function go(r){let e=pt(r);if(!e)return[];let t=[];e.request&&d(t,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&d(t,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&d(t,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&d(t,{kind:"task",value:e.current.task.title,source:"checkpoint"});let n=e.files.active.at(-1);n&&d(t,{kind:"file",value:n,source:"checkpoint"});for(let o of e.nextActions)d(t,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)d(t,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)d(t,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)d(t,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)d(t,{kind:o.kind,value:o.content,source:"checkpoint"});return t}function yo(r){let e=fo(r);if(!e)return[];let t=[];d(t,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&d(t,{kind:"request",value:e.request,source:"handoff"}),e.activity&&d(t,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&d(t,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&d(t,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&d(t,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&d(t,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&d(t,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let n of e.blockers)d(t,{kind:"blocker",value:n,source:"handoff"});for(let n of e.decisions)d(t,{kind:"decision",value:n,source:"handoff"});for(let n of e.completed.tasks)d(t,{kind:"completed",value:n,source:"handoff"});for(let n of e.remaining.todos)d(t,{kind:"todo",value:n,source:"handoff"});return d(t,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),d(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),t}function ho(r){let e=Se(r);if(!e)return[];let t=[];return d(t,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&d(t,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&d(t,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&d(t,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&d(t,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&d(t,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&d(t,{kind:"decision",value:e.latestDecision,source:"session-origin"}),t}function ko(r){let e=be(r);if(!e)return[];let t=[];e.currentRequest&&d(t,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&d(t,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&d(t,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&d(t,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&d(t,{kind:"task",value:e.currentTask.title,source:"work-state"});let n=e.activeFiles?.at(-1)??e.filesTouched.at(-1);n&&d(t,{kind:"file",value:n,source:"work-state"});for(let o of e.nextActions.slice(0,5))d(t,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))d(t,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))d(t,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(i=>i.status==="completed").slice(-8))d(t,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(i=>i.status!=="completed"&&i.status!=="cancelled").slice(0,8))d(t,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))d(t,{kind:"test",value:o,source:"work-state"});return d(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),t}function vo(r,e){let t=lo[r];return e.map((n,o)=>({...n,score:(t[n.kind]??10)+mo[n.source]+Math.max(0,5-o*.01)}))}function wo(r){let e=new Map;for(let t of r){let n=`${t.kind}:${po(t.value)}`,o=e.get(n);(!o||t.score>o.score)&&e.set(n,t)}return[...e.values()]}function ce(r,e,t={}){let n=ae(e),o=[...go(r),...yo(r),...ho(r),...ko(r)],i=wo(vo(n,o)).sort((u,p)=>p.score-u.score),s=Math.max(1,t.maxFacts??12),a=Math.max(300,t.maxChars??3200),c=[],l=0;for(let u of i){if(c.length>=s)break;let p=u.kind.length+u.value.length+u.source.length+16;c.length>0&&l+p>a||(c.push(u),l+=p)}return{intent:n,facts:c,context:{project:{id:r.id,name:r.name},intent:n,selectedFacts:c.map(u=>({kind:u.kind,value:u.value,source:u.source}))},stats:{candidates:o.length,selected:c.length,chars:l}}}var ft={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"},gt=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],bo={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:gt};function So(r){let e=r.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 xo(r){let e=r.filter(n=>n.source==="handoff");if(e.length===0)return r;let t=r.filter(n=>n.source==="checkpoint"&&["rule","architecture","fix"].includes(n.kind));return[...e,...t]}function Mo(r){let e=new Set,t=[];for(let n of r){let o=`${n.kind}:${n.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),t.push(n))}return t}function yt(r){switch(r){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function Ao(r,e){let t=[];for(let n of e){let o=r.filter(i=>i.kind===n).slice(0,yt(n));for(let i of o)t.push(`${ft[n]}: ${i.value}`)}return t.join(`
|
|
6
|
+
`)}function Co(r,e){let t=bo[e]??gt,n=[];for(let o of t){let i=r.filter(s=>s.kind===o).slice(0,yt(o));for(let s of i)n.push(`${ft[o]}: ${s.value}`)}return n.join(`
|
|
7
|
+
`)}function ht(r,e){let t=ce(r,e,{maxFacts:32,maxChars:6400}),n=Mo(xo(t.facts)),o=So(e)?Ao(n,["todo","task","next_action","file"]):Co(n,String(t.intent));return o?{intent:String(t.intent),answer:o,source:n[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"}}import{existsSync as Po,mkdirSync as Io,readFileSync as To,renameSync as Ro,rmSync as jo,writeFileSync as Eo}from"node:fs";import{join as kt}from"node:path";var Oo=720*60*1e3;function vt(r){return kt(r.rootPath,".toolnet","context","memory-agent-conversation.json")}function W(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function _o(r){let e=W(r);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(t=>t.test(e))}function Ko(r){if(_o(r))return!1;let e=W(r),t=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(n=>n.test(e))?!0:t.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function $o(r,e,t){let n=vt(r);if(!Po(n))return null;try{let o=JSON.parse(To(n,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==r.id||!Array.isArray(o.focus))return null;let i=Date.parse(o.updatedAt);return!Number.isFinite(i)||e-i>t?null:o}catch{return null}}function No(r,e=8){let t=new Set,n=[];for(let o of r){let i=o.value.replace(/\s+/gu," ").trim();if(!i)continue;let s=[o.kind,W(i)].join(":");if(!t.has(s)&&(t.add(s),n.push({...o,value:i}),n.length>=e))break}return n}function Fo(r,e){let t=vt(r),n=kt(r.rootPath,".toolnet","context");Io(n,{recursive:!0,mode:448});let o=`${t}.${process.pid}.tmp`;try{Eo(o,JSON.stringify(e,null,2)+`
|
|
8
|
+
`,{encoding:"utf8",mode:384}),Ro(o,t)}finally{jo(o,{force:!0})}}function Ho(r){return r.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
|
|
9
|
+
`)}function Lo(r,e){return r.priorFocus.find(t=>t.kind===e)?.value}function wt(r){if(!r.usedPriorFocus||r.currentIntent!=="summary"||r.priorFocus.length===0)return null;let e=W(r.originalQuestion),t=/^(?:tại sao|vì sao|sao vậy|why|why so|why that)\b/u.test(e),n=/^(?:rồi sao|sau đó|tiếp thì sao|thế tiếp theo|then what|what next)\b/u.test(e),o=t?["decision","blocker","next_action","task","file"]:n?["next_action","todo","task","blocker","file","decision"]:["task","next_action","file","decision","blocker"],i={task:"Task li\xEAn quan",next_action:"Vi\u1EC7c ti\u1EBFp theo",file:"File li\xEAn quan",decision:"Quy\u1EBFt \u0111\u1ECBnh li\xEAn quan",blocker:"Blocker",todo:"TODO"},s=[];for(let a of o){let c=Lo(r,a);if(c&&(s.push(`${i[a]??a}: ${c}.`),t&&s.length>=2||!t&&s.length>=3))break}return s.length===0?null:{answer:s.join(" "),intent:"summary",source:"conversation-focus"}}function Do(r){let e=W(r);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)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function bt(r,e,t={}){let n=t.now??Date.now(),o=t.maxAgeMs??Oo,i=$o(r,n,o),s=!!(i&&i.focus.length>0&&Ko(e)&&!Do(e)),a=s&&i?[e.trim(),"","Previous ToolNet Memory conversation focus:",Ho(i),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
|
|
10
|
+
`):e.trim(),c=ae(e),u=ce(r,a,{maxFacts:8,maxChars:1800}).facts.map(g=>({kind:g.kind,value:g.value,source:g.source})),p=No(s&&i?[...u,...i.focus]:u);return Fo(r,{schema:"toolnet.memory-conversation.v1",version:1,projectId:r.id,updatedAt:new Date(n).toISOString(),lastIntent:c,focus:p}),{question:a,originalQuestion:e,usedPriorFocus:s,previousIntent:i?.lastIntent,currentIntent:c,priorFocus:i?.focus??[],focusCount:p.length}}import{existsSync as Wo,readFileSync as zo}from"node:fs";import{join as Go}from"node:path";function S(r){return!!r?.trim()}function St(r){let e=[],t=[],n=100;S(r.goal)||S(r.request)||(e.push("goal_or_request"),n-=20),S(r.activity)||S(r.current.task?.title)||S(r.current.phase?.title)||(e.push("current_work"),n-=25),S(r.nextAction)||S(r.remaining.todos[0])||(e.push("next_action"),n-=25),r.tests.status!=="unknown"||r.tests.recent.length>0||(r.tests.checks?.length??0)>0||(r.evidence?.commands.length??0)>0||(r.evidence?.references.length??0)>0||(e.push("evidence"),n-=20),S(r.files.current)||r.files.recent.length>0||(r.files.active?.length??0)>0||(r.files.modified?.length??0)>0||(r.files.created?.length??0)>0||(e.push("files"),n-=10),r.tests.status==="failing"&&t.push("tests_failing"),r.blockers.length>0&&t.push("active_blockers"),n=Math.max(0,Math.min(100,n));let l=e.includes("current_work")||e.includes("next_action"),u;return n>=80&&!l?u="high":n>=50?u="medium":u="low",{confidence:u,score:n,missingContext:e,warnings:t}}var xt={compact:{completed:3,evidence:3,files:5,blockers:2,maxChars:1800},normal:{completed:10,evidence:10,files:15,blockers:5,maxChars:4200},benchmark:{completed:30,evidence:30,files:40,blockers:10,maxChars:1e4}};function P(r){let e=new Set,t=[];for(let n of r){let o=n?.replace(/\s+/gu," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();e.has(i)||(e.add(i),t.push(o))}return t}function I(r){return r.length>0?r.map(e=>`- ${e}`).join(`
|
|
11
|
+
`):"- none"}function Vo(r,e){return r.length<=e?r:[r.slice(0,e).trimEnd(),"","[Structured handoff truncated]"].join(`
|
|
12
|
+
`)}function Mt(r,e){if(e)return e;let t=r.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/\bbenchmark\b/u.test(t)||/\bdeep handoff\b/u.test(t)||/\bfull handoff\b/u.test(t)||/\btakeover\b/u.test(t)||/\btake over\b/u.test(t)||/tiếp quản/u.test(t)||/bằng chứng đầy đủ/u.test(t)||/evidence.*(?:file|test|command)/u.test(t)?"benchmark":/\bcompact\b/u.test(t)||/\bbrief\b/u.test(t)||/ngắn gọn/u.test(t)||/tóm tắt ngắn/u.test(t)?"compact":"normal"}function qo(r,e="normal"){let t=xt[e],n=P([`Source agent: ${r.source.agent}`,`Captured: ${r.capturedAt}`,r.goal?`Goal: ${r.goal}`:void 0,r.request?`Request: ${r.request}`:void 0,r.activity?`Activity: ${r.activity}`:void 0,r.current.phase?`Phase: ${r.current.phase.title} [${r.current.phase.status}]`:void 0,r.current.task?`Task: ${r.current.task.title} [${r.current.task.status}]`:void 0,r.current.file?`Current file: ${r.current.file}`:void 0,`Progress: ${JSON.stringify(r.progress)}`]),o=P([...r.completed.phases.map(l=>`Phase: ${l}`),...r.completed.tasks.map(l=>`Task: ${l}`)]).slice(0,t.completed),i=P([`Tests status: ${r.tests.status}`,...r.tests.recent.map(l=>`Test: ${l}`),...(r.tests.checks??[]).map(l=>`Check [${l.status}] ${l.kind}: ${l.command}`),...(r.evidence?.commands??[]).map(l=>`Command: ${l}`),...(r.evidence?.references??[]).map(l=>`Reference: ${l}`),...r.decisions.map(l=>`Decision: ${l}`),...r.attention.map(l=>`Attention: ${l}`)]).slice(0,t.evidence),s=P([r.files.current,...(r.files.active??[]).map(l=>`Active: ${l}`),...(r.files.modified??[]).map(l=>`Modified: ${l}`),...(r.files.created??[]).map(l=>`Created: ${l}`),...(r.files.deleted??[]).map(l=>`Deleted: ${l}`),...r.files.recent.map(l=>`Recent: ${l}`)]).slice(0,t.files),a=P(r.blockers).slice(0,t.blockers),c=P([r.nextAction,r.nextAction?void 0:r.remaining.todos[0]]).slice(0,1);return{currentState:n,completed:o,evidence:i,filesTouched:s,blockers:a,nextAction:c}}function Bo(r,e,t){return[`HANDOFF_DETAIL: ${e}`,`CONTINUITY_CONFIDENCE: ${t.confidence}`,`QUALITY_SCORE: ${t.score}`,`MISSING_CONTEXT: ${t.missingContext.length>0?t.missingContext.join(", "):"none"}`,`QUALITY_WARNINGS: ${t.warnings.length>0?t.warnings.join(", "):"none"}`,"","CURRENT_STATE",I(r.currentState),"","COMPLETED",I(r.completed),"","EVIDENCE",I(r.evidence),"","FILES_TOUCHED",I(r.filesTouched),"","BLOCKERS",I(r.blockers),"","NEXT_ACTION",I(r.nextAction)].join(`
|
|
13
|
+
`)}function At(r,e="normal"){let t=Go(r.rootPath,".toolnet","work","handoff-latest.json");if(!Wo(t))return null;try{let o=JSON.parse(zo(t,"utf8")).continuity;if(!o||o.schema!=="toolnet.handoff.v2"||o.version!==2)return null;let i=qo(o,e),s=St(o),a=Vo(Bo(i,e,s),xt[e].maxChars);return{detail:e,data:i,quality:s,text:a}}catch{return null}}function Uo(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}var Jo=[/\bhandoff\b/u,/\bcontinuity\b/u,/\bcontinue\b/u,/\bresume\b/u,/\btakeover\b/u,/\btake over\b/u,/tiếp tục/u,/tiếp quản/u,/bàn giao/u,/dừng ở đâu/u,/đang làm gì/u],Qo=[/\bcurrent state\b/u,/\bcurrent task\b/u,/\bevidence\b/u,/\breport locations?\b/u,/\bfiles?\b/u,/\burls?\b/u,/\bassets?\b/u,/\btests?\b/u,/\bcommands?\b/u,/\bblockers?\b/u,/\bnext actions?\b/u,/trạng thái hiện tại/u,/task hiện tại/u,/bằng chứng/u,/vị trí báo cáo/u,/file/u,/url/u,/blocker/u,/việc tiếp theo/u,/bước tiếp theo/u],Yo=[/\bsummarize\b/u,/\bsummary\b/u,/\bfull state\b/u,/\bfull context\b/u,/tóm tắt/u,/đầy đủ/u,/toàn bộ trạng thái/u];function Xo(r){let e=0;for(let t of Qo)t.test(r)&&(e+=1);return e}function Ct(r,e){let t=Uo(r);if(/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(t)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(t)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(t))return!1;if(e==="summary"||e==="status")return!0;if(!t)return!1;let o=Jo.some(a=>a.test(t)),i=Yo.some(a=>a.test(t)),s=Xo(t);return!!(o&&s>=1||i&&s>=2||s>=4)}var Mu={question:xe.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:xe.enum(["local"]).optional().describe("Returns deterministic local memory only. No external AI is used."),detail:xe.enum(["compact","normal","benchmark"]).optional().describe("Handoff detail level. compact=minimal, normal=standard, benchmark=deep evidence/files/tests for agent takeover.")};function Pt(r,e,t,n,o){if(!Ct(e,t))return{answer:n};let i=Mt(e,o),s=At(r.project,i);return s?{answer:s.text,handoff:s.data,detail:s.detail,confidence:s.quality.confidence,missingContext:s.quality.missingContext,quality:s.quality}:{answer:n}}async function It(r,e){let t=bt(r.project,e.question),n=wt(t);if(n)return{...Pt(r,t.originalQuestion,String(n.intent),n.answer,e.detail),mode:"local",usedAi:!1,source:n.source,intent:n.intent};let o=ht(r.project,t.originalQuestion),i=Pt(r,t.originalQuestion,String(o.intent),o.answer,e.detail);return"handoff"in i?{...i,mode:"local",usedAi:!1,source:o.source,intent:o.intent,routing:"deterministic-handoff"}:{...i,mode:"local",usedAi:!1,source:o.source,intent:o.intent}}import{z as Kt}from"zod";import{chmodSync as Pu,existsSync as Tt,mkdirSync as Iu,readFileSync as Rt,renameSync as Tu,writeFileSync as Ru}from"node:fs";import{dirname as Eu,join as z}from"node:path";var jt="toolnet.context-offload.v1",Zo="toolnet.context-offload-asset.v1";function Et(r){return z(r,".toolnet","offload")}function Ot(r){return z(Et(r),"assets")}function ei(r){return z(Et(r),"graph.json")}function Me(){return{schema:jt,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function ti(r){let e=ei(r);if(!Tt(e))return Me();try{let t=JSON.parse(Rt(e,"utf8"));return t.schema!==jt||t.version!==1||!Array.isArray(t.nodes)?Me():t}catch{return Me()}}function ri(r,e){let t=e.trim().toLowerCase();if(!/^[a-f0-9]{8,64}$/u.test(t))throw new Error("Invalid context offload asset reference.");if(t.length===64&&Tt(z(Ot(r),`${t}.json`)))return t;let n=ti(r).nodes.map(o=>o.id).filter(o=>o.startsWith(t));if(n.length===0)throw new Error(`Context offload asset not found: ${e}`);if(n.length>1)throw new Error(`Ambiguous context offload asset reference: ${e}`);return n[0]}function _t(r,e,t=6e3){let n=ri(r,e),o=Rt(z(Ot(r),`${n}.json`),"utf8"),i=JSON.parse(o);if(i.schema!==Zo||i.version!==1||i.assetId!==n)throw new Error(`Invalid context offload asset: ${e}`);let s=Math.max(200,Math.min(2e4,Math.floor(t)));return{assetId:n,kind:i.event.type,bytes:Buffer.byteLength(o,"utf8"),truncated:o.length>s,content:o.length>s?`${o.slice(0,s)}
|
|
14
|
+
[truncated]`:o}}var $u={assetId:Kt.string().regex(/^[a-f0-9]{8,64}$/iu).describe("Asset reference from the ToolNet Context Offload Graph."),maxChars:Kt.number().int().min(200).max(2e4).optional().describe("Maximum asset characters to return. Defaults to 6000.")};async function $t(r,e){return _t(r.project.rootPath,e.assetId,e.maxChars??6e3)}async function Nt(r,e){return{schema:"toolnet.api-memory-ask.v1",result:await It({project:r},e)}}async function Ft(r,e){return{schema:"toolnet.api-context-offload.v1",result:await $t({project:r},e)}}import{z as Ht}from"zod";var Wu={query:Ht.string(),limit:Ht.number().int().min(1).max(20).optional()};async function Lt(r,e){return r.retrieval.search(r.project.id,e.query,{topK:e.limit??8}).map(n=>({id:n.memory.id,type:n.memory.type,content:n.memory.content,importance:n.memory.importance,score:n.score,tags:n.memory.tags}))}import{z as zt}from"zod";import{chmodSync as Vu,existsSync as ni,mkdirSync as qu,readFileSync as oi,readdirSync as ii,renameSync as Bu,statSync as si,writeFileSync as Uu}from"node:fs";import{join as Dt}from"node:path";var ai="toolnet.skill-memory.v1";function ci(r,e=Number.MAX_SAFE_INTEGER){let t=new Set,n=[];for(let o of r){let i=o.replace(/\s+/gu," ").trim();if(!i)continue;let s=i.normalize("NFKC").toLowerCase();if(!t.has(s)&&(t.add(s),n.push(i),n.length>=e))break}return n}function ui(r){return Dt(r.rootPath,".toolnet","memory","skills")}function li(r,e){if(!r||typeof r!="object")return!1;let t=r;return t.schema===ai&&t.version===1&&t.projectId===e&&typeof t.id=="string"&&typeof t.task=="string"&&Array.isArray(t.steps)&&Array.isArray(t.verification)&&Array.isArray(t.files)}function di(r){let e=ui(r);if(!ni(e))return[];if(!si(e).isDirectory())return[];let t=[];for(let n of ii(e)){if(!n.endsWith(".json"))continue;let o=Dt(e,n);try{let i=JSON.parse(oi(o,"utf8"));li(i,r.id)&&t.push(i)}catch{}}return t.sort((n,o)=>{let i=o.createdAt.localeCompare(n.createdAt);return i!==0?i:n.id.localeCompare(o.id)})}function mi(r){return ci(r.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_./-]+/gu).filter(e=>e.length>=2),32)}function pi(r,e){let t=e.normalize("NFKC").toLowerCase().trim();if(!t)return 0;if(r.id.toLowerCase()===t||r.fingerprint.toLowerCase()===t)return 1e3;let n=[r.title,r.task,r.summary,...r.steps,...r.verification,...r.files].join(`
|
|
15
|
+
`).normalize("NFKC").toLowerCase(),o=0;r.task.normalize("NFKC").toLowerCase().includes(t)&&(o+=40),r.title.normalize("NFKC").toLowerCase().includes(t)&&(o+=30);for(let i of mi(t))n.includes(i)&&(o+=5),r.task.normalize("NFKC").toLowerCase().includes(i)&&(o+=4),r.files.some(s=>s.toLowerCase().includes(i))&&(o+=3);return o}function Wt(r,e,t=5){let n=Math.max(1,Math.min(10,Math.floor(t)));return di(r).map(o=>({...o,score:pi(o,e)})).filter(o=>o.score>0).sort((o,i)=>i.score!==o.score?i.score-o.score:i.createdAt.localeCompare(o.createdAt)).slice(0,n)}var Zu={query:zt.string().min(2).max(500).describe("Task, problem, file, command or workflow to match against successful reusable Skill Memory SOPs."),limit:zt.number().int().min(1).max(10).optional().describe("Maximum matching reusable SOPs to return. Default 5.")};async function Gt(r,e){let t=Wt(r.project,e.query,e.limit??5);return{schema:"toolnet.skill-memory-search.v1",query:e.query,count:t.length,matches:t}}async function Vt(r,e,t){return{schema:"toolnet.api-memory-search.v1",results:await Lt({project:r,retrieval:e},t)}}async function qt(r,e){return{schema:"toolnet.api-skill-search.v1",result:await Gt({project:r},e)}}function G(r){if(!r||typeof r!="object"||Array.isArray(r))throw new Error("Invalid Memory Hub request");return r}function w(r,e,t=1,n=200){if(typeof r!="string"||r.trim().length<t||r.trim().length>n)throw new Error(`Invalid ${e}`);return r.trim()}function Bt(r,e,t=500){if(r!==void 0)return w(r,e,1,t)}function Ae(r,e,t=64){if(r!==void 0){if(!Array.isArray(r)||r.length>t||r.some(n=>typeof n!="string"||!n.trim()))throw new Error(`Invalid ${e}`);return r.map(n=>n.trim())}}async function Ut(r,e){return{schema:"toolnet.api-hub-summary.v1",hub:await r.summary(e)}}async function Jt(r,e){return{schema:"toolnet.api-hub-teams.v1",teams:await r.listTeams(e)}}async function Qt(r,e,t){let n=G(t),o={...n.id!==void 0?{id:w(n.id,"team id",2,100)}:{},name:w(n.name,"team name",2,100),...n.description!==void 0?{description:Bt(n.description,"team description",500)}:{}};return{schema:"toolnet.api-hub-team.v1",team:await r.createTeam(e,o)}}async function Yt(r,e){return{schema:"toolnet.api-hub-agents.v1",agents:await r.listAgents(e)}}async function Xt(r,e,t){let n=G(t),o={...n.id!==void 0?{id:w(n.id,"agent id",2,100)}:{},name:w(n.name,"agent name",2,100),...n.kind!==void 0?{kind:Bt(n.kind,"agent kind",100)}:{},...n.teamIds!==void 0?{teamIds:Ae(n.teamIds,"teamIds",64)}:{},...n.metadata&&typeof n.metadata=="object"&&!Array.isArray(n.metadata)?{metadata:n.metadata}:{}};return{schema:"toolnet.api-hub-agent.v1",agent:await r.createAgent(e,o)}}async function Zt(r,e){return{schema:"toolnet.api-hub-acl.v1",grants:await r.listAcl(e)}}async function er(r,e,t){let n=G(t),o=w(n.role,"role",4,20);if(!["owner","admin","member","viewer"].includes(o))throw new Error("Invalid role");let i=Ae(n.scopes,"scopes",b.length);if(i?.some(a=>!b.includes(a)))throw new Error("Invalid Memory Hub scope");let s={principal:w(n.principal,"principal",1,120),role:o,...i?{scopes:i}:{}};return{schema:"toolnet.api-hub-acl-grant.v1",grant:await r.grantAcl(e,s)}}async function tr(r,e,t){let n=G(t),o=w(n.principal,"principal",1,120);return await r.revokeAcl(e,o),{schema:"toolnet.api-hub-acl-revoke.v1",principal:o,revoked:!0}}async function rr(r,e){return{schema:"toolnet.api-hub-loadouts.v1",loadouts:await r.listLoadouts(e)}}async function nr(r,e,t){let n=G(t),o=n.maxContextChars;if(o!==void 0&&(!Number.isInteger(o)||o<500||o>5e4))throw new Error("Invalid maxContextChars");let i=n.memoryMode;if(i!==void 0&&i!=="local"&&i!=="ai")throw new Error("Invalid memoryMode");if(n.skillMemory!==void 0&&typeof n.skillMemory!="boolean")throw new Error("Invalid skillMemory");if(n.contextOffload!==void 0&&typeof n.contextOffload!="boolean")throw new Error("Invalid contextOffload");let s={agentId:w(n.agentId,"agentId",2,100),...n.tools!==void 0?{tools:Ae(n.tools,"tools",64)}:{},...i?{memoryMode:i}:{},...n.skillMemory!==void 0?{skillMemory:n.skillMemory}:{},...n.contextOffload!==void 0?{contextOffload:n.contextOffload}:{},...o!==void 0?{maxContextChars:o}:{}};return{schema:"toolnet.api-hub-loadout.v1",loadout:await r.setLoadout(e,s)}}async function or(r,e){return{schema:"toolnet.api-hub-observability.v1",observability:await r.observability(e)}}async function x(r,e,t){if(!await r.authorize(e,t))throw new f(`Principal '${e}' lacks '${t}'`,403)}function ir(r){if(!r||typeof r!="object"||Array.isArray(r))throw new f("Invalid Wiki request",400);return r}function Ce(r,e,t){if(typeof r!="string"||!r.trim()||r.length>t)throw new f(`Invalid ${e}`,400);return r.trim()}function sr(r,e,t){if(r!==void 0){if(typeof r!="string"||r.length>t)throw new f(`Invalid ${e}`,400);return r}}function ar(r){if(r!==void 0){if(!Array.isArray(r)||r.length>50||r.some(e=>typeof e!="string"||e.length>100))throw new f("Invalid Wiki tags",400);return r}}async function cr(r,e,t){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-summary.v1",wiki:await r.summary()}}async function ur(r,e,t){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-pages.v1",pages:await r.listPages()}}async function lr(r,e,t,n){await x(e,t,"wiki:write");let o=ir(n),i={...o.slug!==void 0?{slug:Ce(o.slug,"Wiki slug",120)}:{},title:Ce(o.title,"Wiki title",200),...o.summary!==void 0?{summary:sr(o.summary,"Wiki summary",1e3)}:{},content:typeof o.content=="string"?o.content:"",...o.tags!==void 0?{tags:ar(o.tags)}:{}};return{schema:"toolnet.api-wiki-page.v1",page:await r.createPage(i)}}async function dr(r,e,t,n){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-page.v1",page:await r.getPage(n)}}async function mr(r,e,t,n,o){await x(e,t,"wiki:write");let i=ir(o),s={...i.title!==void 0?{title:Ce(i.title,"Wiki title",200)}:{},...i.summary!==void 0?{summary:sr(i.summary,"Wiki summary",1e3)}:{},...i.content!==void 0?{content:typeof i.content=="string"?i.content:(()=>{throw new f("Invalid Wiki content",400)})()}:{},...i.tags!==void 0?{tags:ar(i.tags)}:{}};return{schema:"toolnet.api-wiki-page.v1",page:await r.updatePage(n,s)}}async function pr(r,e,t,n,o){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-search.v1",query:n,results:await r.search(n,o)}}async function fr(r,e,t,n){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-history.v1",revisions:await r.history(n)}}async function gr(r,e,t,n){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-backlinks.v1",pages:await r.backlinks(n)}}async function A(r,e,t){if(!await r.authorize(e,t))throw new f(`Principal '${e}' lacks '${t}'`,403)}function yr(r){if(!r||typeof r!="object"||Array.isArray(r))throw new f("Invalid governance request",400);return r}async function hr(r,e,t){return await A(e,t,"governance:read"),{schema:"toolnet.api-governance-summary.v1",governance:await r.summary()}}async function kr(r,e,t,n){if(await A(e,t,"governance:read"),n&&!new Set(["pending","approved","rejected","superseded"]).has(n))throw new f("Invalid review status",400);return{schema:"toolnet.api-governance-reviews.v1",reviews:await r.listReviews(n)}}async function vr(r,e,t,n,o,i){await A(t,n,"governance:write");let s=yr(i),a=s.action;if(a!=="approve"&&a!=="reject"&&a!=="supersede"&&a!=="merge")throw new f("Invalid governance action",400);if(s.note!==void 0&&typeof s.note!="string")throw new f("Invalid review note",400);if(s.targetReviewId!==void 0&&typeof s.targetReviewId!="string")throw new f("Invalid targetReviewId",400);return{schema:"toolnet.api-governance-review.v1",review:await r.decide(o,{action:a,principal:n,...typeof s.note=="string"?{note:s.note}:{},...typeof s.targetReviewId=="string"?{targetReviewId:s.targetReviewId}:{}},e)}}async function wr(r,e,t,n){return await A(t,n,"governance:read"),{schema:"toolnet.api-knowledge-quality.v1",quality:await r.quality(e)}}async function br(r,e,t){return await A(e,t,"governance:read"),{schema:"toolnet.api-governance-policy.v1",policy:await r.policy()}}async function Sr(r,e,t,n){await A(e,t,"governance:write");let o=yr(n),i={};if(o.autoApproveThreshold!==void 0){if(typeof o.autoApproveThreshold!="number")throw new f("Invalid autoApproveThreshold",400);i.autoApproveThreshold=o.autoApproveThreshold}if(o.criticalApproveThreshold!==void 0){if(typeof o.criticalApproveThreshold!="number")throw new f("Invalid criticalApproveThreshold",400);i.criticalApproveThreshold=o.criticalApproveThreshold}if(o.staleAfterDays!==void 0){if(typeof o.staleAfterDays!="number")throw new f("Invalid staleAfterDays",400);i.staleAfterDays=o.staleAfterDays}return{schema:"toolnet.api-governance-policy.v1",policy:await r.setPolicy(i,t)}}async function xr(r,e,t,n){return await A(e,t,"governance:read"),{schema:"toolnet.api-governance-audit.v1",events:await r.auditLog(n)}}function yi(r){let e=r.headers["x-toolnet-principal"];return(Array.isArray(e)?e[0]:e)?.trim()||"anonymous"}function hi(r,e){if(!e)return!0;let t=r.headers.authorization;if(!t?.startsWith("Bearer "))return!1;let n=Buffer.from(t.slice(7)),o=Buffer.from(e);return n.length===o.length&&fi(n,o)}function m(r,e,t){r.statusCode=e,r.setHeader("content-type","application/json; charset=utf-8"),r.setHeader("cache-control","no-store"),r.end(JSON.stringify(t))}async function k(r){let e=[],t=0;for await(let n of r){let o=Buffer.isBuffer(n)?n:Buffer.from(n);if(t+=o.length,t>16384)throw new Error("Request body too large");e.push(o)}return e.length===0?{}:JSON.parse(Buffer.concat(e).toString("utf8"))}function ki(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.question!="string"||e.question.length<2||e.question.length>4e3||e.mode!==void 0&&e.mode!=="local"?null:{question:e.question,...e.mode?{mode:e.mode}:{}}}function vi(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.query!="string"||e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>20)?null:{query:e.query,...e.limit!==void 0?{limit:e.limit}:{}}}function wi(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.query!="string"||e.query.length<2||e.query.length>500||e.limit!==void 0&&(!Number.isInteger(e.limit)||e.limit<1||e.limit>10)?null:{query:e.query,...e.limit!==void 0?{limit:e.limit}:{}}}function bi(r){if(!r||typeof r!="object"||Array.isArray(r))return null;let e=r;return typeof e.assetId!="string"||!/^[a-f0-9]{8,64}$/iu.test(e.assetId)||e.maxChars!==void 0&&(!Number.isInteger(e.maxChars)||e.maxChars<200||e.maxChars>2e4)?null:{assetId:e.assetId,...e.maxChars!==void 0?{maxChars:e.maxChars}:{}}}function Mr(r){return gi(async(e,t)=>{try{let n=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`),o=yi(e),i=Date.now();if(t.once("finish",()=>{r.hub&&r.hub.recordRequest({method:e.method??"GET",path:n.pathname,principal:o,statusCode:t.statusCode,durationMs:Date.now()-i}).catch(()=>{})}),n.pathname.startsWith("/v1/")&&!hi(e,r.token)){m(t,401,{error:"Unauthorized"});return}if(e.method==="GET"&&n.pathname==="/v1/health"){m(t,200,lt(r.project));return}if(e.method==="GET"&&n.pathname==="/v1/project"){m(t,200,dt(r.project));return}if(e.method==="POST"&&n.pathname==="/v1/memory/ask"){let u=ki(await k(e));if(!u){m(t,400,{error:"Invalid memory ask request"});return}m(t,200,await Nt(r.project,u));return}if(e.method==="POST"&&n.pathname==="/v1/memory/search"){let u=vi(await k(e));if(!u){m(t,400,{error:"Invalid memory search request"});return}m(t,200,await Vt(r.project,r.retrieval,u));return}if(e.method==="POST"&&n.pathname==="/v1/skills/search"){let u=wi(await k(e));if(!u){m(t,400,{error:"Invalid skill search request"});return}m(t,200,await qt(r.project,u));return}if(e.method==="POST"&&n.pathname==="/v1/offload/read"){let u=bi(await k(e));if(!u){m(t,400,{error:"Invalid context offload request"});return}m(t,200,await Ft(r.project,u));return}if(n.pathname.startsWith("/v1/hub")&&!r.hub){m(t,503,{error:"Memory Hub unavailable"});return}if(e.method==="GET"&&n.pathname==="/v1/hub"){m(t,200,await Ut(r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/hub/teams"){m(t,200,await Jt(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/teams"){m(t,201,await Qt(r.hub,o,await k(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/agents"){m(t,200,await Yt(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/agents"){m(t,201,await Xt(r.hub,o,await k(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/acl"){m(t,200,await Zt(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/acl/grant"){m(t,200,await er(r.hub,o,await k(e)));return}if(e.method==="POST"&&n.pathname==="/v1/hub/acl/revoke"){m(t,200,await tr(r.hub,o,await k(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/loadouts"){m(t,200,await rr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/loadouts"){m(t,200,await nr(r.hub,o,await k(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/observability"){m(t,200,await or(r.hub,o));return}if(n.pathname.startsWith("/v1/wiki")&&(!r.wiki||!r.hub)){m(t,503,{error:"Wiki unavailable"});return}if(e.method==="GET"&&n.pathname==="/v1/wiki"){m(t,200,await cr(r.wiki,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/wiki/pages"){m(t,200,await ur(r.wiki,r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/wiki/pages"){m(t,201,await lr(r.wiki,r.hub,o,await k(e)));return}if(e.method==="GET"&&n.pathname==="/v1/wiki/search"){let u=n.searchParams.get("q")??"",p=Number(n.searchParams.get("limit")??10),g=Number.isInteger(p)?Math.max(1,Math.min(20,p)):10;m(t,200,await pr(r.wiki,r.hub,o,u,g));return}let s=/^\/v1\/wiki\/pages\/([^/]+)\/history$/u.exec(n.pathname);if(e.method==="GET"&&s){m(t,200,await fr(r.wiki,r.hub,o,decodeURIComponent(s[1])));return}let a=/^\/v1\/wiki\/pages\/([^/]+)\/backlinks$/u.exec(n.pathname);if(e.method==="GET"&&a){m(t,200,await gr(r.wiki,r.hub,o,decodeURIComponent(a[1])));return}let c=/^\/v1\/wiki\/pages\/([^/]+)$/u.exec(n.pathname);if(e.method==="GET"&&c){m(t,200,await dr(r.wiki,r.hub,o,decodeURIComponent(c[1])));return}if(e.method==="PUT"&&c){m(t,200,await mr(r.wiki,r.hub,o,decodeURIComponent(c[1]),await k(e)));return}if(n.pathname.startsWith("/v1/governance")&&(!r.governance||!r.wiki||!r.hub)){m(t,503,{error:"Knowledge Governance unavailable"});return}if(e.method==="GET"&&n.pathname==="/v1/governance"){m(t,200,await hr(r.governance,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/governance/reviews"){m(t,200,await kr(r.governance,r.hub,o,n.searchParams.get("status")??void 0));return}let l=/^\/v1\/governance\/reviews\/([^/]+)$/u.exec(n.pathname);if(e.method==="POST"&&l){m(t,200,await vr(r.governance,r.wiki,r.hub,o,decodeURIComponent(l[1]),await k(e)));return}if(e.method==="GET"&&n.pathname==="/v1/governance/quality"){m(t,200,await wr(r.governance,r.wiki,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/governance/policy"){m(t,200,await br(r.governance,r.hub,o));return}if(e.method==="PUT"&&n.pathname==="/v1/governance/policy"){m(t,200,await Sr(r.governance,r.hub,o,await k(e)));return}if(e.method==="GET"&&n.pathname==="/v1/governance/audit"){let u=Number(n.searchParams.get("limit")??100),p=Number.isInteger(u)?Math.max(1,Math.min(500,u)):100;m(t,200,await xr(r.governance,r.hub,o,p));return}m(t,404,{error:"Not found"})}catch(n){if(n instanceof h||n instanceof f){m(t,n.statusCode,{error:n.message});return}if(n instanceof Error&&n.message.startsWith("Invalid ")){m(t,400,{error:n.message});return}m(t,500,{error:n instanceof Error?n.message:String(n)})}})}var Ar=process.env.TOOLNET_API_HOST??"127.0.0.1",Cr=Number(process.env.TOOLNET_API_PORT??9750);async function Si(){let r=le(),e=new q().detect(),t=qe({provider:r.storage.provider,r2:r.storage.r2,s3:r.storage.s3,huggingface:r.storage.huggingface,localRoot:r.storage.localRoot}),n=Ue(t,{attempts:Number(process.env.TOOLNET_STORAGE_RETRIES??3)}),o=new oe(n,e.id,e.name,e.remote??e.name),i=new ie(o,e,process.env.TOOLNET_HUB_OWNER?.trim()||"owner"),s=new se(i,Number(process.env.TOOLNET_HUB_MAX_EVENTS??100));await s.initialize();let a=new K(o,e),c=new F(a);await c.initialize();let l=new D(new L(o,e));await l.initialize();let u=new Q,p=new ne(o);u.importRecords(await p.load(e.id));let g=new te(u);Mr({project:e,retrieval:g,token:process.env.TOOLNET_API_TOKEN?.trim()||void 0,hub:s,wiki:c,governance:l}).listen(Cr,Ar,()=>{console.log("ToolNet Memory API"),console.log(`Project: ${e.name}`),console.log(`Listening: http://${Ar}:${Cr}`)})}Si().catch(r=>{console.error(r),process.exit(1)});
|