summaryrefslogtreecommitdiffhomepage
path: root/packages/frontend/src/lib/components/SidebarPanel.svelte
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-05-22 00:19:14 +0900
committerAdam Malczewski <[email protected]>2026-05-22 00:19:14 +0900
commitfb97d4cb72d0a90dde102b7001603716ee6e4c3b (patch)
tree55c6e8b56b3395008523ab94c16c4f526083d846 /packages/frontend/src/lib/components/SidebarPanel.svelte
parent7884709e3b2adb1b65c1c086257e0300eed51cee (diff)
downloaddispatch-fb97d4cb72d0a90dde102b7001603716ee6e4c3b.tar.gz
dispatch-fb97d4cb72d0a90dde102b7001603716ee6e4c3b.zip
feat: agent summoning system, todo improvements, security fixes, double-execution bug fix
- Add summon/retrieve tools for spawning child agents in new tabs - summon: non-blocking, returns agent_id immediately - retrieve: blocking, waits for child to finish, returns result - Child tools are intersected with parent permissions (no privilege escalation) - Working directory validated to stay within workspace - Abort controller stops orphaned agents on tab close - Rename task_list tool to todo with comprehensive usage guidance in system prompt - Rename PermissionLog.svelte to ToolPermissions.svelte - Add 'Summon agents' toggle to tool permissions UI - Redesign TaskListPanel with DaisyUI checkboxes (indeterminate for in-progress) - Remove 'blocked' status from task system - Add tab-created WebSocket event for child agent tab visibility - Add HMR cleanup for WebSocket connections (close stale connections on hot reload) - Fix ensureAssistantMessage to not throw on closed tabs - Fix double tool execution: remove execute from AI SDK tool() in registry.ts (agent.ts already executes tools manually via executeToolWithStreaming) - Fix all pre-existing test failures (missing mocks, stale API signatures) - Add debug info to copy button (tab ID, injected skills, all tab IDs) - Add tab ID and tools to conversation copy output
Diffstat (limited to 'packages/frontend/src/lib/components/SidebarPanel.svelte')
-rw-r--r--packages/frontend/src/lib/components/SidebarPanel.svelte120
1 files changed, 66 insertions, 54 deletions
diff --git a/packages/frontend/src/lib/components/SidebarPanel.svelte b/packages/frontend/src/lib/components/SidebarPanel.svelte
index 93d528e..a0aeb1d 100644
--- a/packages/frontend/src/lib/components/SidebarPanel.svelte
+++ b/packages/frontend/src/lib/components/SidebarPanel.svelte
@@ -1,64 +1,76 @@
<script lang="ts">
- import ModelSelector from "./ModelSelector.svelte";
- import ModelStatus from "./ModelStatus.svelte";
- import TaskListPanel from "./TaskListPanel.svelte";
- import ConfigPanel from "./ConfigPanel.svelte";
- import SkillsBrowser from "./SkillsBrowser.svelte";
- import PermissionLog from "./PermissionLog.svelte";
- import KeyUsage from "./KeyUsage.svelte";
- import ClaudeReset from "./ClaudeReset.svelte";
- import SettingsPanel from "./SettingsPanel.svelte";
- import SystemPromptPanel from "./SystemPromptPanel.svelte";
- import type { TaskItem, LogEntry, KeyInfo } from "../types.js";
+import type { KeyInfo, LogEntry, TaskItem } from "../types.js";
+import ClaudeReset from "./ClaudeReset.svelte";
+import ConfigPanel from "./ConfigPanel.svelte";
+import KeyUsage from "./KeyUsage.svelte";
+import ModelSelector from "./ModelSelector.svelte";
+import ModelStatus from "./ModelStatus.svelte";
+import SettingsPanel from "./SettingsPanel.svelte";
+import SkillsBrowser from "./SkillsBrowser.svelte";
+import SystemPromptPanel from "./SystemPromptPanel.svelte";
+import TaskListPanel from "./TaskListPanel.svelte";
+import ToolPermissions from "./ToolPermissions.svelte";
- const {
- keys = [],
- tasks = [],
- permissionLog = [],
- apiBase = "",
- activeKeyId = null,
- activeModelId = null,
- reasoningEffort = "max",
- onKeyChange,
- onModelChange,
- onReasoningChange,
- }: {
- keys?: KeyInfo[];
- tasks?: TaskItem[];
- permissionLog?: LogEntry[];
- apiBase?: string;
- activeKeyId?: string | null;
- activeModelId?: string | null;
- reasoningEffort?: string;
- onKeyChange: (keyId: string) => void;
- onModelChange: (keyId: string, modelId: string) => void;
- onReasoningChange: (effort: string) => void;
- } = $props();
+const {
+ keys = [],
+ tasks = [],
+ permissionLog = [],
+ apiBase = "",
+ activeKeyId = null,
+ activeModelId = null,
+ reasoningEffort = "max",
+ onKeyChange,
+ onModelChange,
+ onReasoningChange,
+}: {
+ keys?: KeyInfo[];
+ tasks?: TaskItem[];
+ permissionLog?: LogEntry[];
+ apiBase?: string;
+ activeKeyId?: string | null;
+ activeModelId?: string | null;
+ reasoningEffort?: string;
+ onKeyChange: (keyId: string) => void;
+ onModelChange: (keyId: string, modelId: string) => void;
+ onReasoningChange: (effort: string) => void;
+} = $props();
- interface Panel {
- id: number;
- selected: string;
- }
+interface Panel {
+ id: number;
+ selected: string;
+}
- let nextId = 0;
- let panels = $state<Panel[]>([{ id: nextId++, selected: "Model Choice" }]);
+let nextId = 0;
+let panels = $state<Panel[]>([{ id: nextId++, selected: "Model Choice" }]);
- const viewOptions = ["Select a view", "Model Choice", "Key Usage", "Claude Reset", "Model Status", "Tasks", "Config", "Skills", "Tools", "System Prompt", "Settings"];
+const viewOptions = [
+ "Select a view",
+ "Model Choice",
+ "Key Usage",
+ "Claude Reset",
+ "Model Status",
+ "Tasks",
+ "Config",
+ "Skills",
+ "Tools",
+ "System Prompt",
+ "Settings",
+];
- function addPanel() {
- panels = [...panels, { id: nextId++, selected: "Select a view" }];
- }
+function addPanel() {
+ panels = [...panels, { id: nextId++, selected: "Select a view" }];
+}
- function panelClass(selected: string): string {
- const base = "bg-base-200 rounded-lg p-3 flex flex-col min-h-0";
- const fill = selected === "Key Usage" || selected === "Claude Reset" || selected === "Tasks";
- return fill ? base + " flex-1" : base;
- }
+function panelClass(selected: string): string {
+ const base = "bg-base-200 rounded-lg p-3 flex flex-col min-h-0";
+ const fill = selected === "Key Usage" || selected === "Claude Reset" || selected === "Tasks";
+ return fill ? base + " flex-1" : base;
+}
- function contentClass(selected: string): string {
- const fill = selected === "Key Usage" || selected === "Claude Reset" || selected === "Tasks";
- return fill ? "mt-2 flex-1 min-h-0" : "mt-2";
- }
+function contentClass(selected: string): string {
+ const fill = selected === "Key Usage" || selected === "Claude Reset" || selected === "Tasks";
+ return fill ? "mt-2 flex-1 min-h-0" : "mt-2";
+}
</script>
<div class="flex flex-col gap-2">
@@ -115,7 +127,7 @@
{:else if panel.selected === "Skills"}
<SkillsBrowser {apiBase} />
{:else if panel.selected === "Tools"}
- <PermissionLog entries={permissionLog} {apiBase} />
+ <ToolPermissions entries={permissionLog} {apiBase} />
{:else if panel.selected === "System Prompt"}
<SystemPromptPanel {apiBase} />
{:else if panel.selected === "Settings"}