generated from nhcarrigan/template
f173892aaa
## Summary This PR includes major feature additions, bug fixes, comprehensive testing improvements, and responsive design enhancements! ## New Features โจ ### Plugin & MCP Management (#133, #134) - **Plugin Management Panel**: Install, uninstall, enable/disable, and update plugins - **MCP Server Management Panel**: Add/remove MCP servers, view detailed configuration - **Marketplace Management**: Add/remove plugin marketplaces from GitHub - Backend commands for full CLI integration (`list_plugins`, `install_plugin`, `add_mcp_server`, etc.) - Beautiful UI with proper loading states, error handling, and theme support ### Visual Todo List Panel (#132) - Real-time todo list display when Hikari uses the `TodoWrite` tool - Shows pending/in-progress/completed status with visual indicators - Progress bar and completion count - Automatically clears on disconnect - Theme-aware styling ### Clear Session History Button (#130) - "Clear All Sessions" button in Session History panel - Confirmation dialog with session count - Keyboard support and accessibility features - Gives users control over disk usage ### CLI Version Display (#131) - Displays Claude CLI version in status bar - Auto-polls every 30 seconds for updates - Useful for debugging and feature compatibility ## Bug Fixes ๐ ### Stats Panel Scrolling (#136) - **Fixed stats panel overflow**: Added scrollable container with `max-height` constraint - Stats panel now scrolls when content (Tools Used, Historical Costs, Budget sections) gets too long - Prevents content from overflowing off screen ### Agent Monitor Fixes (#122) - **Fixed agents stuck in "running" state**: Added `SubagentStop` hook parsing - **Fixed agents persisting after disconnect**: Call `clearConversation()` on disconnect - **Fixed "Kill All" button**: Now properly marks all agents as errored - **Fixed badge persisting after tab close**: Cleanup agents when conversation is deleted - Comprehensive tests for agent lifecycle management ### Discord RPC Cleanup (#129) - Removed file-based logging for Discord RPC - Replaced with proper `tracing` framework usage - Reduces disk usage and eliminates maintenance burden ### Close Modal Bug Fix (#128) - Fixed close confirmation modal not triggering after Discord RPC refactor - Removed frontend calls to deleted `log_discord_rpc` command - Modal now works correctly after all operations ### Responsive Design Fixes (#118) - Fixed top navigation icons getting cut off at small screen widths - Fixed Connect button disappearing on narrow screens - Fixed bottom status info (clock, CLI version) getting cut off - Added flex-wrap and mobile-optimised layouts - Icons-only mode on screens < 640px - Vertical stacking on screens < 768px ## Testing Improvements ๐งช ### Comprehensive Test Coverage (#114) - **417 backend tests** (up from 408) - **387 frontend tests** (up from 363) - **61%+ backend code coverage** - Added E2E integration tests for cross-platform notification commands - New test files: `agents.test.ts`, comprehensive CLI parsing tests - Tests for `debug_logger.rs`, `bridge_manager.rs`, `notifications.rs` - Console mocking for cleaner test output - Fixed flaky frontend tests ### Testing Documentation - Updated CLAUDE.md with comprehensive testing guidelines - Documented mocking approaches (console mocking, E2E command structure testing) - Added step-by-step guide for adding tests to new features - Goal to maintain ~100% test coverage documented ## Closes Closes #114 Closes #118 Closes #122 Closes #128 Closes #129 Closes #130 Closes #131 Closes #132 Closes #133 Closes #134 Closes #136 ## Technical Details - All new backend commands properly registered in `lib.rs` - CLI output parsing with comprehensive test coverage - Cross-platform compatibility verified through E2E tests (Linux CI can test Windows commands) - Theme-aware UI components using CSS variables throughout - Proper TypeScript types for all new stores and components - ESLint and Prettier compliant - All Clippy warnings addressed โจ This PR was created with help from Hikari~ ๐ธ Reviewed-on: #135 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
183 lines
6.6 KiB
Svelte
183 lines
6.6 KiB
Svelte
<script lang="ts">
|
|
import { todos } from "$lib/stores/todos";
|
|
import { CheckCircle, Circle, Loader } from "lucide-svelte";
|
|
|
|
interface Props {
|
|
onClose: () => void;
|
|
}
|
|
|
|
const { onClose }: Props = $props();
|
|
|
|
const currentTodos = $derived($todos);
|
|
const hasTodos = $derived(currentTodos.length > 0);
|
|
const completedCount = $derived(currentTodos.filter((t) => t.status === "completed").length);
|
|
const totalCount = $derived(currentTodos.length);
|
|
</script>
|
|
|
|
<div
|
|
class="fixed top-0 right-0 h-full w-96 bg-[var(--bg-primary)] border-l border-[var(--accent-primary)]/30 shadow-2xl flex flex-col z-50"
|
|
>
|
|
<!-- Header -->
|
|
<div class="flex items-center justify-between p-4 border-b border-[var(--accent-primary)]/30">
|
|
<div class="flex items-center gap-3">
|
|
<div class="text-[var(--accent-primary)]">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-6 w-6"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<h2 class="text-lg font-semibold text-[var(--text-primary)]">Hikari's Todo List</h2>
|
|
{#if hasTodos}
|
|
<p class="text-xs text-[var(--text-secondary)]">
|
|
{completedCount} of {totalCount} completed
|
|
</p>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
<button
|
|
onclick={onClose}
|
|
class="text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors p-1 rounded-lg hover:bg-[var(--bg-secondary)]"
|
|
aria-label="Close todo panel"
|
|
>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-5 w-5"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
>
|
|
<path
|
|
fill-rule="evenodd"
|
|
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
|
clip-rule="evenodd"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="flex-1 overflow-y-auto p-4">
|
|
{#if !hasTodos}
|
|
<div class="flex flex-col items-center justify-center h-full text-[var(--text-secondary)]">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-16 w-16 mb-4 opacity-50"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
/>
|
|
</svg>
|
|
<p class="text-center">No active todos</p>
|
|
<p class="text-sm text-center mt-2">I'll update this when I start working on tasks!</p>
|
|
</div>
|
|
{:else}
|
|
<div class="space-y-2">
|
|
{#each currentTodos as todo (todo.content)}
|
|
<div
|
|
class="group bg-[var(--bg-secondary)]/50 rounded-lg p-3 border border-[var(--border-color)] hover:border-[var(--accent-primary)]/50 transition-all"
|
|
class:opacity-60={todo.status === "completed"}
|
|
>
|
|
<div class="flex items-start gap-3">
|
|
<!-- Status Icon -->
|
|
<div class="mt-0.5 flex-shrink-0">
|
|
{#if todo.status === "completed"}
|
|
<CheckCircle class="w-5 h-5 text-[var(--success-color)]" />
|
|
{:else if todo.status === "in_progress"}
|
|
<Loader class="w-5 h-5 text-[var(--accent-primary)] animate-spin" />
|
|
{:else}
|
|
<Circle class="w-5 h-5 text-[var(--text-secondary)]" />
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="flex-1 min-w-0">
|
|
<p
|
|
class="text-sm font-medium"
|
|
class:text-[var(--text-secondary)]={todo.status === "completed"}
|
|
class:line-through={todo.status === "completed"}
|
|
class:text-[var(--text-primary)]={todo.status !== "completed"}
|
|
>
|
|
{todo.status === "in_progress" ? todo.activeForm : todo.content}
|
|
</p>
|
|
|
|
<!-- Status Badge -->
|
|
<div class="mt-1">
|
|
{#if todo.status === "completed"}
|
|
<span
|
|
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-[var(--success-color)]/20 text-[var(--success-color)] border border-[var(--success-color)]/30"
|
|
>
|
|
โ Completed
|
|
</span>
|
|
{:else if todo.status === "in_progress"}
|
|
<span
|
|
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-[var(--accent-primary)]/20 text-[var(--accent-primary)] border border-[var(--accent-primary)]/30 animate-pulse"
|
|
>
|
|
โก In Progress
|
|
</span>
|
|
{:else}
|
|
<span
|
|
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-[var(--bg-secondary)] text-[var(--text-secondary)] border border-[var(--border-color)]"
|
|
>
|
|
โ Pending
|
|
</span>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Footer with Progress Bar -->
|
|
{#if hasTodos}
|
|
<div class="border-t border-[var(--accent-primary)]/30 p-4 bg-[var(--bg-secondary)]/50">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<span class="text-xs font-medium text-[var(--text-secondary)]">Progress</span>
|
|
<span class="text-xs font-medium text-[var(--accent-primary)]">
|
|
{Math.round((completedCount / totalCount) * 100)}%
|
|
</span>
|
|
</div>
|
|
<div class="w-full bg-[var(--bg-secondary)] rounded-full h-2 overflow-hidden">
|
|
<div
|
|
class="bg-gradient-to-r from-[var(--accent-primary)] to-[var(--accent-secondary)] h-2 rounded-full transition-all duration-500 ease-out"
|
|
style="width: {(completedCount / totalCount) * 100}%"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
@keyframes pulse {
|
|
0%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
.animate-pulse {
|
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
}
|
|
</style>
|