diff --git a/engraphis/static/index.html b/engraphis/static/index.html index e81269e..922f67d 100644 --- a/engraphis/static/index.html +++ b/engraphis/static/index.html @@ -305,6 +305,7 @@
Store
+
🤖 Connect your agent
Loading…
@@ -557,7 +558,12 @@ /* health + settings */ async function checkHealth(){try{await api('/health');const d=document.getElementById('health-dot'),t=document.getElementById('health-text');if(d)d.style.background='var(--green)';if(t)t.textContent='Connected'}catch(e){const d=document.getElementById('health-dot'),t=document.getElementById('health-text');if(d)d.style.background='var(--red)';if(t)t.textContent='Offline'}} -function loadSettings(){loadLicense();loadSyncStatus();const s=document.getElementById('cfg-store');if(s)s.textContent=location.host} +function loadSettings(){loadLicense();loadSyncStatus();loadApiTokens();const s=document.getElementById('cfg-store');if(s)s.textContent=location.host} + +async function renderTokList(){try{const toks=(await api('/auth/tokens')).tokens||[];const el=document.getElementById('tok-list');if(!el)return;el.innerHTML=toks.length?toks.map(t=>`
${esc(t.label||'(unlabelled)')} · ${t.revoked?'revoked':fmtRel(t.created_at)}${t.last_used_at?' · used '+fmtRel(t.last_used_at):''}${t.revoked?'':``}
`).join(''):'
No tokens yet.
'}catch(e){}} +async function loadApiTokens(){const el=document.getElementById('tokens-body');if(!el)return;try{const st=await api('/auth/state');if(!st.enabled||!st.user){el.innerHTML='
Team mode is off — activate a Team license and sign in to connect agents to this instance.
';return}let ci={};try{ci=await api('/auth/connect-info')}catch(e){}const base=ci.api_base||(API||'');el.innerHTML=`
Point an agent at this instance with a per-user bearer token (hashed at rest; shown once). POST ${esc(base)}/remember · GET ${esc(base)}/recall
Your tokens
`;renderTokList()}catch(e){el.innerHTML='
'+esc(e.message)+'
'}} +async function createApiToken(){const label=(document.getElementById('tok-label').value||'').trim();try{const d=await api('/auth/token',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({label})});document.getElementById('tok-created').innerHTML=`
Copy this token now — it won't be shown again:
${esc(d.token)}
Add to your agent config: Authorization: Bearer ${esc(d.token)}
`;document.getElementById('tok-label').value='';renderTokList()}catch(e){toast('Token: '+e.message,'err')}} +async function revokeApiToken(id){if(!confirm('Revoke this token? Agents using it will stop working immediately.'))return;try{await api('/auth/token/'+id,{method:'DELETE'});toast('Token revoked','ok');renderTokList()}catch(e){toast(e.message,'err')}} async function loadSyncStatus(){try{const d=await api('/sync/status');renderSync(d);if(d&&d.available)loadAutoSync()}catch(e){const el=document.getElementById('sync-body');if(el)el.textContent='Cloud sync is unavailable right now.'}} function renderSync(d){const el=document.getElementById('sync-body');if(!el)return;if(!d||!d.available){el.innerHTML=`
Sync your memories to the cloud and pull them on any device — just sign in with your license key.
No key yet? Start a free 3-day trial or get ${esc((d&&d.tier_required)||'pro')} →
`;return}const last=d.last;let status='Not synced yet on this device.';if(last){const when=new Date((last.at||0)*1000).toLocaleString();status='Last synced '+when+' — pushed '+(last.exported||0)+', +'+(last.added||0)+' new from your other devices'+((last.errors&&last.errors.length)?' · '+last.errors.length+' issue(s)':'')+'.'}el.innerHTML=`
Status${esc((d.plan||'pro').toUpperCase())} · sync on
Your memories sync to the cloud. On another device: install Engraphis, open this dashboard, sign in with the same license key, and click Sync — everything downloads automatically.
${esc(status)}
`} async function signInSync(){const i=document.getElementById('sync-key');const k=i?i.value.trim():'';if(!k){toast('Paste your license key','err');return}try{const d=await api('/license/activate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({key:k})});LIC=d;try{updateLicBadge();updateFeatureLocks()}catch(e){}if((!d.plan||d.plan==='free')&&d.error){toast('Key accepted but not active — '+d.error,'err')}else{toast('Signed in — '+(d.plan||'').toUpperCase()+' plan','ok')}await loadSyncStatus();try{loadLicense()}catch(e){}}catch(e){toast('Sign-in failed: '+e.message,'err')}}