@trymesh/cli 0.3.22 → 0.3.23

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/dist/auth.js CHANGED
@@ -1 +1 @@
1
- function e(e){return"object"==typeof e&&null!==e&&"access_token"in e&&"string"==typeof e.access_token&&function(e){const s=e.split(".");if(3!==s.length)return!1;try{const e=JSON.parse(Buffer.from(s[1],"base64url").toString("utf8"));return!("number"==typeof e.exp&&1e3*e.exp<Date.now())}catch{return!1}}(e.access_token)}function s(e){return e.trim().replace(/\s+at\s+|[\(\[]\s*at\s*[\)\]]|_at_|\*at\*/i,"@").replace(/\s+/g,"").toLowerCase()}async function t(){try{const e=await import("keytar");return e.default??e}catch{return null}}import n from"node:fs/promises";import i from"node:path";import r from"node:os";import a from"enquirer";const{prompt:o}=a;import{createClient as c}from"@supabase/supabase-js";import u from"picocolors";import"dotenv/config";const l=process.env.SUPABASE_URL||"https://msmonxiacxhendxehezw.supabase.co",h=process.env.SUPABASE_ANON_KEY||"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im1zbW9ueGlhY3hoZW5keGVoZXp3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzY5NDU3NTMsImV4cCI6MjA5MjUyMTc1M30.K-FQFpcOwtJAIAfn5lTzmrox_6cv_8qqXGxi9IgosB8",m=i.join(r.homedir(),".config","mesh"),d=i.join(m,"session.json"),p="mesh-agent-cli",f="refresh-token",w=process.env.MESH_USERNAME_EMAIL_DOMAIN?.trim();export class AuthManager{supabase;session=null;keytarUnavailable=!1;constructor(){this.supabase=c(l,h)}async restoreAuthenticated(){try{const s=await n.readFile(d,"utf-8"),t=JSON.parse(s);if(!e(t))throw new Error("Invalid session shape");const i=await this.getKeychainRefreshToken(),r=t.refresh_token??void 0,a=i||r;if(t.access_token){const{data:e,error:s}=await this.supabase.auth.setSession({access_token:t.access_token,refresh_token:a||""});if(!s&&e.session&&e.user&&e.user.email)return this.session=e.session,await this.saveSession(e.session),{email:e.user.email,id:e.user.id}}}catch{}return null}async ensureAuthenticated(){const e=await this.restoreAuthenticated();return e||this.promptLogin()}async promptLogin(){process.stdout.write(["",`${u.cyan(u.bold("mesh"))} ${u.dim("Please sign in to continue.")}`,""].join("\n")+"\n");let e=null;for(;!e;){const{identifier:t,password:n}=await o([{type:"input",name:"identifier",message:u.dim("email or username: ")},{type:"password",name:"password",message:u.dim("password: ")}]),i=s(t||""),r=n?.trim()||"";if(!i||!r){process.stdout.write(u.red("\n ✗ Email/username and password are required.\n\n"));continue}const a=await this.resolveLoginEmail(i);if(!a){process.stdout.write(u.red("\n ✗ Username not found or ambiguous. Try your full email address.\n\n"));continue}const{data:c,error:l}=await this.supabase.auth.signInWithPassword({email:a,password:r});!l&&c.session&&c.user&&c.user.email?(this.session=c.session,await this.saveSession(c.session),e={email:c.user.email,id:c.user.id}):process.stdout.write(u.red(`\n ✗ ${l?.message??"Login failed. Please try again."}\n\n`))}return process.stdout.write(u.green(`\n ✓ Signed in as ${e.email}\n\n`)),e}async signOut(){await this.supabase.auth.signOut();try{await n.unlink(d),await this.deleteKeychainRefreshToken()}catch{}process.stdout.write(u.dim("\nSigned out.\n"))}async saveSession(e){await n.mkdir(m,{recursive:!0,mode:448});let s=!1;e.refresh_token&&(s=await this.setKeychainRefreshToken(e.refresh_token));const{refresh_token:t,...i}=e,r=s||!e.refresh_token?i:{...i,refresh_token:e.refresh_token};await n.writeFile(d,JSON.stringify(r),{mode:384})}getAccessToken(){return this.session?.access_token}async resolveLoginEmail(e){if(e.includes("@"))return e;try{const{data:s,error:t}=await this.supabase.rpc("mesh_resolve_login_identifier",{identifier:e});if(!t&&"string"==typeof s&&s.includes("@"))return s.trim().toLowerCase()}catch{}return w?`${e}@${w}`.toLowerCase():null}async getKeychainRefreshToken(){const e=await t();if(!e)return this.keytarUnavailable=!0,null;try{return await e.getPassword(p,f)}catch{return this.keytarUnavailable=!0,null}}async setKeychainRefreshToken(e){const s=await t();if(!s)return this.noteKeytarFallback(),!1;try{return await s.setPassword(p,f,e),!0}catch{return this.noteKeytarFallback(),!1}}async deleteKeychainRefreshToken(){const e=await t();e&&await e.deletePassword(p,f).catch(()=>!1)}noteKeytarFallback(){this.keytarUnavailable||(this.keytarUnavailable=!0,process.stderr.write(u.dim("[Mesh] OS keychain unavailable; storing session fallback in ~/.config/mesh/session.json with 0600 permissions.\n")))}}
1
+ function e(e){return"object"==typeof e&&null!==e&&"access_token"in e&&"string"==typeof e.access_token&&function(e){const s=e.split(".");if(3!==s.length)return!1;try{const e=JSON.parse(Buffer.from(s[1],"base64url").toString("utf8"));return!("number"==typeof e.exp&&1e3*e.exp<Date.now())}catch{return!1}}(e.access_token)}function s(e){return e.trim().replace(/\s+at\s+|[\(\[]\s*at\s*[\)\]]|_at_|\*at\*/i,"@").replace(/\s+/g,"").toLowerCase()}async function t(){try{const e=await import("keytar");return e.default??e}catch{return null}}import n from"node:fs/promises";import r from"node:path";import i from"node:os";import a from"enquirer";const{prompt:o}=a;import{createClient as c}from"@supabase/supabase-js";import u from"ws";import l from"picocolors";import"dotenv/config";const h=process.env.SUPABASE_URL||"https://msmonxiacxhendxehezw.supabase.co",m=process.env.SUPABASE_ANON_KEY||"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im1zbW9ueGlhY3hoZW5keGVoZXp3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzY5NDU3NTMsImV4cCI6MjA5MjUyMTc1M30.K-FQFpcOwtJAIAfn5lTzmrox_6cv_8qqXGxi9IgosB8",p=r.join(i.homedir(),".config","mesh"),d=r.join(p,"session.json"),f="mesh-agent-cli",w="refresh-token",y=process.env.MESH_USERNAME_EMAIL_DOMAIN?.trim();export class AuthManager{supabase;session=null;keytarUnavailable=!1;constructor(){this.supabase=c(h,m,{realtime:{transport:u}})}async restoreAuthenticated(){try{const s=await n.readFile(d,"utf-8"),t=JSON.parse(s);if(!e(t))throw new Error("Invalid session shape");const r=await this.getKeychainRefreshToken(),i=t.refresh_token??void 0,a=r||i;if(t.access_token){const{data:e,error:s}=await this.supabase.auth.setSession({access_token:t.access_token,refresh_token:a||""});if(!s&&e.session&&e.user&&e.user.email)return this.session=e.session,await this.saveSession(e.session),{email:e.user.email,id:e.user.id}}}catch{}return null}async ensureAuthenticated(){const e=await this.restoreAuthenticated();return e||this.promptLogin()}async promptLogin(){process.stdout.write(["",`${l.cyan(l.bold("mesh"))} ${l.dim("Please sign in to continue.")}`,""].join("\n")+"\n");let e=null;for(;!e;){const{identifier:t,password:n}=await o([{type:"input",name:"identifier",message:l.dim("email or username: ")},{type:"password",name:"password",message:l.dim("password: ")}]),r=s(t||""),i=n?.trim()||"";if(!r||!i){process.stdout.write(l.red("\n ✗ Email/username and password are required.\n\n"));continue}const a=await this.resolveLoginEmail(r);if(!a){process.stdout.write(l.red("\n ✗ Username not found or ambiguous. Try your full email address.\n\n"));continue}const{data:c,error:u}=await this.supabase.auth.signInWithPassword({email:a,password:i});!u&&c.session&&c.user&&c.user.email?(this.session=c.session,await this.saveSession(c.session),e={email:c.user.email,id:c.user.id}):process.stdout.write(l.red(`\n ✗ ${u?.message??"Login failed. Please try again."}\n\n`))}return process.stdout.write(l.green(`\n ✓ Signed in as ${e.email}\n\n`)),e}async signOut(){await this.supabase.auth.signOut();try{await n.unlink(d),await this.deleteKeychainRefreshToken()}catch{}process.stdout.write(l.dim("\nSigned out.\n"))}async saveSession(e){await n.mkdir(p,{recursive:!0,mode:448});let s=!1;e.refresh_token&&(s=await this.setKeychainRefreshToken(e.refresh_token));const{refresh_token:t,...r}=e,i=s||!e.refresh_token?r:{...r,refresh_token:e.refresh_token};await n.writeFile(d,JSON.stringify(i),{mode:384})}getAccessToken(){return this.session?.access_token}async resolveLoginEmail(e){if(e.includes("@"))return e;try{const{data:s,error:t}=await this.supabase.rpc("mesh_resolve_login_identifier",{identifier:e});if(!t&&"string"==typeof s&&s.includes("@"))return s.trim().toLowerCase()}catch{}return y?`${e}@${y}`.toLowerCase():null}async getKeychainRefreshToken(){const e=await t();if(!e)return this.keytarUnavailable=!0,null;try{return await e.getPassword(f,w)}catch{return this.keytarUnavailable=!0,null}}async setKeychainRefreshToken(e){const s=await t();if(!s)return this.noteKeytarFallback(),!1;try{return await s.setPassword(f,w,e),!0}catch{return this.noteKeytarFallback(),!1}}async deleteKeychainRefreshToken(){const e=await t();e&&await e.deletePassword(f,w).catch(()=>!1)}noteKeytarFallback(){this.keytarUnavailable||(this.keytarUnavailable=!0,process.stderr.write(l.dim("[Mesh] OS keychain unavailable; storing session fallback in ~/.config/mesh/session.json with 0600 permissions.\n")))}}
@@ -1 +1 @@
1
- import t from"node:fs/promises";import e from"node:path";import s from"node:os";import a from"node:crypto";import{createClient as i}from"@supabase/supabase-js";export class CacheManager{l1BasePath;supabase=null;workspaceHash;pendingL2Writes=new Map;flushTimer=null;constructor(t){this.workspaceHash=a.createHash("md5").update(t.agent.workspaceRoot).digest("hex"),this.l1BasePath=e.join(s.tmpdir(),"mesh-agent-cache",this.workspaceHash),t.agent.enableCloudCache&&t.supabase?.url&&t.supabase?.key&&(this.supabase=i(t.supabase.url,t.supabase.key))}getL1Path(t,s){return e.join(this.l1BasePath,t,`${s}.json`)}async getCapsule(e,s,a,i){const n=this.getL1Path(e,s);try{const e=await t.readFile(n,"utf-8"),s=JSON.parse(e);if(i&&s.contentHash===i)return s;if(!i&&s.mtimeMs===a)return s}catch{}if(this.supabase)try{const{data:t,error:n}=await this.supabase.from("capsules").select("content, mtime, content_hash").eq("workspace_hash",this.workspaceHash).eq("file_path",e).eq("tier",s).maybeSingle();if(t&&!n){const n=i&&t.content_hash===i,r=!i&&Number(t.mtime)===a;if(n||r){const n={content:t.content,capsuleTier:s,mtimeMs:a,contentHash:t.content_hash||i||""};return await this.writeL1(e,s,n),n}}if(i){const{data:t,error:n}=await this.supabase.from("capsules").select("content, mtime, content_hash").eq("content_hash",i).eq("tier",s).limit(1).maybeSingle();if(t&&!n){const n={content:t.content,capsuleTier:s,mtimeMs:a,contentHash:i};return await this.writeL1(e,s,n),n}}}catch{}return null}async setCapsule(t,e,s,a,i){const n={content:s,capsuleTier:e,mtimeMs:a,contentHash:i||""};await this.writeL1(t,e,n),this.supabase&&this.queueL2Write({workspace_hash:this.workspaceHash,file_path:t,tier:e,content:s,mtime:a,content_hash:i||""})}async getCapsuleBatch(e){const s=new Map,a=[];for(const i of e){const e=this.batchKey(i.filePath,i.tier),n=this.getL1Path(i.filePath,i.tier);try{const a=await t.readFile(n,"utf-8"),r=JSON.parse(a),h=i.contentHash&&r.contentHash===i.contentHash,c=!i.contentHash&&r.mtimeMs===i.mtimeMs;if(h||c){s.set(e,r);continue}}catch{}a.push(i)}if(!this.supabase||0===a.length)return s;for(let t=0;t<a.length;t+=100){const e=a.slice(t,t+100),i=Array.from(new Set(e.map(t=>t.filePath))),n=Array.from(new Set(e.map(t=>t.tier)));try{const{data:t,error:a}=await this.supabase.from("capsules").select("file_path, tier, content, mtime, content_hash").eq("workspace_hash",this.workspaceHash).in("file_path",i).in("tier",n);if(a||!Array.isArray(t))continue;const r=new Map(e.map(t=>[this.batchKey(t.filePath,t.tier),t]));for(const e of t){const t=this.batchKey(e.file_path,e.tier),a=r.get(t);if(!a)continue;const i=a.contentHash&&e.content_hash===a.contentHash,n=!a.contentHash&&Number(e.mtime)===a.mtimeMs;if(!i&&!n)continue;const h={content:e.content,capsuleTier:e.tier,mtimeMs:a.mtimeMs,contentHash:e.content_hash||a.contentHash||""};s.set(t,h),await this.writeL1(a.filePath,a.tier,h)}}catch{}}return s}async flushCache(){if(this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=null),!this.supabase||0===this.pendingL2Writes.size)return;const t=Array.from(this.pendingL2Writes.values());this.pendingL2Writes.clear();try{await this.supabase.from("capsules").upsert(t,{onConflict:"workspace_hash,file_path,tier"})}catch{}}async deleteCapsule(e,s){const a=this.getL1Path(e,s);try{await t.unlink(a)}catch{}if(this.supabase)try{await this.supabase.from("capsules").delete().eq("workspace_hash",this.workspaceHash).eq("file_path",e).eq("tier",s)}catch{}}async getSyncStatus(){if(!this.supabase)return{l2Count:0,l2Enabled:!1};try{const{count:t,error:e}=await this.supabase.from("capsules").select("*",{count:"exact",head:!0}).eq("workspace_hash",this.workspaceHash);return{l2Count:t||0,l2Enabled:!0}}catch{return{l2Count:0,l2Enabled:!0}}}async writeL1(s,a,i){try{const n=this.getL1Path(s,a);await t.mkdir(e.dirname(n),{recursive:!0}),await t.writeFile(n,JSON.stringify(i),"utf-8")}catch{}}queueL2Write(t){this.pendingL2Writes.set(this.batchKey(t.file_path,t.tier),t),this.pendingL2Writes.size>=50?this.flushCache():this.flushTimer||(this.flushTimer=setTimeout(()=>{this.flushCache()},500),this.flushTimer.unref?.())}batchKey(t,e){return`${t}\0${e}`}async getSimilarRagQuery(s,a=.95){const i=e.join(this.l1BasePath,"rag_queries.json");try{const e=await t.readFile(i,"utf-8"),n=JSON.parse(e);for(const t of n)if(this.cosine(s,t.queryVector)>=a)return t.results}catch{}return null}async setRagQuery(s,a){const i=e.join(this.l1BasePath,"rag_queries.json");let n=[];try{const e=await t.readFile(i,"utf-8");n=JSON.parse(e)}catch{}n.push({queryVector:s,results:a}),n.length>50&&n.shift(),await t.mkdir(e.dirname(i),{recursive:!0}),await t.writeFile(i,JSON.stringify(n),"utf-8")}cosine(t,e){if(!t||!e||0===t.length||0===e.length||t.length!==e.length)return 0;let s=0;for(let a=0;a<t.length;a++)s+=t[a]*e[a];return s}}
1
+ import t from"node:fs/promises";import e from"node:path";import s from"node:os";import a from"node:crypto";import{createClient as i}from"@supabase/supabase-js";import n from"ws";export class CacheManager{l1BasePath;supabase=null;workspaceHash;pendingL2Writes=new Map;flushTimer=null;constructor(t){this.workspaceHash=a.createHash("md5").update(t.agent.workspaceRoot).digest("hex"),this.l1BasePath=e.join(s.tmpdir(),"mesh-agent-cache",this.workspaceHash),t.agent.enableCloudCache&&t.supabase?.url&&t.supabase?.key&&(this.supabase=i(t.supabase.url,t.supabase.key,{realtime:{transport:n}}))}getL1Path(t,s){return e.join(this.l1BasePath,t,`${s}.json`)}async getCapsule(e,s,a,i){const n=this.getL1Path(e,s);try{const e=await t.readFile(n,"utf-8"),s=JSON.parse(e);if(i&&s.contentHash===i)return s;if(!i&&s.mtimeMs===a)return s}catch{}if(this.supabase)try{const{data:t,error:n}=await this.supabase.from("capsules").select("content, mtime, content_hash").eq("workspace_hash",this.workspaceHash).eq("file_path",e).eq("tier",s).maybeSingle();if(t&&!n){const n=i&&t.content_hash===i,r=!i&&Number(t.mtime)===a;if(n||r){const n={content:t.content,capsuleTier:s,mtimeMs:a,contentHash:t.content_hash||i||""};return await this.writeL1(e,s,n),n}}if(i){const{data:t,error:n}=await this.supabase.from("capsules").select("content, mtime, content_hash").eq("content_hash",i).eq("tier",s).limit(1).maybeSingle();if(t&&!n){const n={content:t.content,capsuleTier:s,mtimeMs:a,contentHash:i};return await this.writeL1(e,s,n),n}}}catch{}return null}async setCapsule(t,e,s,a,i){const n={content:s,capsuleTier:e,mtimeMs:a,contentHash:i||""};await this.writeL1(t,e,n),this.supabase&&this.queueL2Write({workspace_hash:this.workspaceHash,file_path:t,tier:e,content:s,mtime:a,content_hash:i||""})}async getCapsuleBatch(e){const s=new Map,a=[];for(const i of e){const e=this.batchKey(i.filePath,i.tier),n=this.getL1Path(i.filePath,i.tier);try{const a=await t.readFile(n,"utf-8"),r=JSON.parse(a),h=i.contentHash&&r.contentHash===i.contentHash,c=!i.contentHash&&r.mtimeMs===i.mtimeMs;if(h||c){s.set(e,r);continue}}catch{}a.push(i)}if(!this.supabase||0===a.length)return s;for(let t=0;t<a.length;t+=100){const e=a.slice(t,t+100),i=Array.from(new Set(e.map(t=>t.filePath))),n=Array.from(new Set(e.map(t=>t.tier)));try{const{data:t,error:a}=await this.supabase.from("capsules").select("file_path, tier, content, mtime, content_hash").eq("workspace_hash",this.workspaceHash).in("file_path",i).in("tier",n);if(a||!Array.isArray(t))continue;const r=new Map(e.map(t=>[this.batchKey(t.filePath,t.tier),t]));for(const e of t){const t=this.batchKey(e.file_path,e.tier),a=r.get(t);if(!a)continue;const i=a.contentHash&&e.content_hash===a.contentHash,n=!a.contentHash&&Number(e.mtime)===a.mtimeMs;if(!i&&!n)continue;const h={content:e.content,capsuleTier:e.tier,mtimeMs:a.mtimeMs,contentHash:e.content_hash||a.contentHash||""};s.set(t,h),await this.writeL1(a.filePath,a.tier,h)}}catch{}}return s}async flushCache(){if(this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=null),!this.supabase||0===this.pendingL2Writes.size)return;const t=Array.from(this.pendingL2Writes.values());this.pendingL2Writes.clear();try{await this.supabase.from("capsules").upsert(t,{onConflict:"workspace_hash,file_path,tier"})}catch{}}async deleteCapsule(e,s){const a=this.getL1Path(e,s);try{await t.unlink(a)}catch{}if(this.supabase)try{await this.supabase.from("capsules").delete().eq("workspace_hash",this.workspaceHash).eq("file_path",e).eq("tier",s)}catch{}}async getSyncStatus(){if(!this.supabase)return{l2Count:0,l2Enabled:!1};try{const{count:t,error:e}=await this.supabase.from("capsules").select("*",{count:"exact",head:!0}).eq("workspace_hash",this.workspaceHash);return{l2Count:t||0,l2Enabled:!0}}catch{return{l2Count:0,l2Enabled:!0}}}async writeL1(s,a,i){try{const n=this.getL1Path(s,a);await t.mkdir(e.dirname(n),{recursive:!0}),await t.writeFile(n,JSON.stringify(i),"utf-8")}catch{}}queueL2Write(t){this.pendingL2Writes.set(this.batchKey(t.file_path,t.tier),t),this.pendingL2Writes.size>=50?this.flushCache():this.flushTimer||(this.flushTimer=setTimeout(()=>{this.flushCache()},500),this.flushTimer.unref?.())}batchKey(t,e){return`${t}\0${e}`}async getSimilarRagQuery(s,a=.95){const i=e.join(this.l1BasePath,"rag_queries.json");try{const e=await t.readFile(i,"utf-8"),n=JSON.parse(e);for(const t of n)if(this.cosine(s,t.queryVector)>=a)return t.results}catch{}return null}async setRagQuery(s,a){const i=e.join(this.l1BasePath,"rag_queries.json");let n=[];try{const e=await t.readFile(i,"utf-8");n=JSON.parse(e)}catch{}n.push({queryVector:s,results:a}),n.length>50&&n.shift(),await t.mkdir(e.dirname(i),{recursive:!0}),await t.writeFile(i,JSON.stringify(n),"utf-8")}cosine(t,e){if(!t||!e||0===t.length||0===e.length||t.length!==e.length)return 0;let s=0;for(let a=0;a<t.length;a++)s+=t[a]*e[a];return s}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trymesh/cli",
3
- "version": "0.3.22",
3
+ "version": "0.3.23",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Mesh terminal agent CLI. Zero-config: ships with a shared Mesh LLM proxy so no AWS credentials are needed.",
@@ -50,10 +50,11 @@
50
50
  "access": "public"
51
51
  },
52
52
  "optionalDependencies": {
53
- "@trymesh/native": "^0.1.0"
53
+ "@trymesh/native": "^0.1.0",
54
+ "keytar": "^7.9.0"
54
55
  },
55
56
  "dependencies": {
56
- "@supabase/supabase-js": "^2.39.7",
57
+ "@supabase/supabase-js": "^2.105.4",
57
58
  "@xenova/transformers": "^2.17.2",
58
59
  "boxen": "^7.1.1",
59
60
  "dotenv": "^16.4.5",
@@ -71,9 +72,6 @@
71
72
  "ws": "^8.20.0",
72
73
  "z3-solver": "^4.13.0"
73
74
  },
74
- "optionalDependencies": {
75
- "keytar": "^7.9.0"
76
- },
77
75
  "devDependencies": {
78
76
  "@types/marked-terminal": "^6.1.0",
79
77
  "@types/node": "^20.11.24",