summaryrefslogtreecommitdiffhomepage
path: root/packages/frontend/src
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-03 00:55:23 +0900
committerAdam Malczewski <[email protected]>2026-06-03 00:55:23 +0900
commitae672fd4f5542a2c217cf97657bf81eeebdaabbd (patch)
tree5274fa0c777991dad5e36d058d669b67b6a69c9e /packages/frontend/src
parent66e5d3b105bfd2b34c6f35876bf33dbb3cb9dcae (diff)
parent2e3c108119012546d72ca6746fbe8e9b6b49c229 (diff)
downloaddispatch-ae672fd4f5542a2c217cf97657bf81eeebdaabbd.tar.gz
dispatch-ae672fd4f5542a2c217cf97657bf81eeebdaabbd.zip
Merge branch 'dev' into img8/image-attachments
Diffstat (limited to 'packages/frontend/src')
-rw-r--r--packages/frontend/src/lib/components/TabBar.svelte34
-rw-r--r--packages/frontend/src/lib/components/ToolPermissions.svelte6
-rw-r--r--packages/frontend/src/lib/settings.svelte.ts2
3 files changed, 40 insertions, 2 deletions
diff --git a/packages/frontend/src/lib/components/TabBar.svelte b/packages/frontend/src/lib/components/TabBar.svelte
index 354260c..7371f7b 100644
--- a/packages/frontend/src/lib/components/TabBar.svelte
+++ b/packages/frontend/src/lib/components/TabBar.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
import { tick } from "svelte";
+import type { Tab } from "../tabs.svelte.js";
import { tabStore } from "../tabs.svelte.js";
function statusColor(status: string): string {
@@ -8,6 +9,21 @@ function statusColor(status: string): string {
return "bg-success";
}
+/**
+ * A tab "needs attention" — and should ping to grab the user's eye — when the
+ * agent has stopped and is likely waiting on the user:
+ * (a) the turn ended (idle) but the task list still has incomplete tasks
+ * (pending / in_progress) — the agent probably expects a response; or
+ * (b) the turn stopped due to an error of any kind.
+ */
+function needsAttention(tab: Tab): boolean {
+ if (tab.agentStatus === "error") return true;
+ if (tab.agentStatus === "idle") {
+ return tab.tasks.some((t) => t.status === "pending" || t.status === "in_progress");
+ }
+ return false;
+}
+
const userTabs = $derived(tabStore.tabs.filter((t) => t.parentTabId === null));
const subagentTabs = $derived(
tabStore.tabs.filter((t) => t.parentTabId !== null && t.parentTabId === activeUserTabId),
@@ -123,7 +139,14 @@ function handleRenameKeydown(e: KeyboardEvent): void {
tabindex="0"
>
<span class="flex items-center gap-1.5">
- <span class="w-1.5 h-1.5 rounded-full shrink-0 {statusColor(tab.agentStatus)}"></span>
+ {#if needsAttention(tab)}
+ <span class="relative inline-grid shrink-0 *:[grid-area:1/1]">
+ <span class="w-1.5 h-1.5 rounded-full animate-ping {statusColor(tab.agentStatus)}"></span>
+ <span class="w-1.5 h-1.5 rounded-full {statusColor(tab.agentStatus)}"></span>
+ </span>
+ {:else}
+ <span class="w-1.5 h-1.5 rounded-full shrink-0 {statusColor(tab.agentStatus)}"></span>
+ {/if}
<span class="font-mono text-[10px] px-1 py-0.5 rounded bg-base-300 text-base-content/60 shrink-0" title="Tab ID — agents address this tab by this handle">{tabStore.shortHandleFor(tab.id)}</span>
{#if editingTabId === tab.id}
<input
@@ -183,7 +206,14 @@ function handleRenameKeydown(e: KeyboardEvent): void {
tabindex="0"
>
<span class="flex items-center gap-1">
- <span class="w-1 h-1 rounded-full shrink-0 {statusColor(tab.agentStatus)}"></span>
+ {#if needsAttention(tab)}
+ <span class="relative inline-grid shrink-0 *:[grid-area:1/1]">
+ <span class="w-1 h-1 rounded-full animate-ping {statusColor(tab.agentStatus)}"></span>
+ <span class="w-1 h-1 rounded-full {statusColor(tab.agentStatus)}"></span>
+ </span>
+ {:else}
+ <span class="w-1 h-1 rounded-full shrink-0 {statusColor(tab.agentStatus)}"></span>
+ {/if}
<span class="font-mono text-[10px] px-1 rounded bg-base-300 text-base-content/60 shrink-0" title="Tab ID — agents address this tab by this handle">{tabStore.shortHandleFor(tab.id)}</span>
<span class="max-w-28 truncate text-xs">{tab.title}</span>
</span>
diff --git a/packages/frontend/src/lib/components/ToolPermissions.svelte b/packages/frontend/src/lib/components/ToolPermissions.svelte
index 6b09a07..4298724 100644
--- a/packages/frontend/src/lib/components/ToolPermissions.svelte
+++ b/packages/frontend/src/lib/components/ToolPermissions.svelte
@@ -53,6 +53,12 @@ const toolPermissions: ToolPermission[] = [
description: "Allow the AI to search the codebase with the cs ranked code-search engine",
},
{
+ id: "key_usage",
+ label: "Key usage",
+ description:
+ "Allow the AI to read current API-key usage levels, rate-limit headroom, and reset times",
+ },
+ {
id: "lsp",
label: "LSP queries",
description:
diff --git a/packages/frontend/src/lib/settings.svelte.ts b/packages/frontend/src/lib/settings.svelte.ts
index 0da4e45..1b93804 100644
--- a/packages/frontend/src/lib/settings.svelte.ts
+++ b/packages/frontend/src/lib/settings.svelte.ts
@@ -15,6 +15,7 @@ let toolPerms = $state<Record<string, boolean>>({
web_search: false,
youtube_transcribe: false,
search_code: false,
+ key_usage: false,
lsp: false,
});
let savedToolPerms = $state<Record<string, boolean>>({
@@ -29,6 +30,7 @@ let savedToolPerms = $state<Record<string, boolean>>({
web_search: false,
youtube_transcribe: false,
search_code: false,
+ key_usage: false,
lsp: false,
});
let skillChecks = $state<Record<string, boolean>>({});