collet 0.1.0

Relentless agentic coding orchestrator with zero-drop agent loops
Documentation
<script lang="ts">
	import { appStore } from '$lib/store.svelte.js';
	import DiffView from '../chat/DiffView.svelte';

	function isDiff(s: string): boolean {
		return s.includes('\n--- ') || s.startsWith('--- ') || s.includes('\n+++ ');
	}

	let expandedIdx = $state<number | null>(null);

	let sorted = $derived([...appStore.tools].reverse());

	function truncate(s: string, max: number): string {
		return s.length > max ? s.slice(0, max) + '...' : s;
	}

	function toggle(idx: number) {
		expandedIdx = expandedIdx === idx ? null : idx;
	}
</script>

<div class="panel">
	<div class="header">Tools</div>
	{#if sorted.length === 0}
		<div class="dim">no tool calls</div>
	{:else}
		<div class="list">
			{#each sorted as tool, i (tool.timestamp)}
				<button class="entry" onclick={() => toggle(i)}>
					<span class="icon">
						{#if tool.success === undefined}
							<span class="pending">⟳</span>
						{:else if tool.success}
							<span class="ok">✓</span>
						{:else}
							<span class="fail">✗</span>
						{/if}
					</span>
					<span class="name">{tool.name}</span>
					<span class="args">{truncate(tool.args, 30)}</span>
				</button>
				{#if expandedIdx === i}
					<div class="detail">
						<div class="detail-section">
							<span class="label">args:</span>
							<pre>{tool.args}</pre>
						</div>
						{#if tool.result}
							<div class="detail-section">
								<span class="label">result:</span>
								{#if isDiff(tool.result)}
									<DiffView diff={tool.result} />
								{:else}
									<pre>{truncate(tool.result, 500)}</pre>
								{/if}
							</div>
						{/if}
					</div>
				{/if}
			{/each}
		</div>
	{/if}
</div>

<style>
	.panel {
		font-family: monospace;
		font-size: 0.8rem;
	}
	.header {
		color: var(--accent);
		padding: 0.25rem 0.5rem;
		font-weight: bold;
		text-transform: uppercase;
		font-size: 0.7rem;
		letter-spacing: 0.08em;
	}
	.list {
		overflow-y: auto;
		max-height: 300px;
	}
	.entry {
		all: unset;
		cursor: pointer;
		display: flex;
		align-items: center;
		gap: 0.3rem;
		padding: 0.2rem 0.5rem;
		width: 100%;
		box-sizing: border-box;
		font-size: 0.7rem;
		color: var(--fg);
	}
	.entry:hover {
		background: var(--bg-surface);
	}
	.entry:focus-visible {
		outline: 1px solid var(--accent);
		outline-offset: -1px;
	}
	.icon {
		flex-shrink: 0;
		width: 0.8rem;
		text-align: center;
	}
	.pending {
		color: var(--yellow);
	}
	.ok {
		color: var(--green);
	}
	.fail {
		color: var(--red);
	}
	.name {
		color: var(--cyan);
		flex-shrink: 0;
	}
	.args {
		color: var(--fg-dim);
		font-size: 0.65rem;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}
	.detail {
		background: var(--bg);
		border-left: 2px solid var(--border);
		margin: 0 0.5rem 0.25rem 1.2rem;
		padding: 0.3rem;
		font-size: 0.65rem;
	}
	.detail-section {
		margin-bottom: 0.2rem;
	}
	.label {
		color: var(--fg-dim);
	}
	.detail pre {
		margin: 0.1rem 0 0;
		color: var(--fg);
		white-space: pre-wrap;
		word-break: break-all;
		font-size: 0.6rem;
	}
	.dim {
		color: var(--fg-dim);
		padding: 0.5rem;
		font-style: italic;
		font-size: 0.7rem;
	}
</style>