fix: per-persona session/file isolation + onboarding route order
- session_store: store sessions under home/{user}/persona/{name}/session_data/
instead of the shared cortex/data/sessions/ bucket
- chat endpoints: add user/persona query params to /sessions, /history/*,
/sessions/*, /note so they resolve the correct persona context
- files router: add user/persona query params to /files and /files/{name}
so the file browser loads the right persona's files
- app.js: pass user/persona on all session, history, and file fetches;
move _fileParams to top-level scope so it is available everywhere
- onboarding: fix FastAPI route ordering — register /persona before /{token}
so the literal path wins and does not get captured as a token value
- ui.py: read Emoji field from IDENTITY.md and inject into CORTEX_CONFIG
so the header icon reflects each persona's chosen emoji
- .gitignore: exclude home/**/session_data/ (runtime state)
- migrate scott/inara sessions from cortex/data/sessions/ to session_data/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,10 @@
|
||||
// User/persona injected by the server at /{user}/{persona}
|
||||
const CORTEX_USER = (window.CORTEX_CONFIG || {}).user || 'scott';
|
||||
const CORTEX_PERSONA = (window.CORTEX_CONFIG || {}).persona || 'inara';
|
||||
const CORTEX_EMOJI = (window.CORTEX_CONFIG || {}).emoji || '✨';
|
||||
const _fileParams = `user=${encodeURIComponent(CORTEX_USER)}&persona=${encodeURIComponent(CORTEX_PERSONA)}`;
|
||||
|
||||
if (headerEmoji) headerEmoji.textContent = CORTEX_EMOJI;
|
||||
|
||||
let sessionId = null;
|
||||
let primaryBackend = 'claude';
|
||||
@@ -219,7 +223,7 @@
|
||||
sessionsPanel.classList.remove('open');
|
||||
return;
|
||||
}
|
||||
const res = await fetch('/sessions');
|
||||
const res = await fetch(`/sessions?${_fileParams}`);
|
||||
const data = await res.json();
|
||||
renderPanel(data.sessions);
|
||||
sessionsPanel.classList.add('open');
|
||||
@@ -268,7 +272,7 @@
|
||||
delBtn.title = 'Delete session';
|
||||
delBtn.addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
await fetch(`/sessions/${s.session_id}`, { method: 'DELETE' });
|
||||
await fetch(`/sessions/${s.session_id}?${_fileParams}`, { method: 'DELETE' });
|
||||
if (sessionId === s.session_id) {
|
||||
sessionId = null;
|
||||
currentHistory = [];
|
||||
@@ -276,7 +280,7 @@
|
||||
sessionEl.textContent = '';
|
||||
addMessage('system', 'Session deleted');
|
||||
}
|
||||
const res = await fetch('/sessions');
|
||||
const res = await fetch(`/sessions?${_fileParams}`);
|
||||
const data = await res.json();
|
||||
renderPanel(data.sessions);
|
||||
});
|
||||
@@ -307,7 +311,7 @@
|
||||
async function resumeSession(id) {
|
||||
talkThinkingDiv = null;
|
||||
if (id && id.startsWith('nct_')) sessionsBtn.classList.remove('talk-badge');
|
||||
const res = await fetch(`/history/${id}`);
|
||||
const res = await fetch(`/history/${id}?${_fileParams}`);
|
||||
const data = await res.json();
|
||||
|
||||
messagesEl.innerHTML = '';
|
||||
@@ -524,7 +528,7 @@
|
||||
async function syncHistory() {
|
||||
if (!sessionId) return;
|
||||
try {
|
||||
await fetch(`/history/${sessionId}`, {
|
||||
await fetch(`/history/${sessionId}?${_fileParams}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ messages: currentHistory }),
|
||||
@@ -856,7 +860,7 @@
|
||||
}
|
||||
|
||||
async function loadFile(name) {
|
||||
const res = await fetch(`/files/${encodeURIComponent(name)}`);
|
||||
const res = await fetch(`/files/${encodeURIComponent(name)}?${_fileParams}`);
|
||||
if (!res.ok) { fileEditor.value = `Error loading ${name}`; return; }
|
||||
const data = await res.json();
|
||||
fileEditor.value = data.content;
|
||||
@@ -866,7 +870,7 @@
|
||||
|
||||
async function openFileModal() {
|
||||
// Populate the file list
|
||||
const res = await fetch('/files');
|
||||
const res = await fetch(`/files?${_fileParams}`);
|
||||
const data = await res.json();
|
||||
fileSelect.innerHTML = '';
|
||||
for (const f of data.files) {
|
||||
@@ -888,7 +892,7 @@
|
||||
|
||||
fileSaveBtn.addEventListener('click', async () => {
|
||||
const name = fileSelect.value;
|
||||
const res = await fetch(`/files/${encodeURIComponent(name)}`, {
|
||||
const res = await fetch(`/files/${encodeURIComponent(name)}?${_fileParams}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ content: fileEditor.value }),
|
||||
@@ -1154,7 +1158,7 @@
|
||||
helpBody.textContent = 'Loading…';
|
||||
helpModal.classList.add('open');
|
||||
try {
|
||||
const res = await fetch('/files/HELP.md');
|
||||
const res = await fetch(`/files/HELP.md?${_fileParams}`);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data = await res.json();
|
||||
helpBody.innerHTML = marked.parse(data.content);
|
||||
|
||||
Reference in New Issue
Block a user