diff --git a/package-lock.json b/package-lock.json
index d76a96f..6f3e7c8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "codepilot",
- "version": "0.6.1",
+ "version": "0.6.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codepilot",
- "version": "0.6.1",
+ "version": "0.6.2",
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.33",
"@hugeicons/core-free-icons": "^3.1.1",
diff --git a/package.json b/package.json
index e8ffff8..fa0000a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "codepilot",
- "version": "0.6.1",
+ "version": "0.6.2",
"private": true,
"main": "dist-electron/main.js",
"scripts": {
diff --git a/src/__tests__/e2e/chat-enhanced.spec.ts b/src/__tests__/e2e/chat-enhanced.spec.ts
index 12ce90c..aa04cd4 100644
--- a/src/__tests__/e2e/chat-enhanced.spec.ts
+++ b/src/__tests__/e2e/chat-enhanced.spec.ts
@@ -30,7 +30,7 @@ test.describe('Chat UI Enhanced (V2)', () => {
// Wait for assistant response -- V2 uses gradient avatar instead of text label
// Detect assistant response via the gradient avatar
await expect(
- page.locator('.from-violet-500')
+ page.locator('[data-role="assistant"]')
).toBeVisible({ timeout: 30_000 });
// Wait for streaming to complete
@@ -50,7 +50,7 @@ test.describe('Chat UI Enhanced (V2)', () => {
await sendMessage(page, 'Show me a Python hello world');
await expect(
- page.locator('.from-violet-500')
+ page.locator('[data-role="assistant"]')
).toBeVisible({ timeout: 30_000 });
await waitForStreamingEnd(page);
@@ -103,9 +103,9 @@ test.describe('Chat UI Enhanced (V2)', () => {
await goToChat(page);
await sendMessage(page, 'Hi there');
- // V2: Assistant avatar uses gradient bg (from-violet-500 to-purple-600)
+ // Detect assistant response via data-role attribute
await expect(
- page.locator('.from-violet-500')
+ page.locator('[data-role="assistant"]')
).toBeVisible({ timeout: 30_000 });
});
@@ -125,7 +125,7 @@ test.describe('Chat UI Enhanced (V2)', () => {
// V2: Assistant avatar is gradient, not bg-primary
await expect(
- page.locator('.from-violet-500:has(svg)')
+ page.locator('[data-role="assistant"]')
).toBeVisible({ timeout: 30_000 });
});
});
diff --git a/src/__tests__/e2e/chat.spec.ts b/src/__tests__/e2e/chat.spec.ts
index e3854fb..a1dfd3b 100644
--- a/src/__tests__/e2e/chat.spec.ts
+++ b/src/__tests__/e2e/chat.spec.ts
@@ -116,9 +116,9 @@ test.describe('Chat Page', () => {
await goToChat(page);
await sendMessage(page, 'Say hello');
- // V2: Wait for assistant response -- gradient avatar appears
+ // Wait for assistant response
await expect(
- page.locator('.from-violet-500')
+ page.locator('[data-role="assistant"]')
).toBeVisible({ timeout: 10_000 });
});
diff --git a/src/app/globals.css b/src/app/globals.css
index 5bc066c..3663c3e 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -54,7 +54,7 @@
--card-foreground: oklch(0.147 0.004 49.25);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.147 0.004 49.25);
- --primary: oklch(0.457 0.24 277.023);
+ --primary: oklch(0.546 0.245 262.881);
--primary-foreground: oklch(0.985 0.001 106.423);
--secondary: oklch(0.97 0.001 106.424);
--secondary-foreground: oklch(0.216 0.006 56.043);
@@ -65,20 +65,20 @@
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.923 0.003 48.717);
--input: oklch(0.923 0.003 48.717);
- --ring: oklch(0.457 0.24 277.023);
- --chart-1: oklch(0.457 0.24 277.023);
+ --ring: oklch(0.546 0.245 262.881);
+ --chart-1: oklch(0.546 0.245 262.881);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0.001 106.423);
--sidebar-foreground: oklch(0.147 0.004 49.25);
- --sidebar-primary: oklch(0.457 0.24 277.023);
+ --sidebar-primary: oklch(0.546 0.245 262.881);
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
--sidebar-accent: oklch(0.97 0.001 106.424);
--sidebar-accent-foreground: oklch(0.216 0.006 56.043);
--sidebar-border: oklch(0.923 0.003 48.717);
- --sidebar-ring: oklch(0.457 0.24 277.023);
+ --sidebar-ring: oklch(0.546 0.245 262.881);
}
.dark {
@@ -88,7 +88,7 @@
--card-foreground: oklch(0.985 0.001 106.423);
--popover: oklch(0.216 0.006 56.043);
--popover-foreground: oklch(0.985 0.001 106.423);
- --primary: oklch(0.585 0.233 277.117);
+ --primary: oklch(0.623 0.214 259.815);
--primary-foreground: oklch(0.985 0.001 106.423);
--secondary: oklch(0.268 0.007 34.298);
--secondary-foreground: oklch(0.985 0.001 106.423);
@@ -99,20 +99,20 @@
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
- --ring: oklch(0.585 0.233 277.117);
- --chart-1: oklch(0.585 0.233 277.117);
+ --ring: oklch(0.623 0.214 259.815);
+ --chart-1: oklch(0.623 0.214 259.815);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.216 0.006 56.043);
--sidebar-foreground: oklch(0.985 0.001 106.423);
- --sidebar-primary: oklch(0.585 0.233 277.117);
+ --sidebar-primary: oklch(0.623 0.214 259.815);
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
--sidebar-accent: oklch(0.268 0.007 34.298);
--sidebar-accent-foreground: oklch(0.985 0.001 106.423);
--sidebar-border: oklch(1 0 0 / 10%);
- --sidebar-ring: oklch(0.585 0.233 277.117);
+ --sidebar-ring: oklch(0.623 0.214 259.815);
}
@layer base {
@@ -125,10 +125,10 @@
/* Selection color */
::selection {
- background: oklch(0.7 0.15 280 / 30%);
+ background: oklch(0.7 0.15 260 / 30%);
}
.dark ::selection {
- background: oklch(0.6 0.2 280 / 35%);
+ background: oklch(0.6 0.2 260 / 35%);
}
/* Custom scrollbar */
@@ -179,16 +179,16 @@
margin-bottom: 0.25em;
}
.prose blockquote {
- border-left-color: oklch(0.7 0.15 280 / 40%);
+ border-left-color: oklch(0.7 0.15 260 / 40%);
font-style: normal;
}
.prose a {
- color: oklch(0.55 0.2 260);
+ color: oklch(0.55 0.2 250);
text-decoration: underline;
text-underline-offset: 2px;
}
.dark .prose a {
- color: oklch(0.7 0.18 260);
+ color: oklch(0.7 0.18 250);
}
.prose hr {
border-color: var(--border);
@@ -197,3 +197,13 @@
font-weight: 600;
}
}
+
+/* Global icon stroke weight — make Hugeicons strokes slightly thicker */
+svg.hugeicons,
+svg.hugeicons path,
+svg.hugeicons line,
+svg.hugeicons circle,
+svg.hugeicons polyline,
+svg.hugeicons rect {
+ stroke-width: 2;
+}
diff --git a/src/components/chat/MessageInput.tsx b/src/components/chat/MessageInput.tsx
index 78913b2..1c4ab4e 100644
--- a/src/components/chat/MessageInput.tsx
+++ b/src/components/chat/MessageInput.tsx
@@ -9,6 +9,7 @@ import {
ClipboardIcon,
HelpCircleIcon,
ArrowDown01Icon,
+ ArrowUp02Icon,
CommandLineIcon,
Attachment01Icon,
Cancel01Icon,
@@ -32,6 +33,7 @@ import {
PromptInputSubmit,
usePromptInputAttachments,
} from '@/components/ai-elements/prompt-input';
+import { SquareIcon } from 'lucide-react';
import type { ChatStatus } from 'ai';
import type { FileAttachment } from '@/types';
import { nanoid } from 'nanoid';
@@ -221,7 +223,14 @@ function FileAwareSubmitButton({
status={status}
onStop={onStop}
disabled={disabled || (!isStreaming && !inputValue.trim() && !hasBadge && !hasFiles)}
- />
+ className="rounded-full"
+ >
+ {isStreaming ? (
+
+ ) : (
+
+ )}
+
);
}
@@ -887,7 +896,7 @@ export function MessageInput({
>
{currentMode.label}
-
+
{/* Mode dropdown */}
@@ -931,7 +940,7 @@ export function MessageInput({
onClick={() => setModelMenuOpen((prev) => !prev)}
>
{currentModelOption.label}
-
+
{modelMenuOpen && (
diff --git a/src/components/chat/ToolCallBlock.tsx b/src/components/chat/ToolCallBlock.tsx
index c9e02c5..b6973b8 100644
--- a/src/components/chat/ToolCallBlock.tsx
+++ b/src/components/chat/ToolCallBlock.tsx
@@ -312,7 +312,7 @@ export function ToolCallBlock({
category === 'read' && "text-blue-500",
category === 'write' && "text-amber-500",
category === 'bash' && "text-green-500",
- category === 'search' && "text-purple-500",
+ category === 'search' && "text-indigo-500",
category === 'other' && "text-zinc-500",
)} />
{summary}
diff --git a/src/components/layout/ChatListPanel.tsx b/src/components/layout/ChatListPanel.tsx
index 1cae414..35d36ea 100644
--- a/src/components/layout/ChatListPanel.tsx
+++ b/src/components/layout/ChatListPanel.tsx
@@ -65,7 +65,7 @@ function groupSessionsByDate(
const MODE_BADGE_CONFIG = {
code: { label: "Code", className: "bg-blue-500/10 text-blue-500" },
- plan: { label: "Plan", className: "bg-purple-500/10 text-purple-500" },
+ plan: { label: "Plan", className: "bg-sky-500/10 text-sky-500" },
ask: { label: "Ask", className: "bg-green-500/10 text-green-500" },
} as const;
diff --git a/src/components/skills/SkillEditor.tsx b/src/components/skills/SkillEditor.tsx
index 3df9775..348fcf5 100644
--- a/src/components/skills/SkillEditor.tsx
+++ b/src/components/skills/SkillEditor.tsx
@@ -124,7 +124,7 @@ export function SkillEditor({ skill, onSave, onDelete }: SkillEditorProps) {
: skill.source === "installed"
? "border-orange-500/40 text-orange-600 dark:text-orange-400"
: skill.source === "plugin"
- ? "border-purple-500/40 text-purple-600 dark:text-purple-400"
+ ? "border-indigo-500/40 text-indigo-600 dark:text-indigo-400"
: "border-blue-500/40 text-blue-600 dark:text-blue-400"
)}
>
diff --git a/src/components/skills/SkillListItem.tsx b/src/components/skills/SkillListItem.tsx
index 06e32ee..8746964 100644
--- a/src/components/skills/SkillListItem.tsx
+++ b/src/components/skills/SkillListItem.tsx
@@ -77,7 +77,7 @@ export function SkillListItem({
: skill.source === "installed"
? "border-orange-500/40 text-orange-600 dark:text-orange-400"
: skill.source === "plugin"
- ? "border-purple-500/40 text-purple-600 dark:text-purple-400"
+ ? "border-indigo-500/40 text-indigo-600 dark:text-indigo-400"
: "border-blue-500/40 text-blue-600 dark:text-blue-400"
)}
>
diff --git a/src/components/ui/input-group.tsx b/src/components/ui/input-group.tsx
index 3d1f9d9..819388d 100644
--- a/src/components/ui/input-group.tsx
+++ b/src/components/ui/input-group.tsx
@@ -14,7 +14,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
data-slot="input-group"
role="group"
className={cn(
- "group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none",
+ "group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-2xl border shadow-md transition-[color,box-shadow] outline-none",
"h-9 min-w-0 has-[>textarea]:h-auto",
// Variants based on alignment.
@@ -23,8 +23,8 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
- // Focus state.
- "has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]",
+ // Focus state — neutral border only, no colored ring.
+ "has-[[data-slot=input-group-control]:focus-visible]:border-border",
// Error state.
"has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",