refactor: replace fs with secureFs for improved file handling

This commit updates various modules to utilize the secure file system operations from the secureFs module instead of the native fs module. Key changes include:

- Replaced fs imports with secureFs in multiple route handlers and services to enhance security and consistency in file operations.
- Added centralized validation for working directories in the sdk-options module to ensure all AI model invocations are secure.

These changes aim to improve the security and maintainability of file handling across the application.
This commit is contained in:
Test User
2025-12-21 01:32:26 -05:00
parent 2b5479ae0d
commit 077a63b03b
62 changed files with 4866 additions and 3350 deletions

View File

@@ -1,8 +1,9 @@
import { Label } from "@/components/ui/label";
import { Palette } from "lucide-react";
import { themeOptions } from "@/config/theme-options";
import { cn } from "@/lib/utils";
import type { Theme, Project } from "../shared/types";
import { useState } from 'react';
import { Label } from '@/components/ui/label';
import { Palette, Moon, Sun } from 'lucide-react';
import { darkThemes, lightThemes } from '@/config/theme-options';
import { cn } from '@/lib/utils';
import type { Theme, Project } from '../shared/types';
interface AppearanceSectionProps {
effectiveTheme: Theme;
@@ -15,13 +16,17 @@ export function AppearanceSection({
currentProject,
onThemeChange,
}: AppearanceSectionProps) {
const [activeTab, setActiveTab] = useState<'dark' | 'light'>('dark');
const themesToShow = activeTab === 'dark' ? darkThemes : lightThemes;
return (
<div
className={cn(
"rounded-2xl overflow-hidden",
"border border-border/50",
"bg-gradient-to-br from-card/90 via-card/70 to-card/80 backdrop-blur-xl",
"shadow-sm shadow-black/5"
'rounded-2xl overflow-hidden',
'border border-border/50',
'bg-gradient-to-br from-card/90 via-card/70 to-card/80 backdrop-blur-xl',
'shadow-sm shadow-black/5'
)}
>
<div className="p-6 border-b border-border/50 bg-gradient-to-r from-transparent via-accent/5 to-transparent">
@@ -37,43 +42,69 @@ export function AppearanceSection({
</div>
<div className="p-6 space-y-4">
<div className="space-y-4">
<Label className="text-foreground font-medium">
Theme{" "}
<span className="text-muted-foreground font-normal">
{currentProject ? `(for ${currentProject.name})` : "(Global)"}
</span>
</Label>
<div className="flex items-center justify-between">
<Label className="text-foreground font-medium">
Theme{' '}
<span className="text-muted-foreground font-normal">
{currentProject ? `(for ${currentProject.name})` : '(Global)'}
</span>
</Label>
{/* Dark/Light Tabs */}
<div className="flex gap-1 p-1 rounded-lg bg-accent/30">
<button
onClick={() => setActiveTab('dark')}
className={cn(
'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200',
activeTab === 'dark'
? 'bg-brand-500 text-white shadow-sm'
: 'text-muted-foreground hover:text-foreground'
)}
>
<Moon className="w-3.5 h-3.5" />
Dark
</button>
<button
onClick={() => setActiveTab('light')}
className={cn(
'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200',
activeTab === 'light'
? 'bg-brand-500 text-white shadow-sm'
: 'text-muted-foreground hover:text-foreground'
)}
>
<Sun className="w-3.5 h-3.5" />
Light
</button>
</div>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{themeOptions.map(({ value, label, Icon, testId }) => {
{themesToShow.map(({ value, label, Icon, testId, color }) => {
const isActive = effectiveTheme === value;
return (
<button
key={value}
onClick={() => onThemeChange(value)}
className={cn(
"group flex items-center justify-center gap-2.5 px-4 py-3.5 rounded-xl",
"text-sm font-medium transition-all duration-200 ease-out",
'group flex items-center justify-center gap-2.5 px-4 py-3.5 rounded-xl',
'text-sm font-medium transition-all duration-200 ease-out',
isActive
? [
"bg-gradient-to-br from-brand-500/15 to-brand-600/10",
"border-2 border-brand-500/40",
"text-foreground",
"shadow-md shadow-brand-500/10",
'bg-gradient-to-br from-brand-500/15 to-brand-600/10',
'border-2 border-brand-500/40',
'text-foreground',
'shadow-md shadow-brand-500/10',
]
: [
"bg-accent/30 hover:bg-accent/50",
"border border-border/50 hover:border-border",
"text-muted-foreground hover:text-foreground",
"hover:shadow-sm",
'bg-accent/30 hover:bg-accent/50',
'border border-border/50 hover:border-border',
'text-muted-foreground hover:text-foreground',
'hover:shadow-sm',
],
"hover:scale-[1.02] active:scale-[0.98]"
'hover:scale-[1.02] active:scale-[0.98]'
)}
data-testid={testId}
>
<Icon className={cn(
"w-4 h-4 transition-all duration-200",
isActive ? "text-brand-500" : "group-hover:text-brand-400"
)} />
<Icon className="w-4 h-4 transition-all duration-200" style={{ color }} />
<span>{label}</span>
</button>
);

View File

@@ -1,4 +1,6 @@
// Shared TypeScript types for settings view components
// Theme type is now imported from the central theme-options config
export { type Theme } from '@/config/theme-options';
export interface CliStatus {
success: boolean;
@@ -17,31 +19,13 @@ export interface CliStatus {
error?: string;
}
export type Theme =
| "dark"
| "light"
| "retro"
| "dracula"
| "nord"
| "monokai"
| "tokyonight"
| "solarized"
| "gruvbox"
| "catppuccin"
| "onedark"
| "synthwave"
| "red"
| "cream"
| "sunset"
| "gray";
export type KanbanDetailLevel = "minimal" | "standard" | "detailed";
export type KanbanDetailLevel = 'minimal' | 'standard' | 'detailed';
export interface Project {
id: string;
name: string;
path: string;
theme?: Theme;
theme?: string;
}
export interface ApiKeys {

View File

@@ -1,8 +1,9 @@
import { Button } from "@/components/ui/button";
import { ArrowRight, ArrowLeft, Check } from "lucide-react";
import { themeOptions } from "@/config/theme-options";
import { useAppStore } from "@/store/app-store";
import { cn } from "@/lib/utils";
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { ArrowRight, ArrowLeft, Check, Moon, Sun } from 'lucide-react';
import { darkThemes, lightThemes } from '@/config/theme-options';
import { useAppStore } from '@/store/app-store';
import { cn } from '@/lib/utils';
interface ThemeStepProps {
onNext: () => void;
@@ -11,6 +12,7 @@ interface ThemeStepProps {
export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
const { theme, setTheme, setPreviewTheme } = useAppStore();
const [activeTab, setActiveTab] = useState<'dark' | 'light'>('dark');
const handleThemeHover = (themeValue: string) => {
setPreviewTheme(themeValue as typeof theme);
@@ -25,19 +27,47 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
setPreviewTheme(null);
};
const themesToShow = activeTab === 'dark' ? darkThemes : lightThemes;
return (
<div className="space-y-6">
<div className="text-center">
<h2 className="text-3xl font-bold text-foreground mb-3">
Choose Your Theme
</h2>
<h2 className="text-3xl font-bold text-foreground mb-3">Choose Your Theme</h2>
<p className="text-muted-foreground max-w-md mx-auto">
Pick a theme that suits your style. Hover to preview, click to select.
</p>
</div>
{/* Dark/Light Tabs */}
<div className="flex justify-center gap-2">
<button
onClick={() => setActiveTab('dark')}
className={cn(
'flex items-center gap-2 px-6 py-2.5 rounded-lg font-medium transition-all duration-200',
activeTab === 'dark'
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
: 'bg-accent/50 text-muted-foreground hover:bg-accent hover:text-foreground'
)}
>
<Moon className="w-4 h-4" />
Dark Themes
</button>
<button
onClick={() => setActiveTab('light')}
className={cn(
'flex items-center gap-2 px-6 py-2.5 rounded-lg font-medium transition-all duration-200',
activeTab === 'light'
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
: 'bg-accent/50 text-muted-foreground hover:bg-accent hover:text-foreground'
)}
>
<Sun className="w-4 h-4" />
Light Themes
</button>
</div>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
{themeOptions.map((option) => {
{themesToShow.map((option) => {
const Icon = option.Icon;
const isSelected = theme === option.value;
@@ -49,11 +79,11 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
onMouseLeave={handleThemeLeave}
onClick={() => handleThemeClick(option.value)}
className={cn(
"relative flex flex-col items-center gap-2 p-4 rounded-lg border-2 transition-all duration-200",
"hover:scale-105 hover:shadow-lg",
'relative flex flex-col items-center gap-2 p-4 rounded-lg border-2 transition-all duration-200',
'hover:scale-105 hover:shadow-lg',
isSelected
? "border-brand-500 bg-brand-500/10"
: "border-border hover:border-brand-400 bg-card"
? 'border-brand-500 bg-brand-500/10'
: 'border-border hover:border-brand-400 bg-card'
)}
>
{isSelected && (
@@ -61,10 +91,8 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
<Check className="w-4 h-4 text-brand-500" />
</div>
)}
<Icon className="w-6 h-6 text-foreground" />
<span className="text-sm font-medium text-foreground">
{option.label}
</span>
<Icon className="w-6 h-6" style={{ color: option.color }} />
<span className="text-sm font-medium text-foreground">{option.label}</span>
</button>
);
})}