infernoflow 0.38.0 → 0.38.2

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/CHANGELOG.md CHANGED
@@ -208,6 +208,19 @@
208
208
  - v0.37.3 — remove Scarf, zero-dep install, no more Windows hang
209
209
  - v0.37.3 — remove @scarf/scarf to fix Windows install hang
210
210
 
211
+ - v0.38.0 — cloud login + auto-push to Supabase on every log
212
+ - v0.38.0 — cloud login, auto-push to Supabase on every log
213
+ - v0.37.4
214
+ - v0.37.3 — remove Scarf, zero-dep install, no more Windows hang
215
+ - v0.37.3 — remove @scarf/scarf to fix Windows install hang
216
+
217
+ - v0.38.1
218
+ - v0.38.0 — cloud login + auto-push to Supabase on every log
219
+ - v0.38.0 — cloud login, auto-push to Supabase on every log
220
+ - v0.37.4
221
+ - v0.37.3 — remove Scarf, zero-dep install, no more Windows hang
222
+ - v0.37.3 — remove @scarf/scarf to fix Windows install hang
223
+
211
224
  ## 0.10.25 — 2026-04-22
212
225
 
213
226
  ### Added
@@ -1 +1 @@
1
- import*as A from"node:https";const s=process.env.INFERNOFLOW_SUPABASE_URL||"https://YOUR_PROJECT.supabase.co",f=process.env.INFERNOFLOW_SUPABASE_ANON_KEY||"YOUR_ANON_KEY";function i(t,e,r,n){return new Promise((h,l)=>{const c=new URL(e),a=r?JSON.stringify(r):null,d={hostname:c.hostname,port:443,path:c.pathname+c.search,method:t,headers:{"Content-Type":"application/json",Accept:"application/json","User-Agent":"infernoflow-cli",apikey:f,...n,...a?{"Content-Length":Buffer.byteLength(a)}:{}}},o=A.request(d,u=>{let p="";u.on("data",m=>p+=m),u.on("end",()=>{try{h({status:u.statusCode,body:JSON.parse(p)})}catch{h({status:u.statusCode,body:p})}})});o.on("error",l),o.setTimeout(8e3,()=>{o.destroy(new Error("timeout"))}),a&&o.write(a),o.end()})}async function y(t,e,r){try{const n={project_id:r,ts:t.ts,type:t.type||"note",summary:t.summary,result:t.result||null,source:t.source||null,auto:t.auto||!1,agent:t.agent||null};await i("POST",`${s}/rest/v1/entries`,n,{Authorization:`Bearer ${e}`,Prefer:"return=minimal"})}catch{}}async function S(t){return await i("POST",`${s}/auth/v1/token?grant_type=pkce`,{auth_code:t},{})}function _(t,e){const r=new URLSearchParams({provider:"github",redirect_to:e,state:t});return`${s}/auth/v1/authorize?${r.toString()}`}async function E(t){const e=await i("GET",`${s}/auth/v1/user`,null,{Authorization:`Bearer ${t}`});return e.status===200?e.body:null}async function O(t,e){const r=new URLSearchParams({project_id:`eq.${e}`,order:"ts.asc",limit:"10000"}),n=await i("GET",`${s}/rest/v1/entries?${r.toString()}`,null,{Authorization:`Bearer ${t}`});return n.status===200&&Array.isArray(n.body)?n.body:[]}export{f as SUPABASE_ANON_KEY,s as SUPABASE_URL,S as exchangeCodeForSession,_ as getOAuthUrl,E as getUser,O as pullEntries,y as pushEntry};
1
+ import*as m from"node:https";const n=process.env.INFERNOFLOW_SUPABASE_URL||"https://vscesbbtmrsctfroigyx.supabase.co",f=process.env.INFERNOFLOW_SUPABASE_ANON_KEY||"sb_publishable_yThoZzOisgqLxrH8BOli-Q_yHVqEhUk";function i(t,e,r,s){return new Promise((h,l)=>{const c=new URL(e),a=r?JSON.stringify(r):null,y={hostname:c.hostname,port:443,path:c.pathname+c.search,method:t,headers:{"Content-Type":"application/json",Accept:"application/json","User-Agent":"infernoflow-cli",apikey:f,...s,...a?{"Content-Length":Buffer.byteLength(a)}:{}}},o=m.request(y,u=>{let p="";u.on("data",d=>p+=d),u.on("end",()=>{try{h({status:u.statusCode,body:JSON.parse(p)})}catch{h({status:u.statusCode,body:p})}})});o.on("error",l),o.setTimeout(8e3,()=>{o.destroy(new Error("timeout"))}),a&&o.write(a),o.end()})}async function A(t,e,r){try{const s={project_id:r,ts:t.ts,type:t.type||"note",summary:t.summary,result:t.result||null,source:t.source||null,auto:t.auto||!1,agent:t.agent||null};await i("POST",`${n}/rest/v1/entries`,s,{Authorization:`Bearer ${e}`,Prefer:"return=minimal"})}catch{}}async function S(t){return await i("POST",`${n}/auth/v1/token?grant_type=pkce`,{auth_code:t},{})}function _(t,e){const r=new URLSearchParams({provider:"github",redirect_to:e,state:t});return`${n}/auth/v1/authorize?${r.toString()}`}async function g(t){const e=await i("GET",`${n}/auth/v1/user`,null,{Authorization:`Bearer ${t}`});return e.status===200?e.body:null}async function E(t,e){const r=new URLSearchParams({project_id:`eq.${e}`,order:"ts.asc",limit:"10000"}),s=await i("GET",`${n}/rest/v1/entries?${r.toString()}`,null,{Authorization:`Bearer ${t}`});return s.status===200&&Array.isArray(s.body)?s.body:[]}export{f as SUPABASE_ANON_KEY,n as SUPABASE_URL,S as exchangeCodeForSession,_ as getOAuthUrl,g as getUser,E as pullEntries,A as pushEntry};
@@ -1,30 +1,12 @@
1
- import*as k from"node:http";import*as L from"node:crypto";import"node:fs";import"node:path";import{bold as i,cyan as r,gray as t,green as g,red as y,yellow as x}from"../ui/output.mjs";import{readCredentials as _,writeCredentials as A,deleteCredentials as O,isLoggedIn as $}from"../cloud/credentials.mjs";import{getOAuthUrl as C,getUser as P,SUPABASE_URL as T}from"../cloud/supabase.mjs";const u=9242,w="/auth/callback",v=`http://localhost:${u}${w}`;function E(e){try{const{execSync:s}=require("child_process"),l=process.platform==="win32"?`start "" "${e}"`:process.platform==="darwin"?`open "${e}"`:`xdg-open "${e}"`;s(l,{stdio:"ignore"})}catch{}}async function U(){if(T.includes("YOUR_PROJECT")&&(console.log(),console.log(` ${y("\u2718")} Supabase not configured yet.`),console.log(),console.log(" Set up your Supabase project first:"),console.log(` ${t("1.")} Create a project at ${r("https://supabase.com")}`),console.log(` ${t("2.")} Run ${r("scripts/supabase-schema.sql")} in the SQL editor`),console.log(` ${t("3.")} Enable GitHub OAuth in Authentication \u2192 Providers`),console.log(` ${t("4.")} Set ${r("INFERNOFLOW_SUPABASE_URL")} and ${r("INFERNOFLOW_SUPABASE_ANON_KEY")}`),console.log(" (or hardcode them in lib/cloud/supabase.mjs)"),console.log(),process.exit(1)),$()){const n=_()?.user;console.log(),console.log(` ${g("\u2714")} Already logged in as ${i(n?.email||n?.user_metadata?.user_name||"unknown")}`),console.log(` Run ${r("infernoflow logout")} to sign out.`),console.log();return}const e=L.randomBytes(16).toString("hex");console.log(),console.log(` ${i("\u{1F525} infernoflow login")}`),console.log();let s,l;const d=new Promise((o,n)=>{s=o,l=n}),a=k.createServer((o,n)=>{if(new URL(o.url,`http://localhost:${u}`).pathname!==w){n.writeHead(404),n.end("Not found");return}if(o.method==="GET"){n.writeHead(200,{"Content-Type":"text/html"}),n.end(`<!DOCTYPE html>
2
- <html>
3
- <head><meta charset="utf-8"><title>infernoflow login</title>
4
- <style>body{font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#f1f5f9}</style>
1
+ import*as k from"node:http";import*as _ from"node:crypto";import*as x from"node:https";import"node:fs";import"node:path";import{bold as u,cyan as h,gray as c,green as p,red as $,yellow as P}from"../ui/output.mjs";import{readCredentials as b,writeCredentials as A,deleteCredentials as O,isLoggedIn as S}from"../cloud/credentials.mjs";import{getUser as T,SUPABASE_URL as y,SUPABASE_ANON_KEY as E}from"../cloud/supabase.mjs";const w=9242,C="/auth/callback",U=`http://localhost:${w}${C}`;function R(o){try{const{execSync:s}=require("child_process"),r=process.platform==="win32"?`start "" "${o}"`:process.platform==="darwin"?`open "${o}"`:`xdg-open "${o}"`;s(r,{stdio:"ignore"})}catch{}}function D(){const o=_.randomBytes(32).toString("base64url"),s=_.createHash("sha256").update(o).digest("base64url");return{verifier:o,challenge:s}}function B(o,s){return new Promise((r,a)=>{const i=JSON.stringify({auth_code:o,code_verifier:s}),l=new URL(`${y}/auth/v1/token?grant_type=pkce`),f={hostname:l.hostname,port:443,path:l.pathname+l.search,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(i),apikey:E,"User-Agent":"infernoflow-cli"}},t=x.request(f,e=>{let n="";e.on("data",g=>n+=g),e.on("end",()=>{try{r({status:e.statusCode,body:JSON.parse(n)})}catch{r({status:e.statusCode,body:n})}})});t.on("error",a),t.write(i),t.end()})}async function I(){if(y.includes("YOUR_PROJECT")&&(console.log(),console.log(` ${$("\u2718")} Supabase not configured yet.`),console.log(),process.exit(1)),S()){const e=b()?.user;console.log(),console.log(` ${p("\u2714")} Already logged in as ${u(e?.email||e?.user_metadata?.user_name||"unknown")}`),console.log(` Run ${h("infernoflow logout")} to sign out.`),console.log();return}const{verifier:o,challenge:s}=D();console.log(),console.log(` ${u("\u{1F525} infernoflow login")}`),console.log();let r,a;const i=new Promise((t,e)=>{r=t,a=e}),l=k.createServer((t,e)=>{const n=new URL(t.url,`http://localhost:${w}`);if(n.pathname!==C){e.writeHead(404),e.end("Not found");return}const m=n.searchParams.get("code"),d=n.searchParams.get("error_description")||n.searchParams.get("error");e.writeHead(200,{"Content-Type":"text/html"}),m?(e.end(`<!DOCTYPE html><html>
2
+ <head><meta charset="utf-8"><title>infernoflow</title>
3
+ <style>body{font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#f1f5f9;text-align:center}</style>
5
4
  </head>
6
- <body>
7
- <script>
8
- const hash = window.location.hash.slice(1);
9
- const params = new URLSearchParams(hash);
10
- const access_token = params.get('access_token');
11
- const refresh_token = params.get('refresh_token');
12
- const expires_in = params.get('expires_in');
13
- const error = params.get('error_description') || params.get('error');
14
- if (access_token) {
15
- fetch('/auth/callback', {
16
- method: 'POST',
17
- headers: {'Content-Type': 'application/json'},
18
- body: JSON.stringify({ access_token, refresh_token, expires_in })
19
- }).then(() => {
20
- document.body.innerHTML = '<div style="text-align:center"><div style="font-size:48px">\u{1F525}</div><h2>Logged in!</h2><p style="color:#94a3b8">You can close this tab and return to the terminal.</p></div>';
21
- });
22
- } else if (error) {
23
- document.body.innerHTML = '<div style="text-align:center"><h2>Login failed</h2><p style="color:#f87171">' + error + '</p></div>';
24
- fetch('/auth/callback', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ error }) });
25
- } else {
26
- document.body.innerHTML = '<div style="text-align:center"><p style="color:#94a3b8">Processing\u2026</p></div>';
27
- }
28
- </script>
29
- </body>
30
- </html>`);return}if(o.method==="POST"){let h="";o.on("data",c=>h+=c),o.on("end",()=>{n.writeHead(200),n.end("ok"),a.close();try{const c=JSON.parse(h);c.error?l(new Error(c.error)):s(c)}catch(c){l(c)}})}});a.listen(u,"127.0.0.1",()=>{const o=C(e,v);console.log(" Opening browser for GitHub login\u2026"),console.log(),console.log(` ${t("If the browser doesn't open, visit:")}`),console.log(` ${r(o)}`),console.log(),E(o),console.log(` ${t("Waiting for login\u2026")} ${t("(Ctrl+C to cancel)")}`)});const m=setTimeout(()=>{a.close(),l(new Error("Login timed out after 3 minutes"))},180*1e3);try{const o=await d;clearTimeout(m);const n=await P(o.access_token),f={access_token:o.access_token,refresh_token:o.refresh_token||null,expires_at:o.expires_in?new Date(Date.now()+parseInt(o.expires_in)*1e3).toISOString():null,user:n,logged_in_at:new Date().toISOString()};A(f);const p=n?.user_metadata?.user_name||n?.email||"unknown";console.log(),console.log(` ${g("\u2714")} Logged in as ${i(p)}`),console.log(),console.log(` ${t("Session memory will now sync to the cloud on every")} ${r("infernoflow log")}`),console.log()}catch(o){clearTimeout(m),a.close(),console.log(),console.log(` ${y("\u2718")} Login failed: ${o.message}`),console.log(),process.exit(1)}}function S(){const e=O();console.log(),console.log(e?` ${g("\u2714")} Logged out. Local credentials removed.`:` ${t("Already logged out.")}`),console.log()}async function b(){const e=_();if(console.log(),!e?.access_token){console.log(` ${t("Not logged in.")} Run ${r("infernoflow login")}`),console.log();return}const s=e.user?.user_metadata?.user_name||e.user?.email||"unknown",l=e.user?.email||t("(no email)"),d=e.logged_in_at?new Date(e.logged_in_at).toLocaleDateString():"unknown",a=!$();console.log(` ${i("\u{1F525} infernoflow")} \u2014 logged in as:`),console.log(),console.log(` User: ${i(s)}`),console.log(` Email: ${l}`),console.log(` Since: ${t(d)}`),console.log(a?` Status: ${x("\u26A0 Token expired \u2014 run infernoflow login to refresh")}`:` Status: ${g("\u2714 Active")}`),console.log()}async function D(e){const s=e[1];return s==="logout"?S():s==="whoami"?b():U()}async function Y(){return S()}async function F(){return b()}export{D as loginCommand,Y as logoutCommand,F as whoamiCommand};
5
+ <body><div><div style="font-size:48px">\u{1F525}</div><h2>Logged in!</h2><p style="color:#94a3b8">You can close this tab and return to the terminal.</p></div></body>
6
+ </html>`),l.close(),r(m)):d?(e.end(`<!DOCTYPE html><html>
7
+ <head><meta charset="utf-8"><title>infernoflow</title>
8
+ <style>body{font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#f1f5f9;text-align:center}</style>
9
+ </head>
10
+ <body><div><h2>Login failed</h2><p style="color:#f87171">${d}</p></div></body>
11
+ </html>`),l.close(),a(new Error(d))):e.end(`<!DOCTYPE html><html><body style="background:#0f172a;color:#f1f5f9;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0">
12
+ <p>Processing\u2026</p></body></html>`)});l.listen(w,"127.0.0.1",()=>{const t=new URLSearchParams({provider:"github",redirect_to:U,code_challenge:s,code_challenge_method:"S256"}),e=`${y}/auth/v1/authorize?${t.toString()}`;console.log(" Opening browser for GitHub login\u2026"),console.log(),console.log(` ${c("If the browser doesn't open, visit:")}`),console.log(` ${h(e)}`),console.log(),R(e),console.log(` ${c("Waiting for login\u2026")} ${c("(Ctrl+C to cancel)")}`)});const f=setTimeout(()=>{l.close(),a(new Error("Login timed out after 3 minutes"))},180*1e3);try{const t=await i;clearTimeout(f);const e=await B(t,o);if(e.status!==200||!e.body?.access_token)throw new Error(e.body?.error_description||e.body?.message||`Auth failed (${e.status})`);const n=e.body,g=await T(n.access_token),m={access_token:n.access_token,refresh_token:n.refresh_token||null,expires_at:n.expires_in?new Date(Date.now()+parseInt(n.expires_in)*1e3).toISOString():null,user:g,logged_in_at:new Date().toISOString()};A(m);const d=g?.user_metadata?.user_name||g?.email||"unknown";console.log(),console.log(` ${p("\u2714")} Logged in as ${u(d)}`),console.log(),console.log(` ${c("Session memory will now sync to the cloud on every")} ${h("infernoflow log")}`),console.log()}catch(t){clearTimeout(f);try{l.close()}catch{}console.log(),console.log(` ${$("\u2718")} Login failed: ${t.message}`),console.log(),process.exit(1)}}function v(){const o=O();console.log(),console.log(o?` ${p("\u2714")} Logged out. Local credentials removed.`:` ${c("Already logged out.")}`),console.log()}async function L(){const o=b();if(console.log(),!o?.access_token){console.log(` ${c("Not logged in.")} Run ${h("infernoflow login")}`),console.log();return}const s=o.user?.user_metadata?.user_name||o.user?.email||"unknown",r=o.user?.email||c("(no email)"),a=o.logged_in_at?new Date(o.logged_in_at).toLocaleDateString():"unknown",i=!S();console.log(` ${u("\u{1F525} infernoflow")} \u2014 logged in as:`),console.log(),console.log(` User: ${u(s)}`),console.log(` Email: ${r}`),console.log(` Since: ${c(a)}`),console.log(i?` Status: ${P("\u26A0 Token expired \u2014 run infernoflow login to refresh")}`:` Status: ${p("\u2714 Active")}`),console.log()}async function q(o){const s=o[1];return s==="logout"?v():s==="whoami"?L():I()}async function J(){return v()}async function z(){return L()}export{q as loginCommand,J as logoutCommand,z as whoamiCommand};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infernoflow",
3
- "version": "0.38.0",
3
+ "version": "0.38.2",
4
4
  "description": "Persistent memory for AI coding sessions — captures what agents can't infer from code alone. Works with Copilot, Cursor, Claude, and Windsurf.",
5
5
  "type": "module",
6
6
  "bin": {