toolnet-memory 0.2.2 → 0.2.4
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/bin/toolnet-memory +28 -6
- package/bundle/agy.js +20 -20
- package/bundle/codex.js +33 -33
- package/bundle/config.js +15 -0
- package/bundle/context-runtime.js +9 -9
- package/bundle/context.js +12 -12
- package/bundle/doctor.js +3 -3
- package/bundle/full-index.js +8 -8
- package/bundle/graph-index.js +4 -0
- package/bundle/impact.js +4 -0
- package/bundle/incremental.js +4 -0
- package/bundle/learner.js +4 -4
- package/bundle/mcp.js +6 -6
- package/bundle/opencode.js +36 -36
- package/bundle/project-manual.js +7 -7
- package/bundle/runtime.js +11 -0
- package/bundle/semantic.js +6 -0
- package/bundle/snapshot.js +3 -3
- package/bundle/update.js +1 -0
- package/bundle/work-continuity.js +4 -4
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import{existsSync as ut}from"node:fs";import{dirname as lt,join as dt,resolve as mt}from"node:path";import{existsSync as se,readFileSync as ne}from"node:fs";import{homedir as ie}from"node:os";import{join as ae}from"node:path";function ce(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 pe(){let r=process.env.TOOLNET_GLOBAL_ENV??ae(ie(),".config","toolnet-memory",".env");if(!se(r))return;let e=ne(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let
|
|
3
|
-
`,{encoding:"utf8",mode:384}),me(s,o)}function
|
|
4
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=H(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{existsSync as st,mkdirSync as nt,readFileSync as it,writeFileSync as at}from"node:fs";import{dirname as ct,join as X}from"node:path";import{createHash 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 pe(){let r=process.env.TOOLNET_GLOBAL_ENV??ae(ie(),".config","toolnet-memory",".env");if(!se(r))return;let e=ne(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let a=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=ce(o.slice(s+1)))}}pe();function v(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function h(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function N(){return{memory:{autoCapture:v(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:v(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:v(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:v(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:h(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:h(process.env.MEMORY_RERANK_TOP,10),finalContext:h(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:h(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:h(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ue}from"node:crypto";import{existsSync as T,mkdirSync as le,readFileSync as de,renameSync as me,writeFileSync as fe}from"node:fs";import{basename as ge,dirname as k,join as x,parse as W,resolve as y}from"node:path";var D=".toolnet",he="project.json";function ye(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function R(r){return x(r,D,he)}function Se(r){return T(R(r))}function je(r,e){let t=y(r),o=W(t).root;for(;;){if(Se(t))return t;if(t===o||e&&t===y(e))break;let s=k(t);if(s===t)break;t=s}return null}function ve(r){let e=y(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(a=>T(x(e,a))))return e;if(e===t)break;let s=k(e);if(s===e)break;e=s}return y(r)}function ke(r){let e;try{e=JSON.parse(de(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}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 o=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:k(k(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,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 $(r,e){let t=x(r,D);le(t,{recursive:!0});let o=R(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),me(s,o)}function _(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 w=class{detect(e=process.cwd()){let t=y(e),o=ve(t),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>T(x(o,m))),c=je(t,a?o:void 0);if(c){let m=R(c),n=ke(m);return n.rootPath!==c&&(n.rootPath=c,n.updatedAt=new Date().toISOString(),$(c,n)),_(n,c)}let u=new Date().toISOString(),i=ge(o),l={version:1,id:ye(o),name:i,remote:i,rootPath:o,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0};return $(o,l),_(l,o)}};import{homedir as We}from"node:os";import{join as De}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as xe,HeadObjectCommand as be,ListObjectsV2Command as Pe,PutObjectCommand as Ae,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var b=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Te({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ae({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Re(this.client,new xe({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new be({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new Pe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let a of s.Contents??[])a.Key&&t.push({key:a.Key,size:a.Size,updatedAt:a.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as B,mkdir as Me,readFile as Oe,readdir as Ee,rm as Ie,stat as L,writeFile as Ce}from"node:fs/promises";import{dirname as Ne,join as $e,relative as V,resolve as _e}from"node:path";var S=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _e(this.root,t)}async put(e,t){let o=this.path(e);await Me(Ne(o),{recursive:!0}),await Ce(o,t)}async get(e){try{return await Oe(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await B(this.path(e)),!0}catch{return!1}}async delete(e){await Ie(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await B(t)}catch{return o}let s=async c=>{let u=await Ee(c,{withFileTypes:!0});for(let i of u){let l=$e(c,i.name);if(i.isDirectory()){await s(l);continue}let m=await L(l);o.push({key:V(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},a=await L(t);return a.isDirectory()?await s(t):o.push({key:V(this.root,t),size:a.size,updatedAt:a.mtime.toISOString()}),o}};function K(r){let e=r.localRoot??De(We(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new b({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new S(e))}return new S(e)}function Be(r){return new Promise(e=>setTimeout(e,r))}async function J(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,a;for(let c=1;c<=t;c++)try{return await r()}catch(u){if(a=u,c>=t)break;let i=Math.min(s,o*2**(c-1)),l=Math.floor(Math.random()*Math.max(1,i*.2));await Be(i+l)}throw a}var Le=new Set(["put","get","getText","delete","list"]);function F(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:Le.has(o)?(...a)=>J(()=>Promise.resolve(s.apply(t,a)),e):s.bind(t)}})}function z(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 H(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var P=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=z(s??o),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),o=t,s=await this.provider.getText(e);if(s){let c;try{c=JSON.parse(s)}catch(u){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${u instanceof Error?u.message:String(u)}`)}if(typeof c.id=="string"&&c.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${c.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof c.createdAt=="string"&&(o=c.createdAt)}let a={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(a,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=H(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{existsSync as st,mkdirSync as nt,readFileSync as it,writeFileSync as at}from"node:fs";import{dirname as ct,join as X}from"node:path";import{createHash as Ve}from"node:crypto";import{dirname as Ke}from"node:path";import{mkdirSync as Je,readFileSync as ro,renameSync as Fe,writeFileSync as ze}from"node:fs";function g(r){return Ve("sha256").update(r).digest("hex")}function j(r,e){Je(Ke(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;ze(t,JSON.stringify(e,null,2)+`
|
|
5
5
|
`,{encoding:"utf8",mode:384}),Fe(t,r)}import{existsSync as Y,mkdirSync as He,readFileSync as Ue,statSync as U,writeFileSync as Ge}from"node:fs";import{dirname as Ye,join as Qe}from"node:path";var G=64*1024,qe=`# ToolNet Project Operating Manual
|
|
6
6
|
|
|
7
7
|
This file contains persistent instructions for AI agents working on this project.
|
|
@@ -45,12 +45,12 @@ Things an AI agent should always remember.
|
|
|
45
45
|
<!--
|
|
46
46
|
- [advisory] Prefer small focused files.
|
|
47
47
|
-->
|
|
48
|
-
`;function
|
|
49
|
-
`);if(
|
|
50
|
-
`)),
|
|
51
|
-
`).trim()}async function Z(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=
|
|
48
|
+
`;function A(r){return Qe(r.rootPath,".toolnet","PROJECT.md")}function Ze(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Xe(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let a=s[1].toLowerCase(),c=Ze(s[2]);if(!c)continue;let u=`${a}:${c.toLowerCase()}`;t.has(u)||(t.add(u),e.push({id:g(u).slice(0,24),mode:a,text:c,source:"manual"}))}return e}function et(r){let e=A(r);return Y(e)||(He(Ye(e),{recursive:!0}),Ge(e,qe,{encoding:"utf8",mode:384})),e}function M(r,e=!1){let t=e?et(r):A(r);if(!Y(t))return null;if(U(t).size>G)throw new Error(`PROJECT.md exceeds ${G} bytes`);let s=Ue(t,"utf8");return{path:t,content:s,digest:g(s),rules:Xe(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(U(t).mtimeMs).toISOString()}}async function O(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function Q(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function q(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function E(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function d(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function tt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let a=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||a.startsWith("- [enforce]")||a.startsWith("* [enforce]")||a.startsWith("- [advisory]")||a.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(d(s,280)),e.length>=16))break}return e}function rt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),a=s.toLowerCase(),u=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(l=>a.startsWith(l));if(!u)continue;let i=s.slice(u.length).trim();i&&(u.includes("enforce")?e.push(i):t.push(i))}return{enforce:e,advisory:t}}function ot(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
|
|
49
|
+
`);if(E(s)<=e){t.push(o);continue}let a=E(t.join(`
|
|
50
|
+
`)),c=Math.max(0,e-a);if(c>=16){let u=Math.floor(c*3.2),i=d(o,u);i&&t.push(i)}break}return t.join(`
|
|
51
|
+
`).trim()}async function Z(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=M(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=rt(o),a=t?t.rules.filter(p=>p.mode==="enforce").map(p=>p.text):s.enforce,c=t?t.rules.filter(p=>p.mode==="advisory").map(p=>p.text):s.advisory,u=o?tt(o):[],i=await O(r.project,r.storage),l=await q(r.project,r.storage),m=await Q(r.project,r.storage),n=[];if(n.push("[TOOLNET PROJECT CONTEXT]"),n.push(`Project: ${r.project.name}`),n.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&n.push(`Full operating manual: ${A(r.project)}`),a.length){n.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let p of a.slice(0,24))n.push(`- [ENFORCE] ${d(p,240)}`)}if(c.length){n.push("","PROJECT PREFERENCES");for(let p of c.slice(0,10))n.push(`- ${d(p,220)}`)}if(l&&(l.mission&&n.push("","MISSION",d(l.mission.value,420)),l.activeObjective&&n.push("","CURRENT OBJECTIVE",d(l.activeObjective.value,420)),l.why&&n.push("","WHY THIS WORK MATTERS",d(l.why.value,420)),l.desiredOutcome&&n.push("","DESIRED OUTCOME",d(l.desiredOutcome.value,420)),l.planRationale&&n.push("","WHY THIS APPROACH",d(l.planRationale.value,420))),i){if(n.push("","ACTIVE WORK"),i.goal&&n.push(`Goal: ${d(i.goal,320)}`),i.plan&&n.push(`Plan: ${d(i.plan,320)}`),n.push(`Progress: phases ${i.progress.phasesCompleted}/${i.progress.phasesTotal}; tasks ${i.progress.tasksCompleted}/${i.progress.tasksTotal}; blocked ${i.progress.blocked}`),i.currentPhase&&n.push(`Current phase: ${i.currentPhase.title} [${i.currentPhase.status}]`),i.currentPhase&&l){let p=l.phases.find(f=>f.order===i.currentPhase?.order);p&&(p.objective&&n.push(`Phase objective: ${d(p.objective.value,340)}`),p.why?n.push(`Why this phase: ${d(p.why.value,340)}`):n.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),p.deliverable&&n.push(`Deliverable: ${d(p.deliverable.value,340)}`),p.dependencies.length&&n.push(`Depends on: ${p.dependencies.slice(0,4).map(f=>d(f.value,180)).join("; ")}`),p.acceptanceCriteria.length&&(n.push("","DEFINITION OF DONE"),p.acceptanceCriteria.slice(0,6).forEach(f=>{n.push(`- ${d(f.value,260)}`)})),p.openQuestions.length&&(n.push("","OPEN QUESTIONS FOR CURRENT PHASE"),p.openQuestions.slice(0,4).forEach(f=>{n.push(`- ${d(f.value,260)}`)})))}i.currentTask&&n.push(`Current task: ${i.currentTask.title} [${i.currentTask.status}]`),i.nextActions.length&&(n.push("","NEXT ACTIONS"),i.nextActions.slice(0,6).forEach((p,f)=>{n.push(`${f+1}. ${d(p,260)}`)})),i.blockers.length&&(n.push("","BLOCKERS"),i.blockers.slice(0,5).forEach(p=>{n.push(`- ${d(p,260)}`)})),i.warnings.length&&(n.push("","ATTENTION"),i.warnings.slice(-5).forEach(p=>{n.push(`- ${d(p,260)}`)})),i.decisions.length&&(n.push("","RECENT DECISIONS"),i.decisions.slice(-5).forEach(p=>{n.push(`- ${d(p,260)}`)})),i.lastSession&&n.push("",`Last work session: ${i.lastSession.agent} / ${i.lastSession.nativeSessionId}`)}if(l&&l.openQuestions.length&&(n.push("","UNRESOLVED QUESTIONS"),l.openQuestions.slice(0,5).forEach(p=>{n.push(`- ${d(p.value,260)}`)})),m&&n.push(`Latest handoff: ${m.reason} / ${m.sourceSession.agent}`),u.length){n.push("","OPERATING NOTES");for(let p of u)n.push(`- ${p}`)}n.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let C=ot(n,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:C,estimatedTokens:E(C),maxTokens:e,hasManual:!!o,hasWorkState:!!i,hasHandoff:!!m,generatedAt:new Date().toISOString()}}function ee(r){return X(r.rootPath,".toolnet","context","startup.md")}function pt(r){return X(r.rootPath,".toolnet","context","startup.json")}function te(r,e){let t=ee(r);nt(ct(t),{recursive:!0}),at(t,e.text.endsWith(`
|
|
52
52
|
`)?e.text:e.text+`
|
|
53
|
-
`,{encoding:"utf8",mode:384}),
|
|
53
|
+
`,{encoding:"utf8",mode:384}),j(pt(r),e)}async function I(r,e,t=900){let o=await Z({project:r,storage:e,maxTokens:t}),s={version:1,projectId:r.id,projectName:r.name,text:o.text,digest:g(o.text),estimatedTokens:o.estimatedTokens,generatedAt:new Date().toISOString()};return te(r,s),await e.put(`projects/${r.id}/context/startup.md`,s.text+`
|
|
54
54
|
`,"text/markdown"),await e.put(`projects/${r.id}/context/startup.json`,JSON.stringify(s,null,2)+`
|
|
55
|
-
`,"application/json"),s}async function re(r,e,t=900){try{let s=await e.getText(`projects/${r.id}/context/startup.md`);if(s&&s.trim()){let
|
|
55
|
+
`,"application/json"),s}async function re(r,e,t=900){try{let s=await e.getText(`projects/${r.id}/context/startup.md`);if(s&&s.trim()){let a=s.trim(),c={version:1,projectId:r.id,projectName:r.name,text:a,digest:g(a),estimatedTokens:Math.ceil(a.length/3.5),generatedAt:new Date().toISOString()};return te(r,c),c}}catch{}let o=ee(r);if(st(o))try{let s=it(o,"utf8").trim();if(s)return{version:1,projectId:r.id,projectName:r.name,text:s,digest:g(s),estimatedTokens:Math.ceil(s.length/3.5),generatedAt:new Date().toISOString()}}catch{}try{return await I(r,e,t)}catch{return null}}function oe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function ft(r){let e=mt(r);for(;;){if(ut(dt(e,".toolnet","project.json")))return e;let t=lt(e);if(t===e)return null;e=t}}function gt(r){let e=N(),t=F(K({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:2});return new P(t,r.id,r.name,r.remote??r.name)}async function ht(){let[r="print",...e]=process.argv.slice(2),t=oe(e,"--project")??process.cwd(),o=ft(t);if(!o)return;let s=new w().detect(o),a=gt(s),c=Number(oe(e,"--tokens")??900);if(r==="refresh"){let i=await I(s,a,Number.isFinite(c)?c:900);console.log(i.text);return}let u=await re(s,a,Number.isFinite(c)?c:900);if(u){if(r==="sync"){console.log(u.digest);return}process.stdout.write(u.text+`
|
|
56
56
|
`)}}ht().catch(()=>{process.exitCode=0});
|
package/bundle/context.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{existsSync as je,readFileSync 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 be(){let r=process.env.TOOLNET_GLOBAL_ENV??we(
|
|
3
|
-
`,{encoding:"utf8",mode:384}),Re(s,o)}function
|
|
4
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ae(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{join as at}from"node:path";import{createHash as rt}from"node:crypto";import{dirname as ot}from"node:path";import{mkdirSync as st,readFileSync as go,renameSync as nt,writeFileSync as it}from"node:fs";function y(r){return rt("sha256").update(r).digest("hex")}function
|
|
1
|
+
import{existsSync as je,readFileSync as ke}from"node:fs";import{homedir as ve}from"node:os";import{join as we}from"node:path";function xe(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 be(){let r=process.env.TOOLNET_GLOBAL_ENV??we(ve(),".config","toolnet-memory",".env");if(!je(r))return;let e=ke(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let n=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=xe(o.slice(s+1)))}}be();function R(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function x(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function Y(){return{memory:{autoCapture:R(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:R(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:R(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:R(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:x(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:x(process.env.MEMORY_RERANK_TOP,10),finalContext:x(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:x(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:x(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Pe}from"node:crypto";import{existsSync as K,mkdirSync as Ae,readFileSync as Te,renameSync as Re,writeFileSync as Me}from"node:fs";import{basename as Oe,dirname as M,join as E,parse as Z,resolve as b}from"node:path";var X=".toolnet",Ee="project.json";function Ie(r){return Pe("sha256").update(r).digest("hex").slice(0,16)}function J(r){return E(r,X,Ee)}function Ce(r){return K(J(r))}function Ne(r,e){let t=b(r),o=Z(t).root;for(;;){if(Ce(t))return t;if(t===o||e&&t===b(e))break;let s=M(t);if(s===t)break;t=s}return null}function $e(r){let e=b(r),t=Z(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(n=>K(E(e,n))))return e;if(e===t)break;let s=M(e);if(s===e)break;e=s}return b(r)}function _e(r){let e;try{e=JSON.parse(Te(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}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 o=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:M(M(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,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 Q(r,e){let t=E(r,X);Ae(t,{recursive:!0});let o=J(r),s=`${o}.tmp-${process.pid}`;Me(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),Re(s,o)}function q(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 O=class{detect(e=process.cwd()){let t=b(e),o=$e(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>K(E(o,f))),p=Ne(t,n?o:void 0);if(p){let f=J(p),a=_e(f);return a.rootPath!==p&&(a.rootPath=p,a.updatedAt=new Date().toISOString(),Q(p,a)),q(a,p)}let l=new Date().toISOString(),c=Oe(o),d={version:1,id:Ie(o),name:c,remote:c,rootPath:o,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return Q(o,d),q(d,o)}};import{homedir as Ze}from"node:os";import{join as Xe}from"node:path";import{DeleteObjectCommand as We,GetObjectCommand as De,HeadObjectCommand as Le,ListObjectsV2Command as Ve,PutObjectCommand as Ke,S3Client as Je}from"@aws-sdk/client-s3";import{getSignedUrl as ze}from"@aws-sdk/s3-request-presigner";var I=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Je({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ke({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await ze(this.client,new De({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Le({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new We({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new Ve({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as ee,mkdir as Be,readFile as Fe,readdir as He,rm as Ue,stat as te,writeFile as Ge}from"node:fs/promises";import{dirname as Ye,join as Qe,relative as re,resolve as qe}from"node:path";var P=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return qe(this.root,t)}async put(e,t){let o=this.path(e);await Be(Ye(o),{recursive:!0}),await Ge(o,t)}async get(e){try{return await Fe(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 ee(this.path(e)),!0}catch{return!1}}async delete(e){await Ue(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ee(t)}catch{return o}let s=async p=>{let l=await He(p,{withFileTypes:!0});for(let c of l){let d=Qe(p,c.name);if(c.isDirectory()){await s(d);continue}let f=await te(d);o.push({key:re(this.root,d),size:f.size,updatedAt:f.mtime.toISOString()})}},n=await te(t);return n.isDirectory()?await s(t):o.push({key:re(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),o}};function oe(r){let e=r.localRoot??Xe(Ze(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new I({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new P(e))}return new P(e)}function et(r){return new Promise(e=>setTimeout(e,r))}async function se(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let p=1;p<=t;p++)try{return await r()}catch(l){if(n=l,p>=t)break;let c=Math.min(s,o*2**(p-1)),d=Math.floor(Math.random()*Math.max(1,c*.2));await et(c+d)}throw n}var tt=new Set(["put","get","getText","delete","list"]);function ne(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:tt.has(o)?(...n)=>se(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}function ie(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 ae(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var C=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=ie(s??o),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),o=t,s=await this.provider.getText(e);if(s){let p;try{p=JSON.parse(s)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}if(typeof p.id=="string"&&p.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${p.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof p.createdAt=="string"&&(o=p.createdAt)}let n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(n,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ae(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{join as at}from"node:path";import{createHash as rt}from"node:crypto";import{dirname as ot}from"node:path";import{mkdirSync as st,readFileSync as go,renameSync as nt,writeFileSync as it}from"node:fs";function y(r){return rt("sha256").update(r).digest("hex")}function v(r,e){st(ot(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;it(t,JSON.stringify(e,null,2)+`
|
|
5
5
|
`,{encoding:"utf8",mode:384}),nt(t,r)}function ce(r,e){let t=r.trim(),o=t.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=y(t).slice(0,12);if(!o||o==="."||o==="..")return`${e}--${s}`;let n=o.slice(0,100);return n===t&&t.length<=100?n:`${n.slice(0,85)}--${s}`}function pe(r,e,t){let o=e.trim(),s=t.trim();if(!o)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let n=ce(o.toLowerCase(),"agent"),p=ce(s,"session");return{projectId:r.id,projectName:r.name,projectRoot:r.rootPath,agent:o,nativeSessionId:s,sessionKey:`${o}:${s}`,remotePrefix:["projects",r.id,"sessions",n,p].join("/"),localDirectory:at(r.rootPath,".toolnet","sessions",n,p)}}import{existsSync as de,mkdirSync as ct,readFileSync as pt,statSync as ue,writeFileSync as ut}from"node:fs";import{dirname as lt,join as dt}from"node:path";var le=64*1024,mt=`# ToolNet Project Operating Manual
|
|
6
6
|
|
|
7
7
|
This file contains persistent instructions for AI agents working on this project.
|
|
@@ -45,14 +45,14 @@ Things an AI agent should always remember.
|
|
|
45
45
|
<!--
|
|
46
46
|
- [advisory] Prefer small focused files.
|
|
47
47
|
-->
|
|
48
|
-
`;function
|
|
49
|
-
`,"application/json"),
|
|
50
|
-
`,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(
|
|
51
|
-
`,"application/json");let
|
|
52
|
-
`);if(
|
|
53
|
-
`)),p=Math.max(0,e-n);if(p>=16){let
|
|
54
|
-
`).trim()}async function
|
|
55
|
-
`);return}if(r==="brief-json"){let s=await
|
|
48
|
+
`;function N(r){return dt(r.rootPath,".toolnet","PROJECT.md")}function ft(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function gt(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let n=s[1].toLowerCase(),p=ft(s[2]);if(!p)continue;let l=`${n}:${p.toLowerCase()}`;t.has(l)||(t.add(l),e.push({id:y(l).slice(0,24),mode:n,text:p,source:"manual"}))}return e}function ht(r){let e=N(r);return de(e)||(ct(lt(e),{recursive:!0}),ut(e,mt,{encoding:"utf8",mode:384})),e}function $(r,e=!1){let t=e?ht(r):N(r);if(!de(t))return null;if(ue(t).size>le)throw new Error(`PROJECT.md exceeds ${le} bytes`);let s=pt(t,"utf8");return{path:t,content:s,digest:y(s),rules:gt(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(ue(t).mtimeMs).toISOString()}}import{mkdirSync as vt}from"node:fs";import{join as z}from"node:path";import{join as me}from"node:path";import{mkdirSync as yt}from"node:fs";function St(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function w(r,e=20){let t=[],o=new Set;for(let s of r.slice().reverse()){let n=St(s);if(!(!n||o.has(n))&&(o.add(n),t.push(s),t.length>=e))break}return t.reverse()}function jt(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function fe(r,e){let t=e.status??r?.status??"pending",o=t;r&&(r.status==="completed"&&t!=="completed"?o="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(o=r.status));let s=r&&jt(e)?r.title:e.text;return{id:r?.id??y(e.key).slice(0,24),title:s,status:o,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function kt(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let n of o.filter(p=>p.key.endsWith(".json")).sort((p,l)=>p.key.localeCompare(l.key))){let p=await e.getText(n.key);if(p)try{let l=JSON.parse(p);l.version===1&&Array.isArray(l.observations)&&s.push(l)}catch{}}return s}async function ge(r,e){let o=(await kt(r,e)).flatMap(i=>i.observations).sort((i,k)=>{let U=i.occurredAt.localeCompare(k.occurredAt);if(U!==0)return U;let G=i.sequence-k.sequence;return G!==0?G:i.id.localeCompare(k.id)}),s=new Map,n=new Map,p,l,c,d=[],f=[],a=[],g=[],u=[],h=[];for(let i of o)switch(i.kind){case"goal":p=i.text;break;case"plan":l=i.text;break;case"phase":s.set(i.key,fe(s.get(i.key),i));break;case"task":n.set(i.key,fe(n.get(i.key),i));break;case"decision":d.push(i.text);break;case"blocker":f.push(i.text);break;case"warning":a.push(i.text);break;case"next_action":g.push(i.text);break;case"file":u.push(i.text);break;case"test":h.push(i.text);break;case"session":c={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let j=Array.from(s.values()).sort((i,k)=>(i.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),S=Array.from(n.values()).sort((i,k)=>(i.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),L=j.find(i=>i.status==="in_progress")??j.find(i=>i.status==="blocked")??j.find(i=>i.status==="pending"),T=S.find(i=>i.status==="in_progress")??S.find(i=>i.status==="blocked")??S.find(i=>i.status==="pending"),ye=w([...g,...T?[T.title]:[],...!T&&L?[L.title]:[],...S.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Se=w([...f,...j.filter(i=>i.status==="blocked").map(i=>i.title),...S.filter(i=>i.status==="blocked").map(i=>i.title)],20),V={version:1,projectId:r.id,projectName:r.name,goal:p,plan:l,phases:j,tasks:S,decisions:w(d,20),blockers:Se,warnings:w(a,20),nextActions:ye,filesTouched:w(u,30),tests:w(h,20),currentPhase:L,currentTask:T,progress:{phasesTotal:j.length,phasesCompleted:j.filter(i=>i.status==="completed").length,tasksTotal:S.length,tasksCompleted:S.filter(i=>i.status==="completed").length,blocked:j.filter(i=>i.status==="blocked").length+S.filter(i=>i.status==="blocked").length},lastSession:c,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},H=me(r.rootPath,".toolnet","work");return yt(H,{recursive:!0}),v(me(H,"current.json"),V),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(V,null,2)+`
|
|
49
|
+
`,"application/json"),V}async function _(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function wt(r){return{goal:r.goal,plan:r.plan,phases:r.phases.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),tasks:r.tasks.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),decisions:r.decisions,blockers:r.blockers,warnings:r.warnings,nextActions:r.nextActions,filesTouched:r.filesTouched,tests:r.tests}}function xt(r){return r.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.nextActions.length>0||r.blockers.length>0}var W=class{constructor(e){this.options=e}options;async capture(e,t){let o=await _(this.options.project,this.options.storage);if(o||(o=await ge(this.options.project,this.options.storage)),!xt(o))return null;let s=$(this.options.project,!1),n=s?s.rules.filter(g=>g.mode==="enforce").map(g=>g.text):[],p=y(JSON.stringify(wt(o))),l=y([this.options.project.id,this.options.identity.sessionKey,p].join("|")).slice(0,24),c=new Date().toISOString(),d={version:1,id:l,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:c,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:t},goal:o.goal,plan:o.plan,progress:o.progress,currentPhase:o.currentPhase,currentTask:o.currentTask,incompletePhases:o.phases.filter(g=>g.status!=="completed"&&g.status!=="cancelled"),incompleteTasks:o.tasks.filter(g=>g.status!=="completed"&&g.status!=="cancelled"),nextActions:o.nextActions.slice(0,10),blockers:o.blockers.slice(0,10),decisions:o.decisions.slice(-10),warnings:o.warnings.slice(-10),attention:[...n,...o.warnings].slice(0,20),filesTouched:o.filesTouched.slice(-20),tests:o.tests.slice(-15),stateDigest:p},f=`projects/${this.options.project.id}/work/handoffs/${l}.json`;await this.options.storage.exists(f)||await this.options.storage.put(f,JSON.stringify(d,null,2)+`
|
|
50
|
+
`,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(d,null,2)+`
|
|
51
|
+
`,"application/json");let a=z(this.options.project.rootPath,".toolnet","work","handoffs");return vt(a,{recursive:!0}),v(z(a,`${l}.json`),d),v(z(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),d),d}};async function D(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function he(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function B(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function m(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function bt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let n=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||n.startsWith("- [enforce]")||n.startsWith("* [enforce]")||n.startsWith("- [advisory]")||n.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(m(s,280)),e.length>=16))break}return e}function Pt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),n=s.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(d=>n.startsWith(d));if(!l)continue;let c=s.slice(l.length).trim();c&&(l.includes("enforce")?e.push(c):t.push(c))}return{enforce:e,advisory:t}}function At(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
|
|
52
|
+
`);if(B(s)<=e){t.push(o);continue}let n=B(t.join(`
|
|
53
|
+
`)),p=Math.max(0,e-n);if(p>=16){let l=Math.floor(p*3.2),c=m(o,l);c&&t.push(c)}break}return t.join(`
|
|
54
|
+
`).trim()}async function F(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=$(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=Pt(o),n=t?t.rules.filter(u=>u.mode==="enforce").map(u=>u.text):s.enforce,p=t?t.rules.filter(u=>u.mode==="advisory").map(u=>u.text):s.advisory,l=o?bt(o):[],c=await _(r.project,r.storage),d=await he(r.project,r.storage),f=await D(r.project,r.storage),a=[];if(a.push("[TOOLNET PROJECT CONTEXT]"),a.push(`Project: ${r.project.name}`),a.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&a.push(`Full operating manual: ${N(r.project)}`),n.length){a.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let u of n.slice(0,24))a.push(`- [ENFORCE] ${m(u,240)}`)}if(p.length){a.push("","PROJECT PREFERENCES");for(let u of p.slice(0,10))a.push(`- ${m(u,220)}`)}if(d&&(d.mission&&a.push("","MISSION",m(d.mission.value,420)),d.activeObjective&&a.push("","CURRENT OBJECTIVE",m(d.activeObjective.value,420)),d.why&&a.push("","WHY THIS WORK MATTERS",m(d.why.value,420)),d.desiredOutcome&&a.push("","DESIRED OUTCOME",m(d.desiredOutcome.value,420)),d.planRationale&&a.push("","WHY THIS APPROACH",m(d.planRationale.value,420))),c){if(a.push("","ACTIVE WORK"),c.goal&&a.push(`Goal: ${m(c.goal,320)}`),c.plan&&a.push(`Plan: ${m(c.plan,320)}`),a.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&a.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&d){let u=d.phases.find(h=>h.order===c.currentPhase?.order);u&&(u.objective&&a.push(`Phase objective: ${m(u.objective.value,340)}`),u.why?a.push(`Why this phase: ${m(u.why.value,340)}`):a.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),u.deliverable&&a.push(`Deliverable: ${m(u.deliverable.value,340)}`),u.dependencies.length&&a.push(`Depends on: ${u.dependencies.slice(0,4).map(h=>m(h.value,180)).join("; ")}`),u.acceptanceCriteria.length&&(a.push("","DEFINITION OF DONE"),u.acceptanceCriteria.slice(0,6).forEach(h=>{a.push(`- ${m(h.value,260)}`)})),u.openQuestions.length&&(a.push("","OPEN QUESTIONS FOR CURRENT PHASE"),u.openQuestions.slice(0,4).forEach(h=>{a.push(`- ${m(h.value,260)}`)})))}c.currentTask&&a.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(a.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((u,h)=>{a.push(`${h+1}. ${m(u,260)}`)})),c.blockers.length&&(a.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(u=>{a.push(`- ${m(u,260)}`)})),c.warnings.length&&(a.push("","ATTENTION"),c.warnings.slice(-5).forEach(u=>{a.push(`- ${m(u,260)}`)})),c.decisions.length&&(a.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(u=>{a.push(`- ${m(u,260)}`)})),c.lastSession&&a.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(d&&d.openQuestions.length&&(a.push("","UNRESOLVED QUESTIONS"),d.openQuestions.slice(0,5).forEach(u=>{a.push(`- ${m(u.value,260)}`)})),f&&a.push(`Latest handoff: ${f.reason} / ${f.sourceSession.agent}`),l.length){a.push("","OPERATING NOTES");for(let u of l)a.push(`- ${u}`)}a.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let g=At(a,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:g,estimatedTokens:B(g),maxTokens:e,hasManual:!!o,hasWorkState:!!c,hasHandoff:!!f,generatedAt:new Date().toISOString()}}function A(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Tt(r){let e=Y(),t=ne(oe({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new C(t,r.id,r.name,r.remote??r.name)}async function Rt(){let[r="help",...e]=process.argv.slice(2),t=new O().detect(A(e,"--project")??process.cwd()),o=Tt(t);if(r==="brief"){let s=Number(A(e,"--tokens")??1e3),n=await F({project:t,storage:o,maxTokens:Number.isFinite(s)?s:1e3});process.stdout.write(n.text+`
|
|
55
|
+
`);return}if(r==="brief-json"){let s=await F({project:t,storage:o,maxTokens:Number(A(e,"--tokens")??1e3)});console.log(JSON.stringify(s,null,2));return}if(r==="handoff-latest"){let s=await D(t,o);console.log(JSON.stringify(s,null,2));return}if(r==="handoff-create"){let s=A(e,"--agent")??"manual";if(s==="manual")throw new Error("--agent must be opencode, agy, or codex");let n=A(e,"--session");if(!n)throw new Error("--session is required");let p=pe(t,s,n),c=await new W({project:t,storage:o,identity:p}).capture("manual",0);console.log(JSON.stringify(c,null,2));return}console.log(`Work Context
|
|
56
56
|
|
|
57
57
|
Commands:
|
|
58
58
|
brief [--project PATH] [--tokens N]
|
package/bundle/doctor.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
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}),te(s,r)}function I(o,e){return{id:o.id,name:o.name,remote:o.remote,rootPath:e,createdAt:o.createdAt,updatedAt:o.updatedAt,graphVersion:o.graphVersion,memoryVersion:o.memoryVersion,metadata:o.metadata}}var h=class{detect(e=process.cwd()){let t=f(e),r=ae(t);if(r){let p=M(r),c=pe(p);return c.rootPath!==r&&(c.rootPath=r,c.updatedAt=new Date().toISOString(),_(r,c)),I(c,r)}let s=ce(t),n=new Date().toISOString(),i=oe(s),a={version:1,id:ne(s),name:i,remote:i,rootPath:s,createdAt:n,updatedAt:n,graphVersion:0,memoryVersion:0};return _(s,a),I(a,s)}};import{homedir as ke}from"node:os";import{join as Ee}from"node:path";import{DeleteObjectCommand as me,GetObjectCommand as de,HeadObjectCommand as ge,ListObjectsV2Command as ue,PutObjectCommand as le,S3Client as fe}from"@aws-sdk/client-s3";import{getSignedUrl as he}from"@aws-sdk/s3-request-presigner";var y=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new fe({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,r="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new le({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await he(this.client,new de({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(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 ge({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new me({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new ue({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};import{access as z,mkdir as ye,readFile as ve,readdir as we,rm as je,stat as V,writeFile as Se}from"node:fs/promises";import{dirname as be,join as xe,relative as K,resolve as Pe}from"node:path";var g=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Pe(this.root,t)}async put(e,t){let r=this.path(e);await ye(be(r),{recursive:!0}),await Se(r,t)}async get(e){try{return await ve(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await z(this.path(e)),!0}catch{return!1}}async delete(e){await je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await z(t)}catch{return r}let s=async i=>{let a=await we(i,{withFileTypes:!0});for(let p of a){let c=xe(i,p.name);if(p.isDirectory()){await s(c);continue}let m=await V(c);r.push({key:K(this.root,c),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await V(t);return n.isDirectory()?await s(t):r.push({key:K(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function L(o){let e=o.localRoot??Ee(ke(),".toolnet-memory","storage");if(o.provider==="huggingface"){let t=o.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new y({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new g(e))}return new g(e)}var v=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 r=JSON.parse(t);if(!Array.isArray(r))throw new Error("Invalid memory snapshot");return r}async save(e,t){let r=JSON.stringify(t,null,2);await this.storage.put(this.key(e),r,"application/json")}};var w=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let r=JSON.parse(t);if(r.version!==1||r.projectId!==e||!Array.isArray(r.records))throw new Error("Invalid vector snapshot");return r}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var j=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var S=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var b=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function Ae(o){return new Promise(e=>setTimeout(e,o))}async function F(o,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let i=1;i<=t;i++)try{return await o()}catch(a){if(n=a,i>=t)break;let p=Math.min(s,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,p*.2));await Ae(p+c)}throw n}var Re=new Set(["put","get","getText","delete","list"]);function B(o,e={}){return new Proxy(o,{get(t,r){let s=Reflect.get(t,r,t);return typeof s!="function"?s:Re.has(r)?(...n)=>F(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}var x=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,r=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!r.ok)throw new Error(`HF embedding failed: ${r.status} ${await r.text()}`);let s=await r.json();if(!Array.isArray(s))throw new Error("HF embedding returned invalid response");return s.map(n=>Me(n))}};function Me(o){if(!Array.isArray(o))throw new Error("Invalid embedding");if(o.length>0&&typeof o[0]=="number")return o;if(o.length>0&&Array.isArray(o[0])){let e=o;if(e.length===0)return[];let t=e[0].length,r=new Array(t).fill(0);for(let s of e)for(let n=0;n<t;n++)r[n]+=s[n]??0;for(let s=0;s<t;s++)r[s]/=e.length;return r}throw new Error("Unsupported embedding shape")}import{createHash as Te}from"node:crypto";var P=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),r=e.toLowerCase().split(/\s+/).filter(Boolean);for(let s of r){let i=Te("sha256").update(s).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return Ce(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function Ce(o){let e=Math.sqrt(o.reduce((t,r)=>t+r*r,0));return e===0?o:o.map(t=>t/e)}var T=class{constructor(e,t=new P){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function H(){let o=process.env.HF_TOKEN,e=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",t=o?new x({token:o,model:e}):null;return new T(t)}var Oe=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],k=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",r){let s=new Date().toISOString(),n=s.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,n),p=[];for(let m of Oe){let A=`${i}/${m}`,C=await this.storage.get(A);C&&(await this.storage.put(`${a}/${m}`,C,"application/json"),p.push(m))}if(p.length===0)return null;let c={version:1,id:n,projectId:e,createdAt:s,reason:t,objects:p,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(c,null,2),"application/json"),c}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),s=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),n=[];for(let i of s){let a=await this.storage.getText(i.key);if(a)try{n.push(JSON.parse(a))}catch{}}return n.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let r=this.snapshotPrefix(e,t),s=await this.storage.getText(`${r}/snapshot.json`);if(!s)throw new Error(`Snapshot not found: ${t}`);let n=JSON.parse(s);if(n.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let p of n.objects){let c=await this.storage.get(`${r}/${p}`);c&&(await this.storage.put(`${i}/${p}`,c,"application/json"),a.push(p))}return{restored:a}}async remove(e,t){let r=this.snapshotPrefix(e,t),s=await this.storage.list(r);for(let n of s)await this.storage.delete(n.key);return s.length}async prune(e,t=10){let s=(await this.list(e)).slice(t),n=0;for(let i of s)await this.remove(e,i.id),n++;return n}};function J(){let o=[],e=[];if((process.env.MEMORY_STORAGE_PROVIDER??"local")==="huggingface"){let s=["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"];for(let n of s)process.env[n]||o.push(`Missing ${n}`);process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback")}return process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:o.length===0,errors:o,warnings:e}}import{randomUUID as _e}from"node:crypto";var E=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${_e()}.txt`,t=`toolnet-memory:${Date.now()}`,r=!1;try{await this.storage.put(e,t,"text/plain"),r=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let s=null;if(this.embeddings)try{let n=await this.embeddings.embed("ToolNet Memory production health check");s={ok:n.length>0,dimensions:n.length,mode:n.length===384?"huggingface":"fallback-or-custom"}}catch{s={ok:!1,dimensions:0,mode:"failed"}}return{ok:r&&(s===null||s.ok),storage:{ok:r,provider:this.storage.name},embedding:s}}};async function Ie(){let o=J();o.ok||(console.log({ok:!1,config:o}),process.exit(1));let e=O(),t=new h().detect(),r=B(L({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),s=H(),n=await new E(r,s).run(),i=await new v(r).load(t.id),a=await new j(r).load(t.id),p=await new w(r).load(t.id),c=await new S(r).load(t.id),m=await new b(r).load(t.id),A=await new k(r).list(t.id);console.log({ok:n.ok,project:t.name,storage:n.storage,embedding:n.embedding,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:c?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:A.length,warnings:o.warnings}),n.ok||process.exit(1)}Ie().catch(o=>{console.error(o instanceof Error?o.message:o),process.exit(1)});
|
|
1
|
+
import"dotenv/config";import{existsSync as W,readFileSync as Z}from"node:fs";import{homedir as Q}from"node:os";import{join as q}from"node:path";function X(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 ee(){let r=process.env.TOOLNET_GLOBAL_ENV??q(Q(),".config","toolnet-memory",".env");if(!W(r))return;let e=Z(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let s=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=X(o.slice(n+1)))}}ee();function h(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function l(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function _(){return{memory:{autoCapture:h(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:h(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:h(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:h(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:l(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:l(process.env.MEMORY_RERANK_TOP,10),finalContext:l(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:l(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:l(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as te}from"node:crypto";import{existsSync as C,mkdirSync as re,readFileSync as oe,renameSync as ne,writeFileSync as se}from"node:fs";import{basename as ie,dirname as y,join as w,parse as N,resolve as u}from"node:path";var D=".toolnet",ae="project.json";function ce(r){return te("sha256").update(r).digest("hex").slice(0,16)}function T(r){return w(r,D,ae)}function pe(r){return C(T(r))}function de(r,e){let t=u(r),o=N(t).root;for(;;){if(pe(t))return t;if(t===o||e&&t===u(e))break;let n=y(t);if(n===t)break;t=n}return null}function me(r){let e=u(r),t=N(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(s=>C(w(e,s))))return e;if(e===t)break;let n=y(e);if(n===e)break;e=n}return u(r)}function ge(r){let e;try{e=JSON.parse(oe(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}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 o=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:y(y(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,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 $(r,e){let t=w(r,D);re(t,{recursive:!0});let o=T(r),n=`${o}.tmp-${process.pid}`;se(n,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),ne(n,o)}function I(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 v=class{detect(e=process.cwd()){let t=u(e),o=me(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>C(w(o,d))),i=de(t,s?o:void 0);if(i){let d=T(i),m=ge(d);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),$(i,m)),I(m,i)}let a=new Date().toISOString(),c=ie(o),p={version:1,id:ce(o),name:c,remote:c,rootPath:o,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return $(o,p),I(p,o)}};import{homedir as Me}from"node:os";import{join as Ae}from"node:path";import{DeleteObjectCommand as le,GetObjectCommand as ue,HeadObjectCommand as fe,ListObjectsV2Command as he,PutObjectCommand as ye,S3Client as ve}from"@aws-sdk/client-s3";import{getSignedUrl as we}from"@aws-sdk/s3-request-presigner";var j=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ve({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ye({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await we(this.client,new ue({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new fe({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 le({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new he({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as V,mkdir as je,readFile as Se,readdir as be,rm as xe,stat as z,writeFile as Pe}from"node:fs/promises";import{dirname as ke,join as Ee,relative as K,resolve as Re}from"node:path";var f=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Re(this.root,t)}async put(e,t){let o=this.path(e);await je(ke(o),{recursive:!0}),await Pe(o,t)}async get(e){try{return await Se(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 V(this.path(e)),!0}catch{return!1}}async delete(e){await xe(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await V(t)}catch{return o}let n=async i=>{let a=await be(i,{withFileTypes:!0});for(let c of a){let p=Ee(i,c.name);if(c.isDirectory()){await n(p);continue}let d=await z(p);o.push({key:K(this.root,p),size:d.size,updatedAt:d.mtime.toISOString()})}},s=await z(t);return s.isDirectory()?await n(t):o.push({key:K(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),o}};function L(r){let e=r.localRoot??Ae(Me(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new j({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new f(e))}return new f(e)}var S=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};var b=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let o=JSON.parse(t);if(o.version!==1||o.projectId!==e||!Array.isArray(o.records))throw new Error("Invalid vector snapshot");return o}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var x=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var P=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var k=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function Ce(r){return new Promise(e=>setTimeout(e,r))}async function F(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await r()}catch(a){if(s=a,i>=t)break;let c=Math.min(n,o*2**(i-1)),p=Math.floor(Math.random()*Math.max(1,c*.2));await Ce(c+p)}throw s}var Te=new Set(["put","get","getText","delete","list"]);function B(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:Te.has(o)?(...s)=>F(()=>Promise.resolve(n.apply(t,s)),e):n.bind(t)}})}var E=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,o=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!o.ok)throw new Error(`HF embedding failed: ${o.status} ${await o.text()}`);let n=await o.json();if(!Array.isArray(n))throw new Error("HF embedding returned invalid response");return n.map(s=>Oe(s))}};function Oe(r){if(!Array.isArray(r))throw new Error("Invalid embedding");if(r.length>0&&typeof r[0]=="number")return r;if(r.length>0&&Array.isArray(r[0])){let e=r;if(e.length===0)return[];let t=e[0].length,o=new Array(t).fill(0);for(let n of e)for(let s=0;s<t;s++)o[s]+=n[s]??0;for(let n=0;n<t;n++)o[n]/=e.length;return o}throw new Error("Unsupported embedding shape")}import{createHash as _e}from"node:crypto";var R=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),o=e.toLowerCase().split(/\s+/).filter(Boolean);for(let n of o){let i=_e("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return $e(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function $e(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var O=class{constructor(e,t=new R){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function J(){let r=process.env.HF_TOKEN,e=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",t=r?new E({token:r,model:e}):null;return new O(t)}var Ie=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],M=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),s=n.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,s),c=[];for(let d of Ie){let m=`${i}/${d}`,g=await this.storage.get(m);g&&(await this.storage.put(`${a}/${d}`,g,"application/json"),c.push(d))}if(c.length===0)return null;let p={version:1,id:s,projectId:e,createdAt:n,reason:t,objects:c,metadata:o};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(p,null,2),"application/json"),p}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),s=[];for(let i of n){let a=await this.storage.getText(i.key);if(a)try{s.push(JSON.parse(a))}catch{}}return s.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let s=JSON.parse(n);if(s.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of s.objects){let p=await this.storage.get(`${o}/${c}`);p&&(await this.storage.put(`${i}/${c}`,p,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let s of n)await this.storage.delete(s.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),s=0;for(let i of n)await this.remove(e,i.id),s++;return s}};function H(){let r=[],e=[];if((process.env.MEMORY_STORAGE_PROVIDER??"local")==="huggingface"){let n=["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"];for(let s of n)process.env[s]||r.push(`Missing ${s}`);process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback")}return process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Ne}from"node:crypto";var A=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${Ne()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let n=null;if(this.embeddings)try{let s=await this.embeddings.embed("ToolNet Memory production health check");n={ok:s.length>0,dimensions:s.length,mode:s.length===384?"huggingface":"fallback-or-custom"}}catch{n={ok:!1,dimensions:0,mode:"failed"}}return{ok:o&&(n===null||n.ok),storage:{ok:o,provider:this.storage.name},embedding:n}}};function G(){return process.argv.includes("--json")}function De(r){if(console.log(""),console.log("ToolNet Memory Doctor"),console.log("====================="),console.log(""),r.project&&(console.log(`Project: ${r.project}`),console.log("")),r.storage)if(r.storage.ok){let n=typeof r.storage.provider=="string"?` (${r.storage.provider})`:"";console.log(`\u2713 Storage${n}`)}else console.log("\u2717 Storage");if(r.embedding)if(r.embedding.ok){let n=[];typeof r.embedding.mode=="string"&&n.push(r.embedding.mode),typeof r.embedding.dimensions=="number"&&n.push(`${r.embedding.dimensions} dimensions`),console.log(`\u2713 Embedding${n.length?` (${n.join(", ")})`:""}`)}else console.log("\u2717 Embedding");(r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(""),console.log("Project data:"),r.memory!==void 0&&console.log(` Memories ${r.memory}`),r.graphSymbols!==void 0&&console.log(` Graph symbols ${r.graphSymbols}`),r.graphEdges!==void 0&&console.log(` Graph edges ${r.graphEdges}`),r.memoryVectors!==void 0&&console.log(` Memory vectors ${r.memoryVectors}`),r.codeChunks!==void 0&&console.log(` Code chunks ${r.codeChunks}`),r.codeVectors!==void 0&&console.log(` Code vectors ${r.codeVectors}`),r.snapshots!==void 0&&console.log(` Snapshots ${r.snapshots}`));let e=r.config?.errors??[];if(e.length>0){console.log(""),console.log("Configuration required:");for(let n of e)console.log(` - ${n}`)}let t=[...r.config?.warnings??[],...r.warnings??[]],o=[...new Set(t)];if(o.length>0){console.log(""),console.log("Warnings:");for(let n of o)console.log(` - ${n}`)}console.log(""),r.ok?console.log("\u2713 ToolNet Memory is ready"):(console.log("\u2717 ToolNet Memory requires attention"),e.length>0&&(console.log(""),console.log("Run:"),console.log(" toolnet-memory setup"))),console.log("")}function U(r){G()?console.log(JSON.stringify(r,null,2)):De(r)}async function Ve(){let r=H();if(!r.ok){let Y={ok:!1,config:r,warnings:r.warnings};U(Y),process.exitCode=1;return}let e=_(),t=new v().detect(),o=B(L({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=J(),s=await new A(o,n).run(),i=await new S(o).load(t.id),a=await new x(o).load(t.id),c=await new b(o).load(t.id),p=await new P(o).load(t.id),d=await new k(o).load(t.id),m=await new M(o).list(t.id),g={ok:s.ok,project:t.name,storage:s.storage,embedding:s.embedding,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:c?.records.length??0,codeChunks:p?.chunks.length??0,codeVectors:d?.records.length??0,snapshots:m.length,warnings:r.warnings};U(g),process.exitCode=g.ok?0:1}Ve().catch(r=>{let e=r instanceof Error?r.message:String(r);G()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
|