<!--
The latest agent sessions on this machine, or in one project's worktrees.
A machine read, filtered by where the sessions ran. Each opens in the
workbench of the worktree it ran in; a session that ran outside every
project has no worktree to open it in, and says so instead of linking.
-->
<script lang="ts">
import { listSessions, type SessionPlaceFilter } from "../../api/client.js";
import type { Session } from "../../api/types.js";
import { formatRelativeTime } from "../../utils/format.js";
import { placeLabel } from "../../utils/places.js";
import { workbench } from "../../stores/workbench.svelte.js";
interface Props {
/** Only sessions that ran here; every session on the machine when absent. */
place?: SessionPlaceFilter;
limit?: number;
}
let { place, limit = 20 }: Props = $props();
let list = $state<Session[]>([]);
let total = $state(0);
let loading = $state(true);
let error = $state<string | null>(null);
async function load(filter: SessionPlaceFilter | undefined, count: number) {
loading = true;
try {
const page = await listSessions({ place: filter, limit: count });
list = page.sessions;
total = page.total;
error = null;
} catch (failure) {
error = failure instanceof Error ? failure.message : String(failure);
} finally {
loading = false;
}
}
$effect(() => {
void load(place, limit);
});
function title(session: Session): string {
return session.display_name?.trim() || session.first_message?.trim() || session.id;
}
</script>
<div class="placed-sessions">
<div class="placed-sessions-head">
<span class="subtle">
{#if loading && list.length === 0}
Reading sessions…
{:else}
Latest {list.length} of {total}
{/if}
</span>
<button class="quiet" disabled={loading} onclick={() => void load(place, limit)}>Refresh</button>
</div>
{#if error}
<p class="placed-sessions-error" role="alert">{error}</p>
{/if}
{#if !loading && list.length === 0 && !error}
<p class="empty">No sessions{place ? ` ran in ${place.project}` : ""} yet.</p>
{/if}
<ul>
{#each list as session (session.id)}
<li>
<!-- Opened in the worktree it ran in, when it ran in one. -->
<button class="session-link" onclick={() => workbench.openSession(session, false)}>
{title(session)}
</button>
<span class="subtle session-place">{placeLabel(session)}</span>
<span class="subtle session-when">{formatRelativeTime(session.ended_at ?? session.started_at)}</span>
</li>
{/each}
</ul>
</div>
<style>
.placed-sessions-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: var(--wb-spacing-6);
font-size: var(--wb-font-size-12);
}
.placed-sessions-error {
color: var(--wb-error);
font-size: var(--wb-font-size-12);
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: flex;
align-items: baseline;
gap: var(--wb-spacing-10);
padding: var(--wb-spacing-4) 0;
border-bottom: 1px solid var(--vscode-panel-border);
font-size: var(--wb-font-size-12);
min-width: 0;
}
.session-link {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left;
}
.session-link {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--vscode-textLink-foreground);
font: inherit;
}
.session-link:hover {
text-decoration: underline;
}
.session-place {
flex-shrink: 0;
font-family: var(--vscode-editor-font-family, monospace);
font-size: var(--wb-font-size-11);
}
.session-when {
flex-shrink: 0;
font-size: var(--wb-font-size-11);
}
</style>