This commit is contained in:
Timothy Jaeryang Baek
2026-03-29 21:01:10 -05:00
parent 4777f4fa32
commit a06685a47b
8 changed files with 86 additions and 36 deletions
+2 -2
View File
@@ -362,7 +362,7 @@
onClose={() => showControls.set(false)}
/>
{:else if activeTab === 'files' && $selectedTerminalId}
<FileNav onAttach={handleTerminalAttach} />
<FileNav onAttach={handleTerminalAttach} {chatId} />
{:else if activeTab === 'files' && codeInterpreterEnabled}
<PyodideFileNav />
{:else}
@@ -513,7 +513,7 @@
onClose={() => showControls.set(false)}
/>
{:else if activeTab === 'files' && $selectedTerminalId}
<FileNav onAttach={handleTerminalAttach} overlay={dragged} />
<FileNav onAttach={handleTerminalAttach} overlay={dragged} {chatId} />
{:else if activeTab === 'files' && codeInterpreterEnabled}
<PyodideFileNav overlay={dragged} />
{:else}
+47 -19
View File
@@ -49,6 +49,7 @@
export let onAttach: ((blob: Blob, name: string, contentType: string) => void) | null = null;
export let overlay = false;
export let chatId: string | null = null;
// ── Terminal panel state ────────────────────────────────────────────
let terminalExpanded = false;
@@ -215,30 +216,48 @@
return url ? { url, key } : null;
};
// Detect terminal changes — the explicit store references ensure
// Detect terminal or chat changes — the explicit store references ensure
// Svelte re-runs this block when any of them update.
// The `mounted` flag prevents the initial run from racing with onMount.
let prevTerminalUrl = '';
let prevChatId = chatId;
let mounted = false;
$: {
($selectedTerminalId, $terminalServers, $settings);
const terminal = getTerminal();
selectedTerminal = terminal;
if (terminal && terminal.url !== prevTerminalUrl) {
prevTerminalUrl = terminal.url;
loading = true;
error = null;
entries = [];
(async () => {
// Discover server features (terminal enabled/disabled)
const config = await getTerminalConfig(terminal.url, terminal.key);
terminalEnabled = config?.features?.terminal !== false;
const chatChanged = chatId !== prevChatId;
const oldChatId = prevChatId;
if (chatChanged) prevChatId = chatId;
const rawCwd = await getCwd(terminal.url, terminal.key);
const cwd = rawCwd ? normalizePath(rawCwd) : null;
const dir = cwd ? (cwd.endsWith('/') ? cwd : cwd + '/') : '/';
savedPath = dir;
loadDir(dir);
})();
const terminalChanged = terminal && terminal.url !== prevTerminalUrl;
if (terminalChanged) prevTerminalUrl = terminal.url;
if (mounted && terminal) {
if (chatChanged && chatId && !oldChatId) {
// Chat just got created (null → real ID): persist the current
// browsed path as the new session's cwd — don't re-fetch.
setCwd(terminal.url, terminal.key, savedPath, chatId);
} else if (terminalChanged || chatChanged) {
// Terminal switched, new chat started, or switched between
// existing chats — re-fetch the session cwd.
loading = true;
error = null;
entries = [];
(async () => {
if (terminalChanged) {
const config = await getTerminalConfig(terminal.url, terminal.key);
terminalEnabled = config?.features?.terminal !== false;
}
const rawCwd = await getCwd(terminal.url, terminal.key, chatId ?? undefined);
const cwd = rawCwd ? normalizePath(rawCwd) : null;
const dir = cwd ? (cwd.endsWith('/') ? cwd : cwd + '/') : '/';
savedPath = dir;
loadDir(dir);
})();
}
}
}
@@ -316,7 +335,7 @@
loading = false;
// Set working directory on the terminal server (fire-and-forget)
setCwd(terminal.url, terminal.key, path);
setCwd(terminal.url, terminal.key, path, chatId ?? undefined);
if (result === null) {
error =
@@ -736,14 +755,22 @@
if (!handledDisplayFile) {
loading = true;
if (savedPath === '/') {
const rawCwd = await getCwd(terminal.url, terminal.key);
// Discover server features on initial mount
const config = await getTerminalConfig(terminal.url, terminal.key);
terminalEnabled = config?.features?.terminal !== false;
if (chatId || savedPath === '/') {
// Fetch session-specific cwd from the server (or global default for new chats)
const rawCwd = await getCwd(terminal.url, terminal.key, chatId ?? undefined);
const cwd = rawCwd ? normalizePath(rawCwd) : null;
if (cwd) savedPath = cwd.endsWith('/') ? cwd : cwd + '/';
}
loadDir(savedPath);
}
mounted = true;
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Shift') shiftKey = true;
};
@@ -1368,6 +1395,7 @@
overlay={overlay || isDraggingHandle}
bind:connected={terminalConnected}
bind:connecting={terminalConnecting}
{chatId}
/>
</div>
{/if}
+7 -2
View File
@@ -12,6 +12,7 @@
const i18n = getContext('i18n');
export let overlay = false;
export let chatId: string | null = null;
let terminalEl: HTMLDivElement;
let term: Terminal | null = null;
@@ -67,9 +68,11 @@
authToken = apiKey;
// Create session
const createHeaders: Record<string, string> = { Authorization: `Bearer ${apiKey}` };
if (chatId) createHeaders['X-Session-Id'] = chatId;
const res = await fetch(`${base}/api/terminals`, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` }
headers: createHeaders
});
if (!res.ok) throw new Error(`Failed to create session: ${res.status}`);
const session = await res.json();
@@ -83,9 +86,11 @@
authToken = token;
// Create session via proxy
const proxyHeaders: Record<string, string> = { Authorization: `Bearer ${token}` };
if (chatId) proxyHeaders['X-Session-Id'] = chatId;
const res = await fetch(`${base}/terminals/${info.serverId}/api/terminals`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` }
headers: proxyHeaders
});
if (!res.ok) throw new Error(`Failed to create session: ${res.status}`);
const session = await res.json();