feat: implement hooks system for project configuration

- Add HooksEditor component for managing project hooks
- Add ProjectSettings component for project-specific configurations
- Create hooksManager utility for hook operations
- Add hooks type definitions
- Update backend commands to support hooks functionality
- Integrate hooks into main app, agent execution, and Claude sessions
- Update API and utilities to handle hooks data
This commit is contained in:
Vivek R
2025-07-06 14:10:44 +05:30
parent 1922ffc145
commit 6b9393f4d3
15 changed files with 2294 additions and 311 deletions

View File

@@ -8,7 +8,6 @@ import {
ChevronDown,
GitBranch,
Settings,
Globe,
ChevronUp,
X,
Hash
@@ -46,6 +45,10 @@ interface ClaudeCodeSessionProps {
* Callback to go back
*/
onBack: () => void;
/**
* Callback to open hooks configuration
*/
onProjectSettings?: (projectPath: string) => void;
/**
* Optional className for styling
*/
@@ -66,6 +69,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
session,
initialProjectPath = "",
onBack,
onProjectSettings,
className,
onStreamingChange,
}) => {
@@ -792,8 +796,6 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
// Keep the previewUrl so it can be restored when reopening
};
const handlePreviewUrlChange = (url: string) => {
console.log('[ClaudeCodeSession] Preview URL changed to:', url);
setPreviewUrl(url);
@@ -971,107 +973,110 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
<ArrowLeft className="h-4 w-4" />
</Button>
<div className="flex items-center gap-2">
<Terminal className="h-5 w-5" />
<div>
<h2 className="text-lg font-semibold">Claude Code Session</h2>
<p className="text-xs text-muted-foreground">
{session ? `Resuming session ${session.id.slice(0, 8)}...` : 'Interactive session'}
<Terminal className="h-5 w-5 text-muted-foreground" />
<div className="flex-1">
<h1 className="text-xl font-bold">Claude Code Session</h1>
<p className="text-sm text-muted-foreground">
{projectPath ? `${projectPath}` : "No project selected"}
</p>
</div>
</div>
</div>
<div className="flex items-center gap-2">
{effectiveSession && (
<>
<Button
variant="outline"
size="sm"
onClick={() => setShowSettings(!showSettings)}
className="flex items-center gap-2"
>
<Settings className="h-4 w-4" />
Settings
</Button>
<Button
variant="outline"
size="sm"
onClick={() => setShowTimeline(!showTimeline)}
className="flex items-center gap-2"
>
<GitBranch className="h-4 w-4" />
Timeline
</Button>
</>
{projectPath && onProjectSettings && (
<Button
variant="outline"
size="sm"
onClick={() => onProjectSettings(projectPath)}
disabled={isLoading}
>
<Settings className="h-4 w-4 mr-2" />
Hooks
</Button>
)}
{/* Preview Button */}
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={() => {
if (!showPreview) {
// Open with current URL or empty URL to show the instruction state
setShowPreview(true);
} else {
handleClosePreview();
}
}}
className="flex items-center gap-2"
>
<Globe className="h-4 w-4" />
{showPreview ? "Close Preview" : "Preview"}
</Button>
</TooltipTrigger>
<TooltipContent>
{showPreview
? "Close the preview pane"
: "Open a browser preview to test your web applications"
<div className="flex items-center gap-2">
{showSettings && (
<CheckpointSettings
sessionId={effectiveSession?.id || ''}
projectId={effectiveSession?.project_id || ''}
projectPath={projectPath}
/>
)}
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => setShowSettings(!showSettings)}
className="h-8 w-8"
>
<Settings className={cn("h-4 w-4", showSettings && "text-primary")} />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Checkpoint Settings</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
{effectiveSession && (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => setShowTimeline(!showTimeline)}
className="h-8 w-8"
>
<GitBranch className={cn("h-4 w-4", showTimeline && "text-primary")} />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Timeline Navigator</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
{messages.length > 0 && (
<Popover
trigger={
<Button
variant="ghost"
size="sm"
className="flex items-center gap-2"
>
<Copy className="h-4 w-4" />
Copy Output
<ChevronDown className="h-3 w-3" />
</Button>
}
</TooltipContent>
</Tooltip>
</TooltipProvider>
{messages.length > 0 && (
<Popover
trigger={
<Button
variant="ghost"
size="sm"
className="flex items-center gap-2"
>
<Copy className="h-4 w-4" />
Copy Output
<ChevronDown className="h-3 w-3" />
</Button>
}
content={
<div className="w-44 p-1">
<Button
variant="ghost"
size="sm"
onClick={handleCopyAsMarkdown}
className="w-full justify-start"
>
Copy as Markdown
</Button>
<Button
variant="ghost"
size="sm"
onClick={handleCopyAsJsonl}
className="w-full justify-start"
>
Copy as JSONL
</Button>
</div>
}
open={copyPopoverOpen}
onOpenChange={setCopyPopoverOpen}
/>
)}
content={
<div className="w-44 p-1">
<Button
variant="ghost"
size="sm"
onClick={handleCopyAsMarkdown}
className="w-full justify-start"
>
Copy as Markdown
</Button>
<Button
variant="ghost"
size="sm"
onClick={handleCopyAsJsonl}
className="w-full justify-start"
>
Copy as JSONL
</Button>
</div>
}
open={copyPopoverOpen}
onOpenChange={setCopyPopoverOpen}
/>
)}
</div>
</div>
</motion.div>