collet 0.1.0

Relentless agentic coding orchestrator with zero-drop agent loops
Documentation
<script lang="ts">
	import { layoutStore } from '$lib/stores/layout.svelte.js';
	import { appStore } from '$lib/store.svelte.js';
	import { projectsStore } from '$lib/stores/projects.svelte.js';
	import { sessionsStore } from '$lib/stores/sessions.svelte.js';
	import ProjectList from '../sidebar/ProjectList.svelte';
	import DirectoryBrowser from '../sidebar/DirectoryBrowser.svelte';
	import SessionList from '../sidebar/SessionList.svelte';

	let switching = $state(false);

	function token(): string | undefined {
		return appStore.authToken ?? undefined;
	}

	async function handleProjectSwitch(workingDir: string) {
		if (switching) return;
		switching = true;
		try {
			await projectsStore.switchTo(workingDir, token());
			appStore.reset();
			sessionsStore.clearSelection();
			await sessionsStore.load(token());
		} finally {
			switching = false;
		}
	}

	async function handleBrowseSelect(path: string) {
		if (switching) return;
		switching = true;
		projectsStore.closeBrowser();
		try {
			await projectsStore.switchTo(path, token());
			appStore.reset();
			sessionsStore.clearSelection();
			await sessionsStore.load(token());
		} finally {
			switching = false;
		}
	}

	function handleNewSession() {
		appStore.reset();
		sessionsStore.clearSelection();
	}
</script>

{#if layoutStore.leftSidebarOpen}
	<aside class="left-sidebar">
		<!-- Project header -->
		<div class="section-header">
			<span class="section-title">Projects</span>
			<button
				class="icon-btn"
				onclick={() => projectsStore.openBrowser(token())}
				aria-label="Add project"
				title="Add project"
			>+</button>
		</div>

		<!-- Directory browser (inline) -->
		{#if projectsStore.browseMode}
			<DirectoryBrowser
				onselect={handleBrowseSelect}
				onclose={() => projectsStore.closeBrowser()}
			/>
		{/if}

		<!-- Project list -->
		<div class="project-list-wrap">
			<ProjectList onswitch={handleProjectSwitch} />
		</div>

		<!-- New Session -->
		<div class="new-session-wrap">
			<button class="new-session-btn" onclick={handleNewSession}>
				+ New Session
			</button>
		</div>

		<!-- Session list -->
		<div class="session-list-wrap">
			<SessionList />
		</div>

		<!-- Footer -->
		<div class="sidebar-footer">
			{#if appStore.serverVersion}
				<span class="version">v{appStore.serverVersion}</span>
			{/if}
		</div>
	</aside>
{/if}

<style>
	.left-sidebar {
		width: var(--left-w, 240px);
		flex-shrink: 0;
		background: var(--bg-surface);
		border-right: 1px solid var(--border);
		display: flex;
		flex-direction: column;
		overflow: hidden;
		font-family: var(--font-mono);
	}

	.section-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 0.375rem 0.5rem;
		border-bottom: 1px solid var(--border);
		flex-shrink: 0;
	}

	.section-title {
		font-size: 0.75rem;
		font-weight: 700;
		color: var(--fg-bright);
	}

	.icon-btn {
		all: unset;
		cursor: pointer;
		color: var(--fg-dim);
		width: 1.25rem;
		height: 1.25rem;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 0.875rem;
	}

	.icon-btn:hover {
		color: var(--fg);
	}

	.project-list-wrap {
		max-height: 160px;
		overflow-y: auto;
		border-bottom: 1px solid var(--border);
		flex-shrink: 0;
	}

	.new-session-wrap {
		padding: 0.375rem 0.5rem;
		flex-shrink: 0;
	}

	.new-session-btn {
		width: 100%;
		padding: 0.25rem;
		background: var(--bg-elevated);
		border: 1px solid var(--border);
		border-radius: 0;
		color: var(--fg);
		font-family: var(--font-mono);
		font-size: 0.8125rem;
		cursor: pointer;
		text-align: center;
	}

	.new-session-btn:hover {
		border-color: var(--accent-dim);
		color: var(--fg-bright);
	}

	.session-list-wrap {
		flex: 1;
		overflow-y: auto;
	}

	.sidebar-footer {
		padding: 0.25rem 0.5rem;
		border-top: 1px solid var(--border);
		flex-shrink: 0;
	}

	.version {
		font-size: 0.6875rem;
		color: var(--fg-dim);
	}
</style>