toolnet-memory 0.3.15 → 0.3.16
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/.release-target +1 -1
- package/README.md +158 -6
- package/bundle/agy-hook.js +66 -66
- package/bundle/agy.js +59 -59
- package/bundle/api.js +15 -15
- package/bundle/background-refresh.js +7 -7
- package/bundle/claude-hook.js +49 -49
- package/bundle/codex-context.js +29 -29
- package/bundle/codex.js +71 -71
- package/bundle/context-runtime.js +44 -44
- package/bundle/context.js +14 -14
- package/bundle/copilot-hook.js +77 -77
- package/bundle/cursor-hook.js +78 -78
- package/bundle/doctor.js +4 -4
- package/bundle/full-index.js +19 -19
- package/bundle/graph-index.js +4 -4
- package/bundle/graph-ui.js +3 -3
- package/bundle/grok-hook.js +55 -55
- package/bundle/handoff-refresh.js +10 -10
- package/bundle/help-cli.js +3 -3
- package/bundle/impact.js +4 -4
- package/bundle/incremental.js +5 -5
- package/bundle/init.js +36 -35
- package/bundle/kiro-hook.js +86 -86
- package/bundle/learner.js +6 -6
- package/bundle/mcp.js +17 -17
- package/bundle/memory-agent.js +6 -6
- package/bundle/memory-query.js +7 -7
- package/bundle/opencode.js +73 -73
- package/bundle/project-manual.js +7 -7
- package/bundle/recovery-certify.js +9 -9
- package/bundle/runtime.js +13 -13
- package/bundle/semantic.js +5 -5
- package/bundle/snapshot.js +4 -4
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +48 -48
- package/bundle/work-continuity.js +7 -7
- package/package.json +14 -2
- package/release-manifest.json +51 -1
package/bundle/context.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function
|
|
3
|
-
`,{encoding:"utf8",mode:384}),Qe(s,n)}function Q(r,t){return{id:r.id,name:r.name,remote:r.remote,rootPath:t,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var K=class{findExisting(t=process.cwd()){let e=j(t),n=pe(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>_(I(n,u))),a=le(e,o?n:void 0);if(!a)return null;let d=fe(W(a));return Q(d,a)}requireExisting(t=process.cwd()){let e=this.findExisting(t);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");return e}detect(t=process.cwd()){let e=j(t),n=pe(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(g=>_(I(n,g))),a=le(e,o?n:void 0);if(a){let g=W(a),c=fe(g);return c.rootPath!==a&&(c.rootPath=a,c.updatedAt=new Date().toISOString(),me(a,c)),Q(c,a)}let d=new Date().toISOString(),u=Xe(n),p={version:1,id:tt(n),name:u,remote:u,rootPath:n,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return me(n,p),Q(p,n)}};var nt=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],st=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ye(r){return r.normalize("NFKC").trim().toLowerCase()}function ot(r){if(r.length===0)return 0;let t=new Map;for(let n of r)t.set(n,(t.get(n)??0)+1);let e=0;for(let n of t.values()){let s=n/r.length;e-=s*Math.log2(s)}return e}function it(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function at(r,t,e){let n=r.slice(Math.max(0,t-48),t),s=r.slice(e,Math.min(r.length,e+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${s}`)}function ct(r,t){return r.start<t.end&&t.start<r.end}function ke(r){return r.sort((t,e)=>t.start!==e.start?t.start-e.start:e.end-e.start-(t.end-t.start))}var D=class{allowValues=new Set;enableEntropyHeuristic;constructor(t={}){for(let e of t.allowValues??[]){let n=ye(e);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=t.enableEntropyHeuristic??!0}scan(t){let e=[];for(let o of nt){let a=new RegExp(o.regex.source,o.regex.flags);for(let d of t.matchAll(a))d.index===void 0||!d[0]||this.allowed(d[0])||e.push({type:o.type,value:d[0],start:d.index,end:d.index+d[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&e.push(...this.entropyMatches(t));let n=ke(e),s=[];for(let o of n)s.some(a=>ct(a,o))||s.push(o);return ke(s)}hasSecrets(t){return this.scan(t).length>0}allowed(t){let e=ye(t);return st.has(e)?!0:this.allowValues.has(e)}entropyMatches(t){let e=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let s of t.matchAll(n)){if(s.index===void 0||!s[0])continue;let o=s[0];this.allowed(o)||it(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||at(t,s.index,s.index+o.length)&&(ot(o)<3.7||e.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return e}};var L=class{scanner;constructor(t={}){this.scanner=new D(t)}sanitize(t){let e=this.scanner.scan(t);if(e.length===0)return{text:t,redacted:0,secretTypes:[]};let n=t,s=[...e].sort((a,d)=>d.start-a.start),o=new Set;for(let a of s)o.add(a.type),n=n.slice(0,a.start)+`[REDACTED:${a.type}]`+n.slice(a.end);return{text:n,redacted:e.length,secretTypes:[...o].sort()}}sanitizeValue(t){if(typeof t=="string")return this.sanitize(t).text;if(Array.isArray(t))return t.map(e=>this.sanitizeValue(e));if(t&&typeof t=="object"){let e={};for(let[n,s]of Object.entries(t)){let o=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){e[n]="[REDACTED]";continue}e[n]=this.sanitizeValue(s)}return e}return t}};var Er=new L;import{homedir as Et}from"node:os";import{join as Ot}from"node:path";import{DeleteObjectCommand as dt,GetObjectCommand as lt,HeadObjectCommand as pt,ListObjectsV2Command as ft,PutObjectCommand as mt,S3Client as gt}from"@aws-sdk/client-s3";import{getSignedUrl as ht}from"@aws-sdk/s3-request-presigner";var F=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new gt({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new mt({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await ht(this.client,new lt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{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(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new pt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new dt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new ft({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};import{access as Se,mkdir as yt,readFile as kt,readdir as St,rm as bt,stat as be,writeFile as vt}from"node:fs/promises";import{dirname as wt,join as xt,relative as ve,resolve as jt}from"node:path";var R=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return jt(this.root,e)}async put(t,e){let n=this.path(t);await yt(wt(n),{recursive:!0}),await vt(n,e)}async get(t){try{return await kt(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await Se(this.path(t)),!0}catch{return!1}}async delete(t){await bt(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),n=[];try{await Se(e)}catch{return n}let s=async a=>{let d=await St(a,{withFileTypes:!0});for(let u of d){let p=xt(a,u.name);if(u.isDirectory()){await s(p);continue}let g=await be(p);n.push({key:ve(this.root,p),size:g.size,updatedAt:g.mtime.toISOString()})}},o=await be(e);return o.isDirectory()?await s(e):n.push({key:ve(this.root,e),size:o.size,updatedAt:o.mtime.toISOString()}),n}};import{DeleteObjectCommand as At,GetObjectCommand as Pt,HeadObjectCommand as Mt,ListObjectsV2Command as It,PutObjectCommand as Rt,S3Client as Tt}from"@aws-sdk/client-s3";import{getSignedUrl as Ct}from"@aws-sdk/s3-request-presigner";var T=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Tt({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Rt({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await Ct(this.client,new Pt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{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(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new Mt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new At({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new It({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};function Z(r,t){return console.warn(t),new R(r)}function we(r){let t=r.localRoot??Ot(Et(),".toolnet-memory","storage");if(r.provider==="r2"){let e=r.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new T({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):Z(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let e=r.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new T({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):Z(t,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let e=r.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new F({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):Z(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new R(t)}function Nt(r){return new Promise(t=>setTimeout(t,r))}async function xe(r,t={}){let e=Math.max(1,t.attempts??3),n=t.baseDelayMs??150,s=t.maxDelayMs??2e3,o;for(let a=1;a<=e;a++)try{return await r()}catch(d){if(o=d,a>=e)break;let u=Math.min(s,n*2**(a-1)),p=Math.floor(Math.random()*Math.max(1,u*.2));await Nt(u+p)}throw o}var _t=new Set(["put","get","getText","delete","list"]);function je(r,t={}){return new Proxy(r,{get(e,n){let s=Reflect.get(e,n,e);return typeof s!="function"?s:_t.has(n)?(...o)=>xe(()=>Promise.resolve(s.apply(e,o)),t):s.bind(e)}})}function Ae(r){let t=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function Pe(r){let t=r.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let s=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:t))}var V=class{constructor(t,e,n,s){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=n,this.folder=Ae(s??n),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),n=e,s=await this.provider.getText(t);if(s){let a;try{a=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${d instanceof Error?d.message:String(d)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(n=a.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:e};await this.provider.put(t,JSON.stringify(o,null,2)+`
|
|
4
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t
|
|
5
|
-
`,{encoding:"utf8",mode:384}),
|
|
1
|
+
import{existsSync as Ze,readFileSync as Xe}from"node:fs";import{homedir as et}from"node:os";import{join as tt}from"node:path";function rt(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function nt(){let r=process.env.TOOLNET_GLOBAL_ENV??tt(et(),".config","toolnet-memory",".env");if(!Ze(r))return;let t=Xe(r,"utf8");for(let e of t.split(/\r?\n/)){let n=e.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let o=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=rt(n.slice(s+1)))}}nt();function I(r,t){return r===void 0?t:["1","true","yes","on"].includes(r.toLowerCase())}function R(r,t){if(!r)return t;let e=Number(r);return Number.isFinite(e)?e:t}function ye(){return{memory:{autoCapture:I(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:I(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:I(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:I(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:R(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:R(process.env.MEMORY_RERANK_TOP,10),finalContext:R(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:R(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:I(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:R(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as dt}from"node:crypto";import{existsSync as L,mkdirSync as lt,readFileSync as pt,renameSync as ft,writeFileSync as mt}from"node:fs";import{basename as gt,dirname as F,join as T,parse as je,resolve as A}from"node:path";import{createHash as Se}from"node:crypto";import{spawnSync as st}from"node:child_process";var C="git-remote-v1",ot=new Set(["github.com","gitlab.com","bitbucket.org"]);function be(r,t){let e=t.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!e||e==="."||e===".."||e.split("/").some(n=>!n||n==="."||n==="..")?null:(ot.has(r)&&(e=e.toLowerCase()),e)}function it(r){let t;try{t=new URL(r)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(t.protocol))return null;let e=t.hostname.trim().toLowerCase();if(!e)return null;let n=t.protocol==="https:"&&t.port==="443"||t.protocol==="http:"&&t.port==="80"||t.protocol==="ssh:"&&t.port==="22",s=t.port&&!n?`${e}:${t.port}`:e,o=be(e,t.pathname);return o?`${s}/${o}`:null}function at(r){let t=r.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!t)return null;let e=t[1]?.trim().toLowerCase();if(!e||e.length===1)return null;let n=be(e,t[2]??"");return n?`${e}/${n}`:null}function he(r){let t=r.trim();return t?t.includes("://")?it(t):at(t):null}function ct(r){return Se("sha256").update(`${C}:${r}`).digest("hex")}function ve(r){return Se("sha256").update(`toolnet-project:${C}:${r}`).digest("hex").slice(0,16)}function ut(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function te(r,t){let e=st("git",["-C",r,...t],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return e.error||e.status!==0?null:e.stdout?.trim()||null}function ke(r,t){let e=ut(r);return e?{scheme:C,canonicalRemote:r,fingerprint:ct(r),repositoryName:e,source:t}:null}function xe(r){let t=te(r,["remote","get-url","origin"]);if(t){let s=he(t);if(s)return ke(s,"origin")}let e=te(r,["remote"]);if(!e)return null;let n=new Set;for(let s of e.split(/\r?\n/u).map(o=>o.trim()).filter(Boolean)){let o=te(r,["remote","get-url",s]);if(!o)continue;let i=he(o);i&&n.add(i)}return n.size!==1?null:ke([...n][0],"unique-remote")}var Ae=".toolnet",yt="project.json";function ht(r){return dt("sha256").update(r).digest("hex").slice(0,16)}function M(r){return T(r,Ae,yt)}function Me(r){return L(M(r))}function we(r,t){let e=A(r),n=je(e).root;for(;;){if(Me(e))return e;if(e===n||t&&e===A(t))break;let s=F(e);if(s===e)break;e=s}return null}function re(r){let t=A(r),e=je(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(o=>L(T(t,o))))return t;if(t===e)break;let s=F(t);if(s===t)break;t=s}return A(r)}function W(r){let t;try{t=JSON.parse(pt(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:F(F(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:n,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:n,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function D(r,t){let e=T(r,Ae);lt(e,{recursive:!0});let n=M(r),s=`${n}.tmp-${process.pid}`;mt(s,JSON.stringify(t,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),ft(s,n)}function j(r,t){return{id:r.id,name:r.name,remote:r.remote,rootPath:t,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}function ne(r){return{version:1,scheme:C,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function kt(r){let t=r.metadata?.toolnetIdentity;if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return typeof e.fingerprint=="string"?e.fingerprint:null}var V=class{adopt(t,e){let n=re(A(t));if(!e.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!e.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!e.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(Me(n)){let d=W(M(n));if(d.id!==e.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${d.id}`,`requested=${e.id}`].join(" "));return j(d,n)}let s=new Date().toISOString(),o={...e.metadata};e.gitIdentity&&(o.toolnetIdentity=ne(e.gitIdentity));let i={version:1,id:e.id.trim(),name:e.name.trim(),remote:e.remote.trim(),rootPath:n,createdAt:e.createdAt??s,updatedAt:s,graphVersion:e.graphVersion??0,memoryVersion:e.memoryVersion??0,metadata:Object.keys(o).length?o:void 0};return D(n,i),j(i,n)}recordGitIdentity(t,e,n={}){let s=this.requireExisting(t),o=M(s.rootPath),i=W(o),d=kt(i);if(d&&d!==e.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${d}`,`current=${e.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let c=i.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===e.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:ne(e)},i.updatedAt=new Date().toISOString(),D(s.rootPath,i)),j(i,s.rootPath)}findExisting(t=process.cwd()){let e=A(t),n=re(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>L(T(n,c))),i=we(e,o?n:void 0);if(!i)return null;let d=W(M(i));return j(d,i)}requireExisting(t=process.cwd()){let e=this.findExisting(t);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");return e}detect(t=process.cwd()){let e=A(t),n=re(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>L(T(n,u))),i=we(e,o?n:void 0);if(i){let u=M(i),k=W(u);return k.rootPath!==i&&(k.rootPath=i,k.updatedAt=new Date().toISOString(),D(i,k)),j(k,i)}let d=new Date().toISOString(),c=gt(n),p=xe(n),g={version:1,id:p?ve(p.canonicalRemote):ht(n),name:c,remote:p?.repositoryName??c,rootPath:n,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0,metadata:p?{toolnetIdentity:ne(p)}:void 0};return D(n,g),j(g,n)}};var St=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],bt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function Pe(r){return r.normalize("NFKC").trim().toLowerCase()}function vt(r){if(r.length===0)return 0;let t=new Map;for(let n of r)t.set(n,(t.get(n)??0)+1);let e=0;for(let n of t.values()){let s=n/r.length;e-=s*Math.log2(s)}return e}function xt(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function wt(r,t,e){let n=r.slice(Math.max(0,t-48),t),s=r.slice(e,Math.min(r.length,e+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${s}`)}function jt(r,t){return r.start<t.end&&t.start<r.end}function Ie(r){return r.sort((t,e)=>t.start!==e.start?t.start-e.start:e.end-e.start-(t.end-t.start))}var z=class{allowValues=new Set;enableEntropyHeuristic;constructor(t={}){for(let e of t.allowValues??[]){let n=Pe(e);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=t.enableEntropyHeuristic??!0}scan(t){let e=[];for(let o of St){let i=new RegExp(o.regex.source,o.regex.flags);for(let d of t.matchAll(i))d.index===void 0||!d[0]||this.allowed(d[0])||e.push({type:o.type,value:d[0],start:d.index,end:d.index+d[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&e.push(...this.entropyMatches(t));let n=Ie(e),s=[];for(let o of n)s.some(i=>jt(i,o))||s.push(o);return Ie(s)}hasSecrets(t){return this.scan(t).length>0}allowed(t){let e=Pe(t);return bt.has(e)?!0:this.allowValues.has(e)}entropyMatches(t){let e=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let s of t.matchAll(n)){if(s.index===void 0||!s[0])continue;let o=s[0];this.allowed(o)||xt(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||wt(t,s.index,s.index+o.length)&&(vt(o)<3.7||e.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return e}};var H=class{scanner;constructor(t={}){this.scanner=new z(t)}sanitize(t){let e=this.scanner.scan(t);if(e.length===0)return{text:t,redacted:0,secretTypes:[]};let n=t,s=[...e].sort((i,d)=>d.start-i.start),o=new Set;for(let i of s)o.add(i.type),n=n.slice(0,i.start)+`[REDACTED:${i.type}]`+n.slice(i.end);return{text:n,redacted:e.length,secretTypes:[...o].sort()}}sanitizeValue(t){if(typeof t=="string")return this.sanitize(t).text;if(Array.isArray(t))return t.map(e=>this.sanitizeValue(e));if(t&&typeof t=="object"){let e={};for(let[n,s]of Object.entries(t)){let o=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){e[n]="[REDACTED]";continue}e[n]=this.sanitizeValue(s)}return e}return t}};var Zr=new H;import{homedir as Gt}from"node:os";import{join as Ut}from"node:path";import{DeleteObjectCommand as Mt,GetObjectCommand as Pt,HeadObjectCommand as It,ListObjectsV2Command as Rt,PutObjectCommand as Ct,S3Client as Tt}from"@aws-sdk/client-s3";import{getSignedUrl as Et}from"@aws-sdk/s3-request-presigner";var B=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new Tt({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Ct({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await Et(this.client,new Pt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{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(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new It({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Mt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new Rt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};import{access as Re,mkdir as Ot,readFile as _t,readdir as Nt,rm as $t,stat as Ce,writeFile as Kt}from"node:fs/promises";import{dirname as Wt,join as Dt,relative as Te,resolve as Lt}from"node:path";var E=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return Lt(this.root,e)}async put(t,e){let n=this.path(t);await Ot(Wt(n),{recursive:!0}),await Kt(n,e)}async get(t){try{return await _t(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await Re(this.path(t)),!0}catch{return!1}}async delete(t){await $t(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),n=[];try{await Re(e)}catch{return n}let s=async i=>{let d=await Nt(i,{withFileTypes:!0});for(let c of d){let p=Dt(i,c.name);if(c.isDirectory()){await s(p);continue}let g=await Ce(p);n.push({key:Te(this.root,p),size:g.size,updatedAt:g.mtime.toISOString()})}},o=await Ce(e);return o.isDirectory()?await s(e):n.push({key:Te(this.root,e),size:o.size,updatedAt:o.mtime.toISOString()}),n}};import{DeleteObjectCommand as Ft,GetObjectCommand as Vt,HeadObjectCommand as zt,ListObjectsV2Command as Ht,PutObjectCommand as Bt,S3Client as Jt}from"@aws-sdk/client-s3";import{getSignedUrl as qt}from"@aws-sdk/s3-request-presigner";var O=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Jt({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Bt({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await qt(this.client,new Vt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{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(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new zt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Ft({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new Ht({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let o of s.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};function se(r,t){return console.warn(t),new E(r)}function Ee(r){let t=r.localRoot??Ut(Gt(),".toolnet-memory","storage");if(r.provider==="r2"){let e=r.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new O({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):se(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let e=r.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new O({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):se(t,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let e=r.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new B({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):se(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new E(t)}function Yt(r){return new Promise(t=>setTimeout(t,r))}async function Oe(r,t={}){let e=Math.max(1,t.attempts??3),n=t.baseDelayMs??150,s=t.maxDelayMs??2e3,o;for(let i=1;i<=e;i++)try{return await r()}catch(d){if(o=d,i>=e)break;let c=Math.min(s,n*2**(i-1)),p=Math.floor(Math.random()*Math.max(1,c*.2));await Yt(c+p)}throw o}var Qt=new Set(["put","get","getText","delete","list"]);function _e(r,t={}){return new Proxy(r,{get(e,n){let s=Reflect.get(e,n,e);return typeof s!="function"?s:Qt.has(n)?(...o)=>Oe(()=>Promise.resolve(s.apply(e,o)),t):s.bind(e)}})}function Ne(r){let t=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function $e(r){let t=r.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let s=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:t))}var J=class{constructor(t,e,n,s){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=n,this.folder=Ne(s??n),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),n=e,s=await this.provider.getText(t);if(s){let i;try{i=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${d instanceof Error?d.message:String(d)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(n=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:e};await this.provider.put(t,JSON.stringify(o,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=$e(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,e,n){return await this.ensureRegistered(),this.provider.put(this.key(t),e,n)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};import{join as nr}from"node:path";import{createHash as Zt}from"node:crypto";import{dirname as Xt}from"node:path";import{mkdirSync as er,readFileSync as Vs,renameSync as tr,writeFileSync as rr}from"node:fs";function b(r){return Zt("sha256").update(r).digest("hex")}function P(r,t){er(Xt(r),{recursive:!0});let e=`${r}.${process.pid}.tmp`;rr(e,JSON.stringify(t,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),tr(e,r)}function Ke(r,t){let e=r.trim(),n=e.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=b(e).slice(0,12);if(!n||n==="."||n==="..")return`${t}--${s}`;let o=n.slice(0,100);return o===e&&e.length<=100?o:`${o.slice(0,85)}--${s}`}function We(r,t,e){let n=t.trim(),s=e.trim();if(!n)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let o=Ke(n.toLowerCase(),"agent"),i=Ke(s,"session");return{projectId:r.id,projectName:r.name,projectRoot:r.rootPath,agent:n,nativeSessionId:s,sessionKey:`${n}:${s}`,remotePrefix:["projects",r.id,"runtime","sources",o,i].join("/"),localDirectory:nr(r.rootPath,".toolnet","runtime","sources",o,i)}}import{existsSync as Fe,mkdirSync as sr,readFileSync as or,statSync as De,writeFileSync as ir}from"node:fs";import{dirname as ar,join as cr}from"node:path";var Le=64*1024,ur=`# ToolNet Project Operating Manual
|
|
6
6
|
|
|
7
7
|
This file contains persistent instructions for AI agents working on this project.
|
|
8
8
|
|
|
@@ -45,19 +45,19 @@ Things an AI agent should always remember.
|
|
|
45
45
|
<!--
|
|
46
46
|
- [advisory] Prefer small focused files.
|
|
47
47
|
-->
|
|
48
|
-
`;function
|
|
49
|
-
`,"application/json"),
|
|
50
|
-
`).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(n)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(n)?"passing":"unknown"}function
|
|
48
|
+
`;function q(r){return cr(r.rootPath,".toolnet","PROJECT.md")}function dr(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function lr(r){let t=[],e=new Set,n=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=n.exec(r);){let o=s[1].toLowerCase(),i=dr(s[2]);if(!i)continue;let d=`${o}:${i.toLowerCase()}`;e.has(d)||(e.add(d),t.push({id:b(d).slice(0,24),mode:o,text:i,source:"manual"}))}return t}function pr(r){let t=q(r);return Fe(t)||(sr(ar(t),{recursive:!0}),ir(t,ur,{encoding:"utf8",mode:384})),t}function G(r,t=!1){let e=t?pr(r):q(r);if(!Fe(e))return null;if(De(e).size>Le)throw new Error(`PROJECT.md exceeds ${Le} bytes`);let s=or(e,"utf8");return{path:e,content:s,digest:b(s),rules:lr(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(De(e).mtimeMs).toISOString()}}import{existsSync as wr,mkdirSync as jr}from"node:fs";import{join as ie}from"node:path";import{join as Ve}from"node:path";import{mkdirSync as fr}from"node:fs";function He(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function v(r,t=20){let e=[],n=new Set;for(let s of r.slice().reverse()){let o=He(s);if(!(!o||n.has(o))&&(n.add(o),e.push(s),e.length>=t))break}return e.reverse()}function mr(r,t=20){let e=new Map;for(let n of r){let s=`${n.kind}|${He(n.command)}`;e.delete(s),e.set(s,n)}return Array.from(e.values()).slice(-t)}function gr(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 ze(r,t){let e=t.status??r?.status??"pending",n=e;r&&(r.status==="completed"&&e!=="completed"?n="completed":e==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(n=r.status));let s=r&&gr(t)?r.title:t.text;return{id:r?.id??b(t.key).slice(0,24),title:s,status:n,order:t.order??r?.order,confidence:Math.max(t.confidence,r?.confidence??0),updatedAt:t.occurredAt,updatedBy:{agent:t.agent,nativeSessionId:t.nativeSessionId,eventId:t.eventId}}}async function Be(r,t){let e=`projects/${r.id}/work/observations/`,n=await t.list(e),s=[];for(let o of n.filter(i=>i.key.endsWith(".json")).sort((i,d)=>i.key.localeCompare(d.key))){let i=await t.getText(o.key);if(i)try{let d=JSON.parse(i);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}async function oe(r,t){let n=(await Be(r,t)).flatMap(a=>a.observations).sort((a,S)=>{let me=a.occurredAt.localeCompare(S.occurredAt);if(me!==0)return me;let ge=a.sequence-S.sequence;return ge!==0?ge:a.id.localeCompare(S.id)}),s=new Map,o=new Map,i,d,c,p,g,u=[],k=[],l=[],h=[],Z=[],N=new Map,$=[],f=[],ue=[],de=[],le=[],pe=[];for(let a of n)switch(a.kind){case"request":i=a.text;break;case"activity":d=a.text;break;case"goal":c=a.text;break;case"plan":p=a.text;break;case"phase":s.set(a.key,ze(s.get(a.key),a));break;case"task":o.set(a.key,ze(o.get(a.key),a));break;case"decision":u.push(a.text);break;case"blocker":k.push(a.text);break;case"warning":l.push(a.text);break;case"next_action":h.push(a.text);break;case"file":{Z.push(a.text);let S=a.fileAction??"active";N.delete(a.text),N.set(a.text,S),S==="modified"?$.push(a.text):S==="created"?f.push(a.text):S==="deleted"&&ue.push(a.text);break}case"command":de.push(a.text);break;case"test":le.push(a.text),a.checkKind&&pe.push({kind:a.checkKind,command:a.text,status:a.checkStatus??"unknown",updatedAt:a.occurredAt,agent:a.agent,nativeSessionId:a.nativeSessionId});break;case"session":g={agent:a.agent,nativeSessionId:a.nativeSessionId,sessionKey:a.sessionKey,updatedAt:a.occurredAt};break}let w=Array.from(s.values()).sort((a,S)=>(a.order??Number.MAX_SAFE_INTEGER)-(S.order??Number.MAX_SAFE_INTEGER)),x=Array.from(o.values()).sort((a,S)=>(a.order??Number.MAX_SAFE_INTEGER)-(S.order??Number.MAX_SAFE_INTEGER)),X=w.find(a=>a.status==="in_progress")??w.find(a=>a.status==="blocked")??w.find(a=>a.status==="pending"),K=x.find(a=>a.status==="in_progress")??x.find(a=>a.status==="blocked")??x.find(a=>a.status==="pending"),Ye=v([...h,...K?[K.title]:[],...!K&&X?[X.title]:[],...x.filter(a=>a.status==="pending").slice(0,5).map(a=>a.title)],8),Qe=v([...k,...w.filter(a=>a.status==="blocked").map(a=>a.title),...x.filter(a=>a.status==="blocked").map(a=>a.title)],20),ee={version:1,projectId:r.id,projectName:r.name,currentRequest:i,currentActivity:d,goal:c,plan:p,phases:w,tasks:x,decisions:v(u,20),blockers:Qe,warnings:v(l,20),nextActions:Ye,filesTouched:v(Z,30),activeFiles:Array.from(N.entries()).filter(([,a])=>a!=="deleted").map(([a])=>a).slice(-5),modifiedFiles:v($,30),createdFiles:v(f,30),deletedFiles:v(ue,30),commands:v(de,20),tests:v(le,20),checks:mr(pe,20),currentPhase:X,currentTask:K,progress:{phasesTotal:w.length,phasesCompleted:w.filter(a=>a.status==="completed").length,tasksTotal:x.length,tasksCompleted:x.filter(a=>a.status==="completed").length,blocked:w.filter(a=>a.status==="blocked").length+x.filter(a=>a.status==="blocked").length},lastSession:g,updatedAt:n.length?n[n.length-1].occurredAt:new Date().toISOString()},fe=Ve(r.rootPath,".toolnet","work");return fr(fe,{recursive:!0}),P(Ve(fe,"current.json"),ee),await t.put(`projects/${r.id}/work/current.json`,JSON.stringify(ee,null,2)+`
|
|
49
|
+
`,"application/json"),ee}async function U(r,t){if((await Be(r,t)).length>0)return oe(r,t);let n=await t.getText(`projects/${r.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}var to=new Int32Array(new SharedArrayBuffer(4));import{closeSync as io,existsSync as yr,fsyncSync as ao,mkdirSync as co,openSync as uo,readFileSync as hr,renameSync as lo,writeFileSync as po}from"node:fs";import{dirname as mo,join as kr}from"node:path";function Sr(r){return kr(r.rootPath,".toolnet","work","current.json")}function Je(r){let t=Sr(r);if(!yr(t))return null;try{let e=JSON.parse(hr(t,"utf8"));return e.version!==1||e.projectId!==r.id?null:e}catch{return null}}function y(r,t){let e=new Set,n=[];for(let s of r){let o=s.replace(/\s+/g," ").trim();if(!o)continue;let i=o.normalize("NFKC").toLowerCase();if(!e.has(i)&&(e.add(i),n.push(o),n.length>=t))break}return n}function qe(r){if(r)return{id:r.id,title:r.title,status:r.status}}function br(r,t=[]){let e=t.slice(-10);if(e.some(s=>s.status==="failed"))return"failing";if(e.some(s=>s.status==="passed"))return"passing";let n=r.slice(-10).join(`
|
|
50
|
+
`).toLowerCase();return/(?:failed|failing|failure|error|✗|❌)/u.test(n)?"failing":/(?:passed|passing|green|success|✓|✅)/u.test(n)?"passing":"unknown"}function vr(r){return b(JSON.stringify(r))}function xr(r){let t=[];for(let e of r){if(!e)continue;let n=e.match(/https?:\/\/[^\s<>"'`)\]}]+/giu)??[];for(let s of n){let o=s.replace(/[.,;:!?]+$/gu,"").trim();o&&t.push(o)}}return y(t,30)}function Ge(r){let{project:t,identity:e,state:n}=r,s=n.activeFiles?.at(-1)??n.filesTouched.at(-1),o=n.phases.filter(f=>f.status==="completed").map(f=>f.title),i=n.tasks.filter(f=>f.status==="completed").map(f=>f.title),d=n.phases.filter(f=>f.status!=="completed"&&f.status!=="cancelled").map(f=>f.title),c=n.tasks.filter(f=>f.status!=="completed"&&f.status!=="cancelled").map(f=>f.title),p=new Set(n.tasks.filter(f=>f.status==="completed").map(f=>f.title.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),g=y(n.nextActions.filter(f=>!p.has(f.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim())),10),u=y([...c,...g],15),k=y(n.tests.slice().reverse(),10),l=y([...(n.activeFiles??[]).slice().reverse(),...n.filesTouched.slice().reverse()],20),h={schema:"toolnet.handoff.v2",version:2,project:{id:t.id,name:t.name},source:{agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,sequence:r.sequence,reason:r.reason},capturedAt:r.capturedAt??new Date().toISOString(),goal:n.goal,request:n.currentRequest,activity:n.currentActivity,current:{phase:qe(n.currentPhase),task:qe(n.currentTask),file:s},completed:{phases:y(o,20),tasks:y(i,30)},remaining:{phases:y(d,20),tasks:y(c,30),todos:u},nextAction:g[0],blockers:y(n.blockers.slice().reverse(),10),decisions:y(n.decisions.slice().reverse(),10),files:{current:s,recent:l,active:y(n.activeFiles??[],10),modified:y(n.modifiedFiles??[],20),created:y(n.createdFiles??[],20),deleted:y(n.deletedFiles??[],20)},tests:{status:br(n.tests,n.checks),recent:k,checks:(n.checks??[]).slice(-10).map(f=>({kind:f.kind,status:f.status,command:f.command}))},evidence:{commands:y((n.commands??[]).slice().reverse(),20),references:xr([n.currentRequest,n.currentActivity,n.goal,n.plan,...n.decisions,...n.blockers,...n.warnings,...n.nextActions,...n.filesTouched,...n.commands??[],...n.tests,...(n.checks??[]).map(f=>f.command)])},attention:y(r.attention??[],20),progress:n.progress},{capturedAt:Z,source:N,...$}=h;return{...h,stateDigest:vr($)}}function Ar(r){return!!(r.currentRequest||r.currentActivity||r.goal||r.plan||r.phases.length>0||r.tasks.length>0||r.nextActions.length>0||r.blockers.length>0||r.decisions.length>0||r.filesTouched.length>0)}function Mr(r,t,e,n,s){if(!Ar(e))return null;let o=G(r,!1),d=[...o?o.rules.filter(u=>u.mode==="enforce").map(u=>u.text):[],...e.warnings].slice(0,20),c=Ge({project:r,identity:t,state:e,reason:n,sequence:s,attention:d}),p=c.stateDigest;return{version:1,id:b([r.id,t.sessionKey,p].join("|")).slice(0,24),projectId:r.id,projectName:r.name,createdAt:new Date().toISOString(),reason:n,sourceSession:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,sequence:s},currentRequest:e.currentRequest,currentActivity:e.currentActivity,goal:e.goal,plan:e.plan,progress:e.progress,currentPhase:e.currentPhase,currentTask:e.currentTask,incompletePhases:e.phases.filter(u=>u.status!=="completed"&&u.status!=="cancelled"),incompleteTasks:e.tasks.filter(u=>u.status!=="completed"&&u.status!=="cancelled"),nextActions:c.remaining.todos.slice(0,10),blockers:e.blockers.slice(-10),decisions:e.decisions.slice(-10),warnings:e.warnings.slice(-10),attention:d,filesTouched:e.filesTouched.slice(-20),activeFiles:e.activeFiles?.slice(-10),modifiedFiles:e.modifiedFiles?.slice(-20),createdFiles:e.createdFiles?.slice(-20),deletedFiles:e.deletedFiles?.slice(-20),tests:e.tests.slice(-15),checks:e.checks?.slice(-10),stateDigest:p,continuity:c}}function Pr(r,t){let e=ie(r.rootPath,".toolnet","work","handoffs");jr(e,{recursive:!0});let n=ie(e,`${t.id}.json`);wr(n)||P(n,t),P(ie(r.rootPath,".toolnet","work","handoff-latest.json"),t)}var Y=class{constructor(t){this.options=t}options;async capture(t,e){let n=Je(this.options.project);n||(n=await U(this.options.project,this.options.storage)),n||(n=await oe(this.options.project,this.options.storage));let s=Mr(this.options.project,this.options.identity,n,t,e);if(!s)return null;Pr(this.options.project,s);let o=`projects/${this.options.project.id}/work/handoffs/${s.id}.json`;return await this.options.storage.exists(o)||await this.options.storage.put(o,JSON.stringify(s,null,2)+`
|
|
51
51
|
`,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(s,null,2)+`
|
|
52
|
-
`,"application/json"),s}};async function
|
|
53
|
-
`);if(
|
|
54
|
-
`)),
|
|
55
|
-
`).trim()}async function
|
|
56
|
-
`);return}if(r==="brief-json"){let s=await
|
|
52
|
+
`,"application/json"),s}};async function Q(r,t){let e=await t.getText(`projects/${r.id}/work/handoff-latest.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function Ue(r,t){let e=await t.getText(`projects/${r.id}/work/semantic/current.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}function ae(r){if(!r)return 0;let t=Array.from(r).length,e=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(t/3.5,e*1.3))}function m(r,t){let e=r.replace(/\s+/g," ").trim();return e.length<=t?e:e.slice(0,Math.max(0,t-1)).trimEnd()+"\u2026"}function Ir(r){let t=[],e=!1;for(let n of r.split(/\r?\n/u)){let s=n.trim();if(s.includes("<!--")&&(e=!0),e){s.includes("-->")&&(e=!1);continue}let o=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||o.startsWith("- [enforce]")||o.startsWith("* [enforce]")||o.startsWith("- [advisory]")||o.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&t.push(m(s,280)),t.length>=16))break}return t}function Rr(r){let t=[],e=[];for(let n of r.split(/\\r?\\n/u)){let s=n.trim(),o=s.toLowerCase(),d=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(p=>o.startsWith(p));if(!d)continue;let c=s.slice(d.length).trim();c&&(d.includes("enforce")?t.push(c):e.push(c))}return{enforce:t,advisory:e}}function Cr(r,t){let e=[];for(let n of r){let s=[...e,n].join(`
|
|
53
|
+
`);if(ae(s)<=t){e.push(n);continue}let o=ae(e.join(`
|
|
54
|
+
`)),i=Math.max(0,t-o);if(i>=16){let d=Math.floor(i*3.2),c=m(n,d);c&&e.push(c)}break}return e.join(`
|
|
55
|
+
`).trim()}async function ce(r){let t=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),e=G(r.project,!1),n=e?.content??"";n||(n=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=Rr(n),o=e?e.rules.filter(l=>l.mode==="enforce").map(l=>l.text):s.enforce,i=e?e.rules.filter(l=>l.mode==="advisory").map(l=>l.text):s.advisory,d=n?Ir(n):[],c=await U(r.project,r.storage),p=await Ue(r.project,r.storage),g=await Q(r.project,r.storage),u=[];if(u.push("[TOOLNET PROJECT CONTEXT]"),u.push(`Project: ${r.project.name}`),u.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),n&&u.push(`Full operating manual: ${q(r.project)}`),o.length){u.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let l of o.slice(0,24))u.push(`- [ENFORCE] ${m(l,240)}`)}if(i.length){u.push("","PROJECT PREFERENCES");for(let l of i.slice(0,10))u.push(`- ${m(l,220)}`)}if(p&&(p.mission&&u.push("","MISSION",m(p.mission.value,420)),p.activeObjective&&u.push("","CURRENT OBJECTIVE",m(p.activeObjective.value,420)),p.why&&u.push("","WHY THIS WORK MATTERS",m(p.why.value,420)),p.desiredOutcome&&u.push("","DESIRED OUTCOME",m(p.desiredOutcome.value,420)),p.planRationale&&u.push("","WHY THIS APPROACH",m(p.planRationale.value,420))),c){if(u.push("","ACTIVE WORK"),c.goal&&u.push(`Goal: ${m(c.goal,320)}`),c.plan&&u.push(`Plan: ${m(c.plan,320)}`),u.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&u.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&p){let l=p.phases.find(h=>h.order===c.currentPhase?.order);l&&(l.objective&&u.push(`Phase objective: ${m(l.objective.value,340)}`),l.why?u.push(`Why this phase: ${m(l.why.value,340)}`):u.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),l.deliverable&&u.push(`Deliverable: ${m(l.deliverable.value,340)}`),l.dependencies.length&&u.push(`Depends on: ${l.dependencies.slice(0,4).map(h=>m(h.value,180)).join("; ")}`),l.acceptanceCriteria.length&&(u.push("","DEFINITION OF DONE"),l.acceptanceCriteria.slice(0,6).forEach(h=>{u.push(`- ${m(h.value,260)}`)})),l.openQuestions.length&&(u.push("","OPEN QUESTIONS FOR CURRENT PHASE"),l.openQuestions.slice(0,4).forEach(h=>{u.push(`- ${m(h.value,260)}`)})))}c.currentTask&&u.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(u.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((l,h)=>{u.push(`${h+1}. ${m(l,260)}`)})),c.blockers.length&&(u.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(l=>{u.push(`- ${m(l,260)}`)})),c.warnings.length&&(u.push("","ATTENTION"),c.warnings.slice(-5).forEach(l=>{u.push(`- ${m(l,260)}`)})),c.decisions.length&&(u.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(l=>{u.push(`- ${m(l,260)}`)})),c.lastSession&&u.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(p&&p.openQuestions.length&&(u.push("","UNRESOLVED QUESTIONS"),p.openQuestions.slice(0,5).forEach(l=>{u.push(`- ${m(l.value,260)}`)})),g&&u.push(`Latest handoff: ${g.reason} / ${g.sourceSession.agent}`),d.length){u.push("","OPERATING NOTES");for(let l of d)u.push(`- ${l}`)}u.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let k=Cr(u,t);return{version:1,projectId:r.project.id,projectName:r.project.name,text:k,estimatedTokens:ae(k),maxTokens:t,hasManual:!!n,hasWorkState:!!c,hasHandoff:!!g,generatedAt:new Date().toISOString()}}function _(r,t){let e=r.indexOf(t);return e>=0?r[e+1]:void 0}function Tr(r){let t=ye(),e=_e(Ee({provider:t.storage.provider,huggingface:t.storage.huggingface,localRoot:t.storage.localRoot}),{attempts:3});return new J(e,r.id,r.name,r.remote??r.name)}async function Er(){let[r="help",...t]=process.argv.slice(2),e=new V().detect(_(t,"--project")??process.cwd()),n=Tr(e);if(r==="brief"){let s=Number(_(t,"--tokens")??1e3),o=await ce({project:e,storage:n,maxTokens:Number.isFinite(s)?s:1e3});process.stdout.write(o.text+`
|
|
56
|
+
`);return}if(r==="brief-json"){let s=await ce({project:e,storage:n,maxTokens:Number(_(t,"--tokens")??1e3)});console.log(JSON.stringify(s,null,2));return}if(r==="handoff-latest"){let s=await Q(e,n);console.log(JSON.stringify(s,null,2));return}if(r==="handoff-create"){let s=_(t,"--agent")??"manual";if(s==="manual")throw new Error("--agent must be opencode, agy, or codex");let o=_(t,"--session");if(!o)throw new Error("--session is required");let i=We(e,s,o),c=await new Y({project:e,storage:n,identity:i}).capture("manual",0);console.log(JSON.stringify(c,null,2));return}console.log(`Work Context
|
|
57
57
|
|
|
58
58
|
Commands:
|
|
59
59
|
brief [--project PATH] [--tokens N]
|
|
60
60
|
brief-json [--project PATH] [--tokens N]
|
|
61
61
|
handoff-latest [--project PATH]
|
|
62
62
|
handoff-create --agent <opencode|agy|codex> --session <id>
|
|
63
|
-
`)}
|
|
63
|
+
`)}Er().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
|