toolnet-memory 0.3.11 → 0.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +432 -163
- package/bundle/agy-hook.js +38 -38
- package/bundle/agy.js +23 -23
- package/bundle/api.js +19 -16
- package/bundle/claude-hook.js +9 -9
- package/bundle/codex.js +28 -28
- package/bundle/context-runtime.js +4 -4
- package/bundle/context.js +12 -12
- package/bundle/continuity-certify.js +16 -13
- package/bundle/copilot-hook.js +13 -13
- package/bundle/cursor-hook.js +13 -13
- package/bundle/grok-hook.js +13 -13
- package/bundle/kiro-hook.js +14 -14
- package/bundle/mcp.js +21 -18
- package/bundle/opencode.js +27 -27
- package/package.json +1 -1
package/bundle/api.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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
|
-
`)}]}}:{},contents:s,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),d=c.candidates?.[0]?.content?.parts?.map(u=>u.text??"").join("").trim();if(!d)throw new Error("gemini: empty model response");return{text:d,provider:"gemini",model:o,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var
|
|
10
|
-
[truncated]`}function
|
|
1
|
+
import"dotenv/config";import{existsSync as Xr,readFileSync as Zr}from"node:fs";import{homedir as en}from"node:os";import{join as tn}from"node:path";function rn(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 nn(){let r=process.env.TOOLNET_GLOBAL_ENV??tn(en(),".config","toolnet-memory",".env");if(!Xr(r))return;let e=Zr(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]=rn(n.slice(o+1)))}}nn();function K(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function N(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function xe(){return{memory:{autoCapture:K(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:K(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:K(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:K(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:N(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:N(process.env.MEMORY_RERANK_TOP,10),finalContext:N(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:N(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:K(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:N(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}var on={critical:100,high:75,normal:50,temporary:20};function Be(r){return on[r]}function ze(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 sn}from"node:crypto";import{existsSync as Ce,mkdirSync as an,readFileSync as cn,renameSync as un,writeFileSync as ln}from"node:fs";import{basename as dn,dirname as ee,join as re,parse as Je,resolve as L}from"node:path";var Ye=".toolnet",mn="project.json";function pn(r){return sn("sha256").update(r).digest("hex").slice(0,16)}function Pe(r){return re(r,Ye,mn)}function fn(r){return Ce(Pe(r))}function gn(r,e){let t=L(r),n=Je(t).root;for(;;){if(fn(t))return t;if(t===n||e&&t===L(e))break;let o=ee(t);if(o===t)break;t=o}return null}function yn(r){let e=L(r),t=Je(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>Ce(re(e,i))))return e;if(e===t)break;let o=ee(e);if(o===e)break;e=o}return L(r)}function hn(r){let e;try{e=JSON.parse(cn(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:ee(ee(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 Ve(r,e){let t=re(r,Ye);an(t,{recursive:!0});let n=Pe(r),o=`${n}.tmp-${process.pid}`;ln(o,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),un(o,n)}function qe(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 te=class{detect(e=process.cwd()){let t=L(e),n=yn(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>Ce(re(n,u))),s=gn(t,i?n:void 0);if(s){let u=Pe(s),f=hn(u);return f.rootPath!==s&&(f.rootPath=s,f.updatedAt=new Date().toISOString(),Ve(s,f)),qe(f,s)}let a=new Date().toISOString(),c=dn(n),d={version:1,id:pn(n),name:c,remote:c,rootPath:n,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return Ve(n,d),qe(d,n)}};import{randomUUID as On}from"node:crypto";var kn=[{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}],ne=class{scan(e){let t=[];for(let n of kn){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 E=class{scanner=new ne;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 vn=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),wn=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 Qe(r){return new Set(r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!wn.has(e)))}function bn(r,e){let t=Qe(r),n=Qe(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 Xe(r){return new Set(r.tags.filter(e=>!vn.has(e.toLowerCase())))}var oe=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=Xe(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=Xe(i);for(let c of o)if(a.has(c))return!0;return bn(e.content,i.content)>=.6})}};var Sn=new Set(["code","decision","rule","todo","summary"]);function An(r){return r.normalize("NFKC").toLowerCase().replace(/[“”"'`]/gu,"").replace(/[.!?]+$/gu,"").replace(/\s+/gu," ").trim()}function Ze(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 Mn(r,e){let t=Ze(e)-Ze(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 et(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 tt(r){let e=new Map;for(let o of r){if(!Sn.has(o.type)||o.metadata?.supersededBy)continue;let i=An(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(Mn),s=i[0];if(!s)continue;let a=i.slice(1);t.push({canonicalId:s.id,duplicateIds:a.map(c=>c.id),mergedTags:et(i.flatMap(c=>c.tags)),mergedSources:et(i.map(c=>c.source))}),n+=a.length}return{groups:t,duplicates:n}}function Ie(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 xn(r,e){let t=new Date(r.updatedAt).getTime();return Number.isFinite(t)?Math.max(0,(e-t)/864e5):0}function Cn(r){let e=Ie(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 Pn(r){return Ie(r)==="permanent"||r.type==="rule"||r.type==="decision"||r.importance==="critical"}function In(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 rt(r,e=Date.now()){let t=50,n=[],o=Ie(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")),In(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=xn(r,e)>=Cn(r);a&&(t-=15,n.push("stale for lifecycle class"));let c=Pn(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 En={critical:100,high:75,normal:50,temporary:20},Tn={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function nt(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 Ee(r,e=Date.now()){return r.expiresAt?new Date(r.expiresAt).getTime()<=e:!1}function Rn(r){return!!r.metadata?.supersededBy}function Te(r,e=Date.now()){return!Ee(r,e)&&!Rn(r)}function D(r,e=Date.now()){if(!Te(r,e))return 0;let t=En[r.importance];if(r.importance==="critical")return t;let n=Tn[r.type]??180,i=Math.max(0,e-new Date(r.updatedAt).getTime())/864e5,s=Math.pow(.5,i/n);return t*s}var ie=class{memories=new Map;sanitizer=new E;conflicts=new oe;remember(e){let t=new Date().toISOString(),n=this.sanitizer.sanitize(e.content.trim()).text,o=e.importance??ze(e.type,n),i={id:On(),projectId:e.projectId,type:e.type,content:n,importance:o,importanceScore:Be(o),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??nt(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=>Te(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=D(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=D(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=tt(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=rt(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&&Ee(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 Re(r){return r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}var se=class{score(e,t){let n=Re(e),o=Re([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 ot(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 it(r){return D(r)/100}var _n={rule:1,decision:.9,todo:.8,summary:.6,activity:.3};function st(r){return _n[r]??.4}var ae=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 ce=class{bm25=new se;analyzer=new ae;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=ot(c),f=it(c),h=st(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 ue=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 le=class{constructor(e){this.memory=e}memory;searcher=new ce;contextBuilder=new ue;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 ro}from"node:os";import{join as no}from"node:path";import{DeleteObjectCommand as jn,GetObjectCommand as Kn,HeadObjectCommand as Nn,ListObjectsV2Command as Ln,PutObjectCommand as Dn,S3Client as Fn}from"@aws-sdk/client-s3";import{getSignedUrl as $n}from"@aws-sdk/s3-request-presigner";var de=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 Dn({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await $n(this.client,new Kn({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 Nn({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 jn({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Ln({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 at,mkdir as Hn,readFile as Wn,readdir as Gn,rm as Un,stat as ct,writeFile as Bn}from"node:fs/promises";import{dirname as zn,join as Vn,relative as ut,resolve as qn}from"node:path";var F=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return qn(this.root,t)}async put(e,t){let n=this.path(e);await Hn(zn(n),{recursive:!0}),await Bn(n,t)}async get(e){try{return await Wn(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 at(this.path(e)),!0}catch{return!1}}async delete(e){await Un(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await at(t)}catch{return n}let o=async s=>{let a=await Gn(s,{withFileTypes:!0});for(let c of a){let d=Vn(s,c.name);if(c.isDirectory()){await o(d);continue}let u=await ct(d);n.push({key:ut(this.root,d),size:u.size,updatedAt:u.mtime.toISOString()})}},i=await ct(t);return i.isDirectory()?await o(t):n.push({key:ut(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),n}};import{DeleteObjectCommand as Jn,GetObjectCommand as Yn,HeadObjectCommand as Qn,ListObjectsV2Command as Xn,PutObjectCommand as Zn,S3Client as eo}from"@aws-sdk/client-s3";import{getSignedUrl as to}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 eo({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 Zn({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await to(this.client,new Yn({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 Qn({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 Jn({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Xn({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 Oe(r,e){return console.warn(e),new F(r)}function lt(r){let e=r.localRoot??no(ro(),".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}):Oe(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}):Oe(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 de({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Oe(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new F(e)}var me=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 oo(r){return new Promise(e=>setTimeout(e,r))}async function dt(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)),d=Math.floor(Math.random()*Math.max(1,c*.2));await oo(c+d)}throw i}var io=new Set(["put","get","getText","delete","list"]);function mt(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:io.has(n)?(...i)=>dt(()=>Promise.resolve(o.apply(t,i)),e):o.bind(t)}})}function pt(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 ft(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 pe=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=pt(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=ft(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 gt="hub/state.v1.json";function so(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 ao(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 fe=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(gt);if(!e){let t=so(this.project,this.ownerPrincipal);return await this.save(t),t}return ao(e,this.project)}async save(e){await this.storage.put(gt,JSON.stringify(e,null,2),"application/json")}};import{randomUUID as _e}from"node:crypto";var yt=["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 co(r){return r==="owner"||r==="admin"?[...A]:["hub:read"]}function je(r){return[...new Set(r.map(e=>e.trim()).filter(Boolean))]}function uo(r){return structuredClone(r)}var ge=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:_e(),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-${_e().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-${_e().slice(0,8)}`;if(n.agents.some(c=>c.id===i))throw new v(`Agent already exists: ${i}`,409);let s=je(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:[...yt],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=je(t.scopes??co(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:[...yt],memoryMode:"local",skillMemory:!0,contextOffload:!0,maxContextChars:6400,updatedAt:o},n.loadouts.push(i)),t.tools&&(i.tools=je(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 uo(await this.ensureState())}};var ht="wiki/state.v1.json";function lo(r){let e=new Date().toISOString();return{schema:"toolnet.wiki.v1",version:1,projectId:r.id,pages:[],revisions:[],createdAt:e,updatedAt:e}}function mo(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 H=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=lo(this.project);return await this.save(t),t}return mo(e,this.project)}async save(e){await this.storage.put(ht,JSON.stringify(e,null,2),"application/json")}};import{randomUUID as wt}from"node:crypto";var g=class extends Error{constructor(t,n){super(t);this.statusCode=n}statusCode};function W(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 G(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 kt(r){let e=[];for(let t of r.matchAll(/\[\[([^\[\]]+)\]\]/gu)){let n=t[1]?.trim();n&&e.push(G(n))}return W(e)}function po(r){return r.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_-]+/u).map(e=>e.trim()).filter(e=>e.length>=2)}function vt(r){return{id:`revision-${wt()}`,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 C(r){return structuredClone(r)}var U=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:W(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 C([...e.pages].sort((t,n)=>t.title.localeCompare(n.title)))}async getPage(e){let t=await this.ensureState(),n=G(e),o=t.pages.find(i=>i.slug===n||i.id===e);if(!o)throw new g(`Wiki page not found: ${e}`,404);return C(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=G(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-${wt()}`,slug:i,title:n,...e.summary?.trim()?{summary:e.summary.trim()}:{},content:o,tags:W(e.tags??[]),links:kt(o),revision:1,createdAt:s,updatedAt:s};return t.pages.push(a),t.revisions.push(vt(a)),C(a)})}async updatePage(e,t){return this.mutate(n=>{let o=G(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=kt(i.content)),t.tags!==void 0&&(i.tags=W(t.tags)),i.revision+=1,i.updatedAt=new Date().toISOString(),n.revisions.push(vt(i)),C(i)})}async history(e){let t=await this.getPage(e),n=await this.ensureState();return C(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 C(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=W(po(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(Me=>Me===b)?k+=5:h.some(Me=>Me.includes(b))&&(k+=3),u.includes(b)&&(k+=2),f.includes(b)&&(k+=1);k>0&&s.push({page:C(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 fo,randomUUID as bt}from"node:crypto";var St="wiki/governance.v1.json",Ct="toolnet.knowledge-governance.v1",At=500,B={autoApproveThreshold:.86,criticalApproveThreshold:.94,staleAfterDays:90};function go(r,e=0,t=1){return Math.max(e,Math.min(t,r))}function Ke(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/gu," ").trim()}function Mt(r){return fo("sha256").update(r.normalize("NFKC").replace(/\s+/gu," ").trim()).digest("hex")}function yo(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 ho(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),go(e)}function xt(r){let e=new Date().toISOString();return{schema:Ct,version:1,projectId:r,policy:{...B},reviews:[],audit:[],createdAt:e,updatedAt:e}}function Pt(r){let e=r.autoApproveThreshold??B.autoApproveThreshold,t=r.criticalApproveThreshold??B.criticalApproveThreshold,n=r.staleAfterDays??B.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 z=class{constructor(e,t){this.storage=e;this.project=t}storage;project;async load(){let e=await this.storage.getText(St);if(!e){let t=xt(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:Pt(t.policy??B)}}catch{let t=xt(this.project.id);return await this.save(t),t}}async save(e){await this.storage.put(St,JSON.stringify(e,null,2),"application/json")}},V=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:bt(),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>At&&(e.audit=e.audit.slice(-At))}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=Pt({...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=ho(e),i=Ke(e.title),s=t.filter(u=>u.slug!==e.slug&&Ke(u.title)===i&&Mt(u.content)!==Mt(e.content)).map(u=>u.slug),a=yo(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:bt(),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=Ke(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 zi}from"node:crypto";import{createServer as Vi}from"node:http";function It(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 Et(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 He}from"zod";import{existsSync as _o,readFileSync as jo}from"node:fs";import{join as Ko}from"node:path";import{existsSync as ko,mkdirSync as jc,readFileSync as vo,renameSync as Kc,writeFileSync as Nc}from"node:fs";import{dirname as Dc,join as wo}from"node:path";function bo(r){return wo(r.rootPath,".toolnet","work","current.json")}function Ne(r){let e=bo(r);if(!ko(e))return null;try{let t=JSON.parse(vo(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as So,mkdirSync as Hc,readFileSync as Ao,renameSync as Wc,writeFileSync as Gc}from"node:fs";import{dirname as Bc,join as Mo}from"node:path";function xo(r){return Mo(r.rootPath,".toolnet","context","session-origin.json")}function Le(r){let e=xo(r);if(!So(e))return null;try{let t=JSON.parse(Ao(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function Co(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function ye(r){let e=Co(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 Io,mkdirSync as Cu,readFileSync as Eo}from"node:fs";import{join as Tt}from"node:path";var fu=new E;function To(r){return Tt(r.rootPath,".toolnet","memory","checkpoints")}function Ro(r){return Tt(To(r),"latest.json")}function Oo(r){let e=Ro(r);if(!Io(e))return null;try{let t=JSON.parse(Eo(e,"utf8"));return t.schema!=="toolnet.memory.checkpoint.v1"||t.project.id!==r.id?null:t}catch{return null}}function Rt(r){return Oo(r)}var No={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}},Lo={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function Do(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 Fo(r){let e=Ko(r.rootPath,".toolnet","work","handoff-latest.json");if(!_o(e))return null;try{let n=JSON.parse(jo(e,"utf8")).continuity;return n?.schema!=="toolnet.handoff.v2"||n.project.id!==r.id?null:n}catch{return null}}function $o(r){let e=Rt(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 Ho(r){let e=Fo(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 Wo(r){let e=Le(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 Go(r){let e=Ne(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 Uo(r,e){let t=No[r];return e.map((n,o)=>({...n,score:(t[n.kind]??10)+Lo[n.source]+Math.max(0,5-o*.01)}))}function Bo(r){let e=new Map;for(let t of r){let n=`${t.kind}:${Do(t.value)}`,o=e.get(n);(!o||t.score>o.score)&&e.set(n,t)}return[...e.values()]}function T(r,e,t={}){let n=ye(e),o=[...$o(r),...Ho(r),...Wo(r),...Go(r)],i=Bo(Uo(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 Ot={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"},_t=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],zo={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:_t};function Vo(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 qo(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 Jo(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 jt(r){switch(r){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function Yo(r,e){let t=[];for(let n of e){let o=r.filter(i=>i.kind===n).slice(0,jt(n));for(let i of o)t.push(`${Ot[n]}: ${i.value}`)}return t.join(`
|
|
6
|
+
`)}function Qo(r,e){let t=zo[e]??_t,n=[];for(let o of t){let i=r.filter(s=>s.kind===o).slice(0,jt(o));for(let s of i)n.push(`${Ot[o]}: ${s.value}`)}return n.join(`
|
|
7
|
+
`)}function R(r,e){let t=T(r,e,{maxFacts:32,maxChars:6400}),n=Jo(qo(t.facts)),o=Vo(e)?Yo(n,["todo","task","next_action","file"]):Qo(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"}}var Kt=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function P(r){let e=Kt.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function q(r){return Kt.some(e=>e.id===r)}function l(r){return process.env[r]?.trim()||void 0}function y(...r){return r.find(e=>!!e?.trim())}function Nt(){if(l("GROQ_API_KEY"))return"groq";if(l("DEEPSEEK_API_KEY"))return"deepseek";if(l("NVIDIA_API_KEY")||l("NVIDIA_NIM_API_KEY"))return"nvidia";if(l("OPENROUTER_API_KEY"))return"openrouter";if(l("ALIBABA_API_KEY")||l("DASHSCOPE_API_KEY"))return"alibaba";if(l("GEMINI_API_KEY")||l("GOOGLE_API_KEY"))return"gemini";if(l("CLOUDFLARE_API_TOKEN")&&l("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(l("HF_TOKEN"))return"huggingface";if(l("OLLAMA_MODEL")||l("OLLAMA_BASE_URL"))return"ollama"}function Lt(){let r=l("TOOLNET_LLM_PROVIDER");return r&&q(r)?r:Nt()??"openai-compatible"}function he(r){let e=P(r);switch(r){case"alibaba":return{provider:r,apiKey:y(l("ALIBABA_API_KEY"),l("DASHSCOPE_API_KEY")),baseUrl:y(l("ALIBABA_BASE_URL"),l("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:y(l("ALIBABA_MODEL"),l("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:l("OPENROUTER_API_KEY"),baseUrl:y(l("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:l("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:l("GROQ_API_KEY"),baseUrl:y(l("GROQ_BASE_URL"),e.defaultBaseUrl),model:l("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:l("DEEPSEEK_API_KEY"),baseUrl:y(l("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:y(l("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:y(l("NVIDIA_API_KEY"),l("NVIDIA_NIM_API_KEY")),baseUrl:y(l("NVIDIA_BASE_URL"),l("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:y(l("NVIDIA_MODEL"),l("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:y(l("GEMINI_API_KEY"),l("GOOGLE_API_KEY")),baseUrl:y(l("GEMINI_BASE_URL"),e.defaultBaseUrl),model:l("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:l("HF_TOKEN"),baseUrl:y(l("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:y(l("HF_LLM_MODEL"),l("HF_MODEL"))};case"ollama":return{provider:r,apiKey:l("OLLAMA_API_KEY"),baseUrl:y(l("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:l("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:l("CLOUDFLARE_ACCOUNT_ID"),apiKey:l("CLOUDFLARE_API_TOKEN"),baseUrl:l("CLOUDFLARE_AI_BASE_URL"),model:l("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:l("CUSTOM_AI_API_KEY"),baseUrl:l("CUSTOM_AI_BASE_URL"),model:l("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:y(l("OPENAI_API_KEY"),l("MODEL_API_KEY")),baseUrl:y(l("OPENAI_BASE_URL"),l("MODEL_BASE_URL")),model:y(l("OPENAI_MODEL"),l("MODEL_NAME"))}}}function Xo(){let r=l("TOOLNET_LLM_PROVIDER"),e=r&&q(r)?r:Lt(),t=P(e),n=he(e);return{provider:e,apiKey:y(l("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:y(l("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:y(l("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:y(l("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function Zo(){let r=l("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&q(r)?r:l("HF_TOKEN")||l("HF_EMBEDDING_MODEL")?"huggingface":"local"}function ei(){let r=Zo();if(r==="local")return{provider:"local",model:y(l("TOOLNET_EMBEDDING_MODEL"),l("LOCAL_EMBEDDING_MODEL"))};let e=P(r),t,n,o,i;switch(r){case"huggingface":t=l("HF_TOKEN"),n=l("HF_INFERENCE_BASE_URL"),o=l("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=l("OPENAI_API_KEY"),n=l("OPENAI_BASE_URL"),o=l("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=l("CLOUDFLARE_API_TOKEN"),n=l("CLOUDFLARE_AI_BASE_URL"),o=l("CLOUDFLARE_EMBEDDING_MODEL"),i=l("CLOUDFLARE_ACCOUNT_ID");break;default:t=he(r).apiKey,n=he(r).baseUrl,o=l(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let s=y(l("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),a=y(l("TOOLNET_EMBEDDING_BASE_URL"),n,e.defaultBaseUrl),c=r==="cloudflare"&&!a&&s?`https://api.cloudflare.com/client/v4/accounts/${s}/ai/v1`:a;return{provider:r,apiKey:y(l("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:c,model:y(l("TOOLNET_EMBEDDING_MODEL"),o),accountId:s}}function De(){let r=Xo(),e=ei();return{llm:r,embedding:e,legacy:{llm:!l("TOOLNET_LLM_PROVIDER")&&!!Nt(),embedding:!l("TOOLNET_EMBEDDING_PROVIDER")&&!!(l("HF_TOKEN")||l("HF_EMBEDDING_MODEL"))}}}function Dt(r=Lt()){let e=De().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=he(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function J(r,e){return l(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function Ft(){let r=[];for(let e of[1,2]){let t=J(e,"PROVIDER");if(!t||!q(t))continue;let n=P(t);r.push({slot:e,config:{provider:t,apiKey:J(e,"API_KEY"),baseUrl:y(J(e,"BASE_URL"),n.defaultBaseUrl),model:y(J(e,"MODEL"),n.defaultModel),accountId:J(e,"ACCOUNT_ID")}})}return r}function $t(){let r=l("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=l("TOOLNET_LLM_MAX_RETRIES"),t=Number(r??6e4),n=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(n)&&n>=0?Math.floor(n):1}}var Y=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function O(r,e,t=3e4){let n=new AbortController,o=setTimeout(()=>n.abort(),t);o.unref?.();try{let i=await fetch(r,{...e,signal:n.signal}),s=await i.text();if(!i.ok){let a=s;try{let c=JSON.parse(s);a=c.error?.message??c.message??s}catch{}throw new Y(a||`HTTP ${i.status}`,i.status)}return s.trim()?JSON.parse(s):{}}finally{clearTimeout(o)}}function ke(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var ve=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),n=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!n)throw new Error("cloudflare: API TOKEN is not configured");let o=this.model(),s=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${o}`,a=await O(s,{method:"POST",headers:{authorization:`Bearer ${n}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),c=a.result?.response?.trim();if(!c)throw new Error(a.errors?.[0]?.message??"cloudflare: empty model response");return{text:c,provider:"cloudflare",model:o}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var we=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let n=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",o=this.model(),i=e.messages.filter(u=>u.role==="system"),s=e.messages.filter(u=>u.role!=="system").map(u=>({role:u.role==="assistant"?"model":"user",parts:[{text:u.content}]})),a=`${ke(n,`models/${encodeURIComponent(o)}:generateContent`)}?key=${encodeURIComponent(t)}`,c=await O(a,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(u=>u.content).join(`
|
|
8
|
+
|
|
9
|
+
`)}]}}:{},contents:s,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),d=c.candidates?.[0]?.content?.parts?.map(u=>u.text??"").join("").trim();if(!d)throw new Error("gemini: empty model response");return{text:d,provider:"gemini",model:o,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var be=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),n=await O(ke(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),o=n.choices?.[0]?.message?.content?.trim();if(!o)throw new Error(`${this.id}: empty model response`);return{text:o,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function Ht(r=Dt()){switch(P(r.id).transport){case"gemini":return new we(r);case"cloudflare":return new ve(r);default:return new be(r)}}function ti(r){return new Promise(e=>{setTimeout(e,r)})}function ri(r){if(r instanceof Y){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var Se=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],n={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=n.cooldownMs??6e4,this.maxRetries=Math.max(0,n.maxRetries??1),this.providers=[e,...t].map(o=>({provider:Ht(o.config),label:o.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),n=this.states.get(t);return n||(n={failures:0,cooldownUntil:0},this.states.set(t,n)),n}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let n=this.state(e);n.failures+=1,n.lastError=t instanceof Error?t.message:String(t),n.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let n=0;n<this.providers.length;n+=1){if(!this.available(n)){t.push(`${this.providers[n].label}: cooldown`);continue}let o=this.providers[n];for(let i=0;i<=this.maxRetries;i+=1)try{let s=await o.provider.generate(e);return this.success(n),s}catch(s){let a=s instanceof Error?s.message:String(s),c=ri(s);if(t.push(`${o.label}: ${a}`),!c)throw s;if(i<this.maxRetries){await ti(Math.min(250*2**i,2e3));continue}this.fail(n,s)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:t.provider,model:t.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,t)=>{let n=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:n.cooldownUntil>Date.now(),cooldownUntil:n.cooldownUntil||void 0,failures:n.failures,lastError:n.lastError}})}};function Wt(){let r=De(),e=Ft();return new Se({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),$t())}var Fe=class{constructor(e=Wt()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function Gt(){return new Fe(Wt())}function ni(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
|
|
10
|
+
[truncated]`}function oi(r,e){let t=R(r,e),n=T(r,e,{maxFacts:12,maxChars:3200});return ni({project:n.context.project,intent:n.intent,directAnswer:t.answer,selectedMemory:n.context.selectedFacts,retrievalStats:n.stats},4200)}async function Ut(r,e,t={}){let n=R(r,e),o=oi(r,e),i=t.router??Gt();try{let s=await i.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
|
|
11
11
|
You are ToolNet Memory Agent.
|
|
12
12
|
|
|
13
13
|
You are NOT the coding agent.
|
|
@@ -44,9 +44,12 @@ ToolNet selected memory:
|
|
|
44
44
|
${o}
|
|
45
45
|
|
|
46
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
|
|
48
|
-
`,{encoding:"utf8",mode:384}),
|
|
49
|
-
`)}function
|
|
50
|
-
`):e.trim(),c=
|
|
51
|
-
|
|
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)});
|
|
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 ii,mkdirSync as si,readFileSync as ai,renameSync as ci,rmSync as ui,writeFileSync as li}from"node:fs";import{join as Bt}from"node:path";var di=720*60*1e3;function zt(r){return Bt(r.rootPath,".toolnet","context","memory-agent-conversation.json")}function Q(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function mi(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 pi(r){if(mi(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 fi(r,e,t){let n=zt(r);if(!ii(n))return null;try{let o=JSON.parse(ai(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 gi(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 yi(r,e){let t=zt(r),n=Bt(r.rootPath,".toolnet","context");si(n,{recursive:!0,mode:448});let o=`${t}.${process.pid}.tmp`;try{li(o,JSON.stringify(e,null,2)+`
|
|
48
|
+
`,{encoding:"utf8",mode:384}),ci(o,t)}finally{ui(o,{force:!0})}}function hi(r){return r.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
|
|
49
|
+
`)}function ki(r,e){return r.priorFocus.find(t=>t.kind===e)?.value}function $e(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=ki(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 vi(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 Vt(r,e,t={}){let n=t.now??Date.now(),o=t.maxAgeMs??di,i=fi(r,n,o),s=!!(i&&i.focus.length>0&&pi(e)&&!vi(e)),a=s&&i?[e.trim(),"","Previous ToolNet Memory conversation focus:",hi(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=ye(e),u=T(r,a,{maxFacts:8,maxChars:1800}).facts.map(h=>({kind:h.kind,value:h.value,source:h.source})),f=gi(s&&i?[...u,...i.focus]:u);return yi(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}}import{existsSync as wi,readFileSync as bi}from"node:fs";import{join as Si}from"node:path";function M(r){return!!r?.trim()}function qt(r){let e=[],t=[],n=100;M(r.goal)||M(r.request)||(e.push("goal_or_request"),n-=20),M(r.activity)||M(r.current.task?.title)||M(r.current.phase?.title)||(e.push("current_work"),n-=25),M(r.nextAction)||M(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),M(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 d=e.includes("current_work")||e.includes("next_action"),u;return n>=80&&!d?u="high":n>=50?u="medium":u="low",{confidence:u,score:n,missingContext:e,warnings:t}}var Jt={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 _(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 j(r){return r.length>0?r.map(e=>`- ${e}`).join(`
|
|
51
|
+
`):"- none"}function Ai(r,e){return r.length<=e?r:[r.slice(0,e).trimEnd(),"","[Structured handoff truncated]"].join(`
|
|
52
|
+
`)}function Yt(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 Mi(r,e="normal"){let t=Jt[e],n=_([`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=_([...r.completed.phases.map(d=>`Phase: ${d}`),...r.completed.tasks.map(d=>`Task: ${d}`)]).slice(0,t.completed),i=_([`Tests status: ${r.tests.status}`,...r.tests.recent.map(d=>`Test: ${d}`),...(r.tests.checks??[]).map(d=>`Check [${d.status}] ${d.kind}: ${d.command}`),...(r.evidence?.commands??[]).map(d=>`Command: ${d}`),...(r.evidence?.references??[]).map(d=>`Reference: ${d}`),...r.decisions.map(d=>`Decision: ${d}`),...r.attention.map(d=>`Attention: ${d}`)]).slice(0,t.evidence),s=_([r.files.current,...(r.files.active??[]).map(d=>`Active: ${d}`),...(r.files.modified??[]).map(d=>`Modified: ${d}`),...(r.files.created??[]).map(d=>`Created: ${d}`),...(r.files.deleted??[]).map(d=>`Deleted: ${d}`),...r.files.recent.map(d=>`Recent: ${d}`)]).slice(0,t.files),a=_(r.blockers).slice(0,t.blockers),c=_([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 xi(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",j(r.currentState),"","COMPLETED",j(r.completed),"","EVIDENCE",j(r.evidence),"","FILES_TOUCHED",j(r.filesTouched),"","BLOCKERS",j(r.blockers),"","NEXT_ACTION",j(r.nextAction)].join(`
|
|
53
|
+
`)}function Qt(r,e="normal"){let t=Si(r.rootPath,".toolnet","work","handoff-latest.json");if(!wi(t))return null;try{let o=JSON.parse(bi(t,"utf8")).continuity;if(!o||o.schema!=="toolnet.handoff.v2"||o.version!==2)return null;let i=Mi(o,e),s=qt(o),a=Ai(xi(i,e,s),Jt[e].maxChars);return{detail:e,data:i,quality:s,text:a}}catch{return null}}function Ci(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}var Pi=[/\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],Ii=[/\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],Ei=[/\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 Ti(r){let e=0;for(let t of Ii)t.test(r)&&(e+=1);return e}function Xt(r,e){let t=Ci(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=Pi.some(a=>a.test(t)),i=Ei.some(a=>a.test(t)),s=Ti(t);return!!(o&&s>=1||i&&s>=2||s>=4)}var El={question:He.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:He.enum(["ai","local"]).optional().describe("ai uses ToolNet Memory Agent with configured LLM fallback chain. local returns deterministic local memory only."),detail:He.enum(["compact","normal","benchmark"]).optional().describe("Handoff detail level. compact=minimal, normal=standard, benchmark=deep evidence/files/tests for agent takeover.")};function Ae(r,e,t,n,o){if(!Xt(e,t))return{answer:n};let i=Yt(e,o),s=Qt(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 Zt(r,e){let t=Vt(r.project,e.question);if(e.mode==="local"){let s=$e(t);if(s)return{...Ae(r,t.originalQuestion,String(s.intent),s.answer,e.detail),mode:"local",usedAi:!1,source:s.source,intent:s.intent};let a=R(r.project,t.originalQuestion);return{...Ae(r,t.originalQuestion,String(a.intent),a.answer,e.detail),mode:"local",usedAi:!1,source:a.source,intent:a.intent}}let n=R(r.project,t.originalQuestion),o=Ae(r,t.originalQuestion,String(n.intent),n.answer,e.detail);if("handoff"in o)return{...o,mode:"ai",usedAi:!1,source:n.source,intent:n.intent,routing:"deterministic-handoff"};let i=await Ut(r.project,t.question);if(!i.usedAi){let s=$e(t);if(s)return{...Ae(r,t.originalQuestion,String(s.intent),s.answer,e.detail),mode:"ai",usedAi:!1,provider:i.provider,model:i.model}}return{answer:i.answer,mode:"ai",usedAi:i.usedAi,provider:i.provider,model:i.model}}import{z as sr}from"zod";import{chmodSync as Ol,existsSync as er,mkdirSync as _l,readFileSync as tr,renameSync as jl,writeFileSync as Kl}from"node:fs";import{dirname as Ll,join as X}from"node:path";var rr="toolnet.context-offload.v1",Ri="toolnet.context-offload-asset.v1";function nr(r){return X(r,".toolnet","offload")}function or(r){return X(nr(r),"assets")}function Oi(r){return X(nr(r),"graph.json")}function We(){return{schema:rr,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function _i(r){let e=Oi(r);if(!er(e))return We();try{let t=JSON.parse(tr(e,"utf8"));return t.schema!==rr||t.version!==1||!Array.isArray(t.nodes)?We():t}catch{return We()}}function ji(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&&er(X(or(r),`${t}.json`)))return t;let n=_i(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 ir(r,e,t=6e3){let n=ji(r,e),o=tr(X(or(r),`${n}.json`),"utf8"),i=JSON.parse(o);if(i.schema!==Ri||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)}
|
|
54
|
+
[truncated]`:o}}var Hl={assetId:sr.string().regex(/^[a-f0-9]{8,64}$/iu).describe("Asset reference from the ToolNet Context Offload Graph."),maxChars:sr.number().int().min(200).max(2e4).optional().describe("Maximum asset characters to return. Defaults to 6000.")};async function ar(r,e){return ir(r.project.rootPath,e.assetId,e.maxChars??6e3)}async function cr(r,e){return{schema:"toolnet.api-memory-ask.v1",result:await Zt({project:r},e)}}async function ur(r,e){return{schema:"toolnet.api-context-offload.v1",result:await ar({project:r},e)}}import{z as lr}from"zod";var Vl={query:lr.string(),limit:lr.number().int().min(1).max(20).optional()};async function dr(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 fr}from"zod";import{chmodSync as Yl,existsSync as Ki,mkdirSync as Ql,readFileSync as Ni,readdirSync as Li,renameSync as Xl,statSync as Di,writeFileSync as Zl}from"node:fs";import{join as mr}from"node:path";var Fi="toolnet.skill-memory.v1";function $i(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 Hi(r){return mr(r.rootPath,".toolnet","memory","skills")}function Wi(r,e){if(!r||typeof r!="object")return!1;let t=r;return t.schema===Fi&&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 Gi(r){let e=Hi(r);if(!Ki(e))return[];if(!Di(e).isDirectory())return[];let t=[];for(let n of Li(e)){if(!n.endsWith(".json"))continue;let o=mr(e,n);try{let i=JSON.parse(Ni(o,"utf8"));Wi(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 Ui(r){return $i(r.normalize("NFKC").toLowerCase().split(/[^\p{L}\p{N}_./-]+/gu).filter(e=>e.length>=2),32)}function Bi(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(`
|
|
55
|
+
`).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 Ui(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 pr(r,e,t=5){let n=Math.max(1,Math.min(10,Math.floor(t)));return Gi(r).map(o=>({...o,score:Bi(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 od={query:fr.string().min(2).max(500).describe("Task, problem, file, command or workflow to match against successful reusable Skill Memory SOPs."),limit:fr.number().int().min(1).max(10).optional().describe("Maximum matching reusable SOPs to return. Default 5.")};async function gr(r,e){let t=pr(r.project,e.query,e.limit??5);return{schema:"toolnet.skill-memory-search.v1",query:e.query,count:t.length,matches:t}}async function yr(r,e,t){return{schema:"toolnet.api-memory-search.v1",results:await dr({project:r,retrieval:e},t)}}async function hr(r,e){return{schema:"toolnet.api-skill-search.v1",result:await gr({project:r},e)}}function Z(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 kr(r,e,t=500){if(r!==void 0)return S(r,e,1,t)}function Ge(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 vr(r,e){return{schema:"toolnet.api-hub-summary.v1",hub:await r.summary(e)}}async function wr(r,e){return{schema:"toolnet.api-hub-teams.v1",teams:await r.listTeams(e)}}async function br(r,e,t){let n=Z(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:kr(n.description,"team description",500)}:{}};return{schema:"toolnet.api-hub-team.v1",team:await r.createTeam(e,o)}}async function Sr(r,e){return{schema:"toolnet.api-hub-agents.v1",agents:await r.listAgents(e)}}async function Ar(r,e,t){let n=Z(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:kr(n.kind,"agent kind",100)}:{},...n.teamIds!==void 0?{teamIds:Ge(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 Mr(r,e){return{schema:"toolnet.api-hub-acl.v1",grants:await r.listAcl(e)}}async function xr(r,e,t){let n=Z(t),o=S(n.role,"role",4,20);if(!["owner","admin","member","viewer"].includes(o))throw new Error("Invalid role");let i=Ge(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 Cr(r,e,t){let n=Z(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 Pr(r,e){return{schema:"toolnet.api-hub-loadouts.v1",loadouts:await r.listLoadouts(e)}}async function Ir(r,e,t){let n=Z(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:Ge(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 Er(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 g(`Principal '${e}' lacks '${t}'`,403)}function Tr(r){if(!r||typeof r!="object"||Array.isArray(r))throw new g("Invalid Wiki request",400);return r}function Ue(r,e,t){if(typeof r!="string"||!r.trim()||r.length>t)throw new g(`Invalid ${e}`,400);return r.trim()}function Rr(r,e,t){if(r!==void 0){if(typeof r!="string"||r.length>t)throw new g(`Invalid ${e}`,400);return r}}function Or(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 _r(r,e,t){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-summary.v1",wiki:await r.summary()}}async function jr(r,e,t){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-pages.v1",pages:await r.listPages()}}async function Kr(r,e,t,n){await x(e,t,"wiki:write");let o=Tr(n),i={...o.slug!==void 0?{slug:Ue(o.slug,"Wiki slug",120)}:{},title:Ue(o.title,"Wiki title",200),...o.summary!==void 0?{summary:Rr(o.summary,"Wiki summary",1e3)}:{},content:typeof o.content=="string"?o.content:"",...o.tags!==void 0?{tags:Or(o.tags)}:{}};return{schema:"toolnet.api-wiki-page.v1",page:await r.createPage(i)}}async function Nr(r,e,t,n){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-page.v1",page:await r.getPage(n)}}async function Lr(r,e,t,n,o){await x(e,t,"wiki:write");let i=Tr(o),s={...i.title!==void 0?{title:Ue(i.title,"Wiki title",200)}:{},...i.summary!==void 0?{summary:Rr(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:Or(i.tags)}:{}};return{schema:"toolnet.api-wiki-page.v1",page:await r.updatePage(n,s)}}async function Dr(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 $r(r,e,t,n){return await x(e,t,"wiki:read"),{schema:"toolnet.api-wiki-backlinks.v1",pages:await r.backlinks(n)}}async function I(r,e,t){if(!await r.authorize(e,t))throw new g(`Principal '${e}' lacks '${t}'`,403)}function Hr(r){if(!r||typeof r!="object"||Array.isArray(r))throw new g("Invalid governance request",400);return r}async function Wr(r,e,t){return await I(e,t,"governance:read"),{schema:"toolnet.api-governance-summary.v1",governance:await r.summary()}}async function Gr(r,e,t,n){if(await I(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 Ur(r,e,t,n,o,i){await I(t,n,"governance:write");let s=Hr(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 Br(r,e,t,n){return await I(t,n,"governance:read"),{schema:"toolnet.api-knowledge-quality.v1",quality:await r.quality(e)}}async function zr(r,e,t){return await I(e,t,"governance:read"),{schema:"toolnet.api-governance-policy.v1",policy:await r.policy()}}async function Vr(r,e,t,n){await I(e,t,"governance:write");let o=Hr(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 qr(r,e,t,n){return await I(e,t,"governance:read"),{schema:"toolnet.api-governance-audit.v1",events:await r.auditLog(n)}}function qi(r){let e=r.headers["x-toolnet-principal"];return(Array.isArray(e)?e[0]:e)?.trim()||"anonymous"}function Ji(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&&zi(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 Yi(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 Qi(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 Xi(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 Zi(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 Jr(r){return Vi(async(e,t)=>{try{let n=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`),o=qi(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/")&&!Ji(e,r.token)){p(t,401,{error:"Unauthorized"});return}if(e.method==="GET"&&n.pathname==="/v1/health"){p(t,200,It(r.project));return}if(e.method==="GET"&&n.pathname==="/v1/project"){p(t,200,Et(r.project));return}if(e.method==="POST"&&n.pathname==="/v1/memory/ask"){let u=Yi(await w(e));if(!u){p(t,400,{error:"Invalid memory ask request"});return}p(t,200,await cr(r.project,u));return}if(e.method==="POST"&&n.pathname==="/v1/memory/search"){let u=Qi(await w(e));if(!u){p(t,400,{error:"Invalid memory search request"});return}p(t,200,await yr(r.project,r.retrieval,u));return}if(e.method==="POST"&&n.pathname==="/v1/skills/search"){let u=Xi(await w(e));if(!u){p(t,400,{error:"Invalid skill search request"});return}p(t,200,await hr(r.project,u));return}if(e.method==="POST"&&n.pathname==="/v1/offload/read"){let u=Zi(await w(e));if(!u){p(t,400,{error:"Invalid context offload request"});return}p(t,200,await ur(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 vr(r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/hub/teams"){p(t,200,await wr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/teams"){p(t,201,await br(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/agents"){p(t,200,await Sr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/agents"){p(t,201,await Ar(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/acl"){p(t,200,await Mr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/acl/grant"){p(t,200,await xr(r.hub,o,await w(e)));return}if(e.method==="POST"&&n.pathname==="/v1/hub/acl/revoke"){p(t,200,await Cr(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/loadouts"){p(t,200,await Pr(r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/hub/loadouts"){p(t,200,await Ir(r.hub,o,await w(e)));return}if(e.method==="GET"&&n.pathname==="/v1/hub/observability"){p(t,200,await Er(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 _r(r.wiki,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/wiki/pages"){p(t,200,await jr(r.wiki,r.hub,o));return}if(e.method==="POST"&&n.pathname==="/v1/wiki/pages"){p(t,201,await Kr(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 Dr(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 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){p(t,200,await $r(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 Nr(r.wiki,r.hub,o,decodeURIComponent(c[1])));return}if(e.method==="PUT"&&c){p(t,200,await Lr(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 Wr(r.governance,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/governance/reviews"){p(t,200,await Gr(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 Ur(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 Br(r.governance,r.wiki,r.hub,o));return}if(e.method==="GET"&&n.pathname==="/v1/governance/policy"){p(t,200,await zr(r.governance,r.hub,o));return}if(e.method==="PUT"&&n.pathname==="/v1/governance/policy"){p(t,200,await Vr(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 qr(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 Yr=process.env.TOOLNET_API_HOST??"127.0.0.1",Qr=Number(process.env.TOOLNET_API_PORT??9750);async function es(){let r=xe(),e=new te().detect(),t=lt({provider:r.storage.provider,r2:r.storage.r2,s3:r.storage.s3,huggingface:r.storage.huggingface,localRoot:r.storage.localRoot}),n=mt(t,{attempts:Number(process.env.TOOLNET_STORAGE_RETRIES??3)}),o=new pe(n,e.id,e.name,e.remote??e.name),i=new fe(o,e,process.env.TOOLNET_HUB_OWNER?.trim()||"owner"),s=new ge(i,Number(process.env.TOOLNET_HUB_MAX_EVENTS??100));await s.initialize();let a=new H(o,e),c=new U(a);await c.initialize();let d=new V(new z(o,e));await d.initialize();let u=new ie,f=new me(o);u.importRecords(await f.load(e.id));let h=new le(u);Jr({project:e,retrieval:h,token:process.env.TOOLNET_API_TOKEN?.trim()||void 0,hub:s,wiki:c,governance:d}).listen(Qr,Yr,()=>{console.log("ToolNet Memory API"),console.log(`Project: ${e.name}`),console.log(`Listening: http://${Yr}:${Qr}`)})}es().catch(r=>{console.error(r),process.exit(1)});
|