diff --git a/bun.lock b/bun.lock index 0152c93a4..398706c6d 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "opcode", @@ -58,6 +59,10 @@ "typescript": "~5.6.2", "vite": "^6.0.3", }, + "optionalDependencies": { + "@esbuild/linux-x64": "^0.25.6", + "@rollup/rollup-linux-x64-gnu": "^4.45.1", + }, }, }, "trustedDependencies": [ @@ -139,7 +144,7 @@ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.5", "", { "os": "none", "cpu": "arm64" }, "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw=="], @@ -357,7 +362,7 @@ "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.43.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.43.0", "", { "os": "linux", "cpu": "x64" }, "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="], "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.43.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ=="], @@ -1061,6 +1066,8 @@ "decode-named-character-reference/character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + "esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw=="], + "hast-util-from-parse5/hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], "hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], @@ -1087,6 +1094,8 @@ "rehype-prism-plus/refractor": ["refractor@4.9.0", "", { "dependencies": { "@types/hast": "^2.0.0", "@types/prismjs": "^1.0.0", "hastscript": "^7.0.0", "parse-entities": "^4.0.0" } }, "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og=="], + "rollup/@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.43.0", "", { "os": "linux", "cpu": "x64" }, "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ=="], + "stringify-entities/character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], "@uiw/react-markdown-preview/rehype-prism-plus/refractor": ["refractor@4.9.0", "", { "dependencies": { "@types/hast": "^2.0.0", "@types/prismjs": "^1.0.0", "hastscript": "^7.0.0", "parse-entities": "^4.0.0" } }, "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og=="], diff --git a/src/components/AgentExecution.tsx b/src/components/AgentExecution.tsx index 90f089ccd..8d6237195 100644 --- a/src/components/AgentExecution.tsx +++ b/src/components/AgentExecution.tsx @@ -549,6 +549,7 @@ export const AgentExecution: React.FC = ({ title="Back" > + Back

{agent.name}

diff --git a/src/components/AgentRunView.tsx b/src/components/AgentRunView.tsx index 16ade6c51..f789c1f38 100644 --- a/src/components/AgentRunView.tsx +++ b/src/components/AgentRunView.tsx @@ -257,6 +257,7 @@ export const AgentRunView: React.FC = ({ className="h-8 w-8" > + Back
{renderIcon(run.agent_icon)} diff --git a/src/components/Agents.tsx b/src/components/Agents.tsx index 795071786..6f1c1124d 100644 --- a/src/components/Agents.tsx +++ b/src/components/Agents.tsx @@ -356,6 +356,7 @@ export const Agents: React.FC = () => { diff --git a/src/components/CCAgents.tsx b/src/components/CCAgents.tsx index f72b154ee..69cab7472 100644 --- a/src/components/CCAgents.tsx +++ b/src/components/CCAgents.tsx @@ -306,6 +306,7 @@ export const CCAgents: React.FC = ({ onBack, className }) => { className="h-8 w-8" > + Back

CC Agents

diff --git a/src/components/ClaudeCodeSession.tsx b/src/components/ClaudeCodeSession.tsx index f0f164f21..67c330404 100644 --- a/src/components/ClaudeCodeSession.tsx +++ b/src/components/ClaudeCodeSession.tsx @@ -1389,7 +1389,17 @@ export const ClaudeCodeSession: React.FC = ({ transition={{ duration: 0.15 }} > @@ -1423,6 +1433,7 @@ export const ClaudeCodeSession: React.FC = ({ onClick={() => setQueuedPrompts(prev => prev.filter(p => p.id !== queuedPrompt.id))} > + Remove from queue @@ -1458,7 +1469,7 @@ export const ClaudeCodeSession: React.FC = ({ top: 0, behavior: 'smooth' }); - + // After smooth scroll completes, trigger a small scroll to ensure rendering setTimeout(() => { if (parentRef.current) { @@ -1476,6 +1487,7 @@ export const ClaudeCodeSession: React.FC = ({ className="px-3 py-2 hover:bg-accent rounded-none" > + Scroll to top @@ -1509,6 +1521,7 @@ export const ClaudeCodeSession: React.FC = ({ className="px-3 py-2 hover:bg-accent rounded-none" > + Scroll to bottom @@ -1542,6 +1555,7 @@ export const ClaudeCodeSession: React.FC = ({ className="h-9 w-9 text-muted-foreground hover:text-foreground" > + Session Timeline @@ -1560,6 +1574,7 @@ export const ClaudeCodeSession: React.FC = ({ className="h-9 w-9 text-muted-foreground hover:text-foreground" > + Copy conversation @@ -1602,6 +1617,7 @@ export const ClaudeCodeSession: React.FC = ({ className="h-8 w-8 text-muted-foreground hover:text-foreground" > + Checkpoint Settings @@ -1654,6 +1670,7 @@ export const ClaudeCodeSession: React.FC = ({ className="h-8 w-8" > + Close timeline
diff --git a/src/components/ClaudeFileEditor.tsx b/src/components/ClaudeFileEditor.tsx index 252e3e7bc..11d14bae0 100644 --- a/src/components/ClaudeFileEditor.tsx +++ b/src/components/ClaudeFileEditor.tsx @@ -110,6 +110,7 @@ export const ClaudeFileEditor: React.FC = ({ className="h-8 w-8" > + Back

{file.relative_path}

diff --git a/src/components/ClaudeMemoriesDropdown.tsx b/src/components/ClaudeMemoriesDropdown.tsx index da4c8037e..32f8d5dff 100644 --- a/src/components/ClaudeMemoriesDropdown.tsx +++ b/src/components/ClaudeMemoriesDropdown.tsx @@ -143,6 +143,7 @@ export const ClaudeMemoriesDropdown: React.FC = ({ }} > + Edit file ))} diff --git a/src/components/CreateAgent.tsx b/src/components/CreateAgent.tsx index 96861e8e0..beee3fd7a 100644 --- a/src/components/CreateAgent.tsx +++ b/src/components/CreateAgent.tsx @@ -139,6 +139,7 @@ export const CreateAgent: React.FC = ({ title="Back to Agents" > + Back to Agents
diff --git a/src/components/CustomTitlebar.tsx b/src/components/CustomTitlebar.tsx index 3342959b0..8a498eaa9 100644 --- a/src/components/CustomTitlebar.tsx +++ b/src/components/CustomTitlebar.tsx @@ -95,6 +95,7 @@ export const CustomTitlebar: React.FC = ({ {isHovered && ( )} + Close window {/* Minimize button */} @@ -109,6 +110,7 @@ export const CustomTitlebar: React.FC = ({ {isHovered && ( )} + Minimize window {/* Maximize button */} @@ -123,6 +125,7 @@ export const CustomTitlebar: React.FC = ({ {isHovered && ( )} + Maximize window
@@ -148,6 +151,7 @@ export const CustomTitlebar: React.FC = ({ className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors tauri-no-drag" > + Agents )} @@ -161,6 +165,7 @@ export const CustomTitlebar: React.FC = ({ className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors tauri-no-drag" > + Usage Dashboard )} @@ -180,6 +185,7 @@ export const CustomTitlebar: React.FC = ({ className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors tauri-no-drag" > + Settings )} @@ -194,6 +200,7 @@ export const CustomTitlebar: React.FC = ({ className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors flex items-center gap-1" > + More options diff --git a/src/components/FilePicker.tsx b/src/components/FilePicker.tsx index 3038df4e1..a0258eca7 100644 --- a/src/components/FilePicker.tsx +++ b/src/components/FilePicker.tsx @@ -381,6 +381,7 @@ export const FilePicker: React.FC = ({ className="h-8 w-8" > + Navigate up {relativePath} @@ -393,6 +394,7 @@ export const FilePicker: React.FC = ({ className="h-8 w-8" > + Close
diff --git a/src/components/FloatingPromptInput.tsx b/src/components/FloatingPromptInput.tsx index 1f042b2c6..7dfc86941 100644 --- a/src/components/FloatingPromptInput.tsx +++ b/src/components/FloatingPromptInput.tsx @@ -881,6 +881,7 @@ const FloatingPromptInputInner = ( className="h-8 w-8" > + Minimize @@ -1259,6 +1260,7 @@ const FloatingPromptInputInner = ( className="h-8 w-8 hover:bg-accent/50 transition-colors" > + Expand @@ -1279,9 +1281,15 @@ const FloatingPromptInputInner = ( )} > {isLoading ? ( - + <> + + Stop generation + ) : ( - + <> + + Send message + )} diff --git a/src/components/MCPServerList.tsx b/src/components/MCPServerList.tsx index b4936928c..08633f6ca 100644 --- a/src/components/MCPServerList.tsx +++ b/src/components/MCPServerList.tsx @@ -266,9 +266,15 @@ export const MCPServerList: React.FC = ({ className="hover:bg-green-500/10 hover:text-green-600" > {testingServer === server.name ? ( - + <> + + Testing connection + ) : ( - + <> + + Test connection + )} diff --git a/src/components/ProjectList.tsx b/src/components/ProjectList.tsx index 8d8ab7995..3f35da4f3 100644 --- a/src/components/ProjectList.tsx +++ b/src/components/ProjectList.tsx @@ -206,6 +206,7 @@ export const ProjectList: React.FC = ({ disabled={currentPage === 1} > + Previous page @@ -234,6 +235,7 @@ export const ProjectList: React.FC = ({ disabled={currentPage === totalPages} > + Next page diff --git a/src/components/SessionOutputViewer.tsx b/src/components/SessionOutputViewer.tsx index eafcc0145..e213c0635 100644 --- a/src/components/SessionOutputViewer.tsx +++ b/src/components/SessionOutputViewer.tsx @@ -412,7 +412,17 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp onClick={() => setIsFullscreen(!isFullscreen)} title="Fullscreen" > - {isFullscreen ? : } + {isFullscreen ? ( + <> + + Exit fullscreen + + ) : ( + <> + + Enter fullscreen + + )} + Refresh output diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 06d338a0c..924b5a800 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -824,6 +824,7 @@ export const Settings: React.FC = ({ className="h-8 w-8" > + Remove rule )) @@ -872,6 +873,7 @@ export const Settings: React.FC = ({ className="h-8 w-8" > + Remove rule )) diff --git a/src/components/SlashCommandsManager.tsx b/src/components/SlashCommandsManager.tsx index 631f1744d..2b866fb07 100644 --- a/src/components/SlashCommandsManager.tsx +++ b/src/components/SlashCommandsManager.tsx @@ -464,6 +464,7 @@ export const SlashCommandsManager: React.FC = ({ className="h-8 w-8" > + Edit command diff --git a/src/components/StorageTab.tsx b/src/components/StorageTab.tsx index aa4071cb3..aa4ddcb3d 100644 --- a/src/components/StorageTab.tsx +++ b/src/components/StorageTab.tsx @@ -496,6 +496,7 @@ export const StorageTab: React.FC = () => { className="h-6 w-6" > + Edit row diff --git a/src/components/TabContent.tsx b/src/components/TabContent.tsx index e306324ed..1c5352492 100644 --- a/src/components/TabContent.tsx +++ b/src/components/TabContent.tsx @@ -163,6 +163,7 @@ const TabPanel: React.FC = ({ tab, isActive }) => { title="Back to Projects" > + Back to Projects
diff --git a/src/components/TimelineNavigator.tsx b/src/components/TimelineNavigator.tsx index 2cc0ce154..a69dd390f 100644 --- a/src/components/TimelineNavigator.tsx +++ b/src/components/TimelineNavigator.tsx @@ -283,9 +283,15 @@ export const TimelineNavigator: React.FC = ({ onClick={() => toggleNodeExpansion(node.checkpoint.id)} > {isExpanded ? ( - + <> + + Collapse + ) : ( - + <> + + Expand + )} )} @@ -350,6 +356,7 @@ export const TimelineNavigator: React.FC = ({ }} > + Restore to this checkpoint Restore to this checkpoint @@ -369,6 +376,7 @@ export const TimelineNavigator: React.FC = ({ }} > + Fork from this checkpoint Fork from this checkpoint @@ -388,6 +396,7 @@ export const TimelineNavigator: React.FC = ({ }} > + Compare with another checkpoint Compare with another checkpoint diff --git a/src/components/claude-code-session/PromptQueue.tsx b/src/components/claude-code-session/PromptQueue.tsx index b2b2f546e..d85750dca 100644 --- a/src/components/claude-code-session/PromptQueue.tsx +++ b/src/components/claude-code-session/PromptQueue.tsx @@ -73,6 +73,7 @@ export const PromptQueue: React.FC = React.memo(({ onClick={() => onRemove(queuedPrompt.id)} > + Remove from queue ))} diff --git a/src/components/claude-code-session/SessionHeader.tsx b/src/components/claude-code-session/SessionHeader.tsx index b48a24823..94cb008f4 100644 --- a/src/components/claude-code-session/SessionHeader.tsx +++ b/src/components/claude-code-session/SessionHeader.tsx @@ -66,6 +66,7 @@ export const SessionHeader: React.FC = React.memo(({ className="h-8 w-8" > + Back to projects
@@ -109,6 +110,7 @@ export const SessionHeader: React.FC = React.memo(({ trigger={ } content={ @@ -145,12 +147,14 @@ export const SessionHeader: React.FC = React.memo(({ )} > + Toggle timeline diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index f6487460b..0228eac6f 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -39,24 +39,58 @@ export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { asChild?: boolean; + /** + * Loading state - sets aria-busy and disables the button + */ + isLoading?: boolean; } /** * Button component with multiple variants and sizes - * + * + * ACCESSIBILITY REQUIREMENTS: + * - Icon-only buttons (size="icon") MUST have an aria-label prop + * - Use isLoading prop to indicate loading state to screen readers + * * @example + * // Standard button * + * + * @example + * // Icon-only button (requires aria-label) + * + * + * @example + * // Loading state + * */ const Button = React.forwardRef( - ({ className, variant, size, ...props }, ref) => { + ({ className, variant, size, isLoading, disabled, children, ...props }, ref) => { + // Warn in development if icon-only button lacks aria-label + if (process.env.NODE_ENV === 'development' && size === 'icon') { + if (!props['aria-label'] && !props['aria-labelledby']) { + console.warn( + 'Button: Icon-only buttons (size="icon") should have an aria-label or aria-labelledby for accessibility' + ); + } + } + return ( ); } ); diff --git a/src/components/ui/pagination.tsx b/src/components/ui/pagination.tsx index 4a10c6d06..489d6e659 100644 --- a/src/components/ui/pagination.tsx +++ b/src/components/ui/pagination.tsx @@ -52,6 +52,7 @@ export const Pagination: React.FC = ({ className="h-8 w-8" > + Previous page @@ -66,6 +67,7 @@ export const Pagination: React.FC = ({ className="h-8 w-8" > + Next page
);