@atercates/claude-deck 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +123 -0
- package/app/api/claude/hidden/route.ts +66 -0
- package/app/api/claude/projects/[name]/sessions/route.ts +71 -0
- package/app/api/claude/projects/route.ts +44 -0
- package/app/api/code-search/available/route.ts +12 -0
- package/app/api/code-search/route.ts +47 -0
- package/app/api/dev-servers/[id]/logs/route.ts +23 -0
- package/app/api/dev-servers/[id]/restart/route.ts +20 -0
- package/app/api/dev-servers/[id]/route.ts +51 -0
- package/app/api/dev-servers/[id]/stop/route.ts +20 -0
- package/app/api/dev-servers/detect/route.ts +39 -0
- package/app/api/dev-servers/route.ts +48 -0
- package/app/api/exec/route.ts +60 -0
- package/app/api/files/content/route.ts +76 -0
- package/app/api/files/route.ts +37 -0
- package/app/api/files/upload-temp/route.ts +41 -0
- package/app/api/git/check/route.ts +54 -0
- package/app/api/git/clone/route.ts +99 -0
- package/app/api/git/commit/route.ts +75 -0
- package/app/api/git/discard/route.ts +38 -0
- package/app/api/git/file-content/route.ts +64 -0
- package/app/api/git/history/[hash]/diff/route.ts +38 -0
- package/app/api/git/history/[hash]/route.ts +34 -0
- package/app/api/git/history/route.ts +27 -0
- package/app/api/git/multi-status/route.ts +46 -0
- package/app/api/git/pr/route.ts +164 -0
- package/app/api/git/push/route.ts +64 -0
- package/app/api/git/stage/route.ts +40 -0
- package/app/api/git/status/route.ts +51 -0
- package/app/api/git/unstage/route.ts +46 -0
- package/app/api/groups/[...path]/route.ts +136 -0
- package/app/api/groups/route.ts +93 -0
- package/app/api/orchestrate/spawn/route.ts +45 -0
- package/app/api/orchestrate/workers/[id]/route.ts +89 -0
- package/app/api/orchestrate/workers/route.ts +31 -0
- package/app/api/projects/[id]/detect/route.ts +27 -0
- package/app/api/projects/[id]/dev-servers/[dsId]/route.ts +66 -0
- package/app/api/projects/[id]/dev-servers/route.ts +51 -0
- package/app/api/projects/[id]/repositories/[repoId]/route.ts +67 -0
- package/app/api/projects/[id]/repositories/route.ts +74 -0
- package/app/api/projects/[id]/route.ts +108 -0
- package/app/api/projects/detect/route.ts +33 -0
- package/app/api/projects/route.ts +59 -0
- package/app/api/sessions/[id]/claude-session/route.ts +42 -0
- package/app/api/sessions/[id]/fork/route.ts +74 -0
- package/app/api/sessions/[id]/mcp-config/route.ts +34 -0
- package/app/api/sessions/[id]/messages/route.ts +60 -0
- package/app/api/sessions/[id]/pr/route.ts +188 -0
- package/app/api/sessions/[id]/preview/route.ts +42 -0
- package/app/api/sessions/[id]/route.ts +229 -0
- package/app/api/sessions/[id]/send-keys/route.ts +119 -0
- package/app/api/sessions/[id]/summarize/route.ts +331 -0
- package/app/api/sessions/init-script/route.ts +84 -0
- package/app/api/sessions/route.ts +209 -0
- package/app/api/sessions/status/route.ts +237 -0
- package/app/api/system/route.ts +9 -0
- package/app/api/tmux/kill-all/route.ts +57 -0
- package/app/api/tmux/rename/route.ts +30 -0
- package/app/globals.css +174 -0
- package/app/icon.svg +11 -0
- package/app/layout.tsx +122 -0
- package/app/page.tsx +629 -0
- package/components/ChatMessage.tsx +65 -0
- package/components/ChatView.tsx +276 -0
- package/components/ClaudeProjects/ClaudeProjectCard.tsx +195 -0
- package/components/ClaudeProjects/ClaudeProjectsSection.tsx +89 -0
- package/components/ClaudeProjects/ClaudeSessionCard.tsx +100 -0
- package/components/ClaudeProjects/index.ts +1 -0
- package/components/CodeSearch/CodeSearchResults.tsx +177 -0
- package/components/ConductorPanel.tsx +256 -0
- package/components/DevServers/DevServerCard.tsx +311 -0
- package/components/DevServers/DevServersSection.tsx +91 -0
- package/components/DevServers/ServerLogsModal.tsx +151 -0
- package/components/DevServers/StartServerDialog.tsx +359 -0
- package/components/DevServers/index.ts +4 -0
- package/components/DiffViewer/DiffModal.tsx +151 -0
- package/components/DiffViewer/UnifiedDiff.tsx +185 -0
- package/components/DiffViewer/index.tsx +2 -0
- package/components/DirectoryPicker.tsx +355 -0
- package/components/FileExplorer/FileEditor.tsx +276 -0
- package/components/FileExplorer/FileTabs.tsx +118 -0
- package/components/FileExplorer/FileTree.tsx +214 -0
- package/components/FileExplorer/HtmlRenderer.tsx +16 -0
- package/components/FileExplorer/MarkdownRenderer.tsx +18 -0
- package/components/FileExplorer/index.tsx +520 -0
- package/components/FilePicker.tsx +339 -0
- package/components/FolderPicker.tsx +201 -0
- package/components/GitDrawer/FileEditDialog.tsx +400 -0
- package/components/GitDrawer/index.tsx +464 -0
- package/components/GitPanel/CommitForm.tsx +205 -0
- package/components/GitPanel/CommitHistory.tsx +174 -0
- package/components/GitPanel/CommitItem.tsx +196 -0
- package/components/GitPanel/FileChanges.tsx +414 -0
- package/components/GitPanel/GitPanelTabs.tsx +39 -0
- package/components/GitPanel/index.tsx +817 -0
- package/components/MessageInput.tsx +82 -0
- package/components/NewClaudeSessionDialog.tsx +166 -0
- package/components/NewSessionDialog/AdvancedSettings.tsx +78 -0
- package/components/NewSessionDialog/AgentSelector.tsx +37 -0
- package/components/NewSessionDialog/CreatingOverlay.tsx +94 -0
- package/components/NewSessionDialog/NewSessionDialog.types.ts +136 -0
- package/components/NewSessionDialog/ProjectSelector.tsx +146 -0
- package/components/NewSessionDialog/WorkingDirectoryInput.tsx +55 -0
- package/components/NewSessionDialog/WorktreeSection.tsx +92 -0
- package/components/NewSessionDialog/hooks/useNewSessionForm.ts +370 -0
- package/components/NewSessionDialog/index.tsx +106 -0
- package/components/NotificationSettings.tsx +127 -0
- package/components/PRCreationModal.tsx +272 -0
- package/components/Pane/DesktopTabBar.tsx +353 -0
- package/components/Pane/MobileTabBar.tsx +210 -0
- package/components/Pane/OpenInVSCode.tsx +69 -0
- package/components/Pane/PaneSkeletons.tsx +57 -0
- package/components/Pane/index.tsx +558 -0
- package/components/PaneLayout.tsx +60 -0
- package/components/Projects/DevServersSection.tsx +140 -0
- package/components/Projects/DirectoryField.tsx +92 -0
- package/components/Projects/NewProjectDialog.tsx +188 -0
- package/components/Projects/NewProjectDialog.types.ts +46 -0
- package/components/Projects/ProjectCard.tsx +276 -0
- package/components/Projects/ProjectSettingsDialog.tsx +811 -0
- package/components/Projects/hooks/useNewProjectForm.ts +249 -0
- package/components/Projects/index.ts +3 -0
- package/components/Providers.tsx +49 -0
- package/components/QuickSwitcher.tsx +306 -0
- package/components/SessionList/KillAllConfirm.tsx +46 -0
- package/components/SessionList/SelectionToolbar.tsx +164 -0
- package/components/SessionList/SessionList.types.ts +37 -0
- package/components/SessionList/SessionListHeader.tsx +71 -0
- package/components/SessionList/hooks/useSessionListMutations.ts +269 -0
- package/components/SessionList/index.tsx +189 -0
- package/components/ShellDrawer/index.tsx +106 -0
- package/components/SidebarFooter.tsx +55 -0
- package/components/Terminal/KeybarToggleButton.tsx +45 -0
- package/components/Terminal/ScrollToBottomButton.tsx +32 -0
- package/components/Terminal/SearchBar.tsx +71 -0
- package/components/Terminal/TerminalToolbar.tsx +551 -0
- package/components/Terminal/VirtualKeyboard.tsx +711 -0
- package/components/Terminal/constants.ts +20 -0
- package/components/Terminal/hooks/index.ts +5 -0
- package/components/Terminal/hooks/resize-handlers.ts +140 -0
- package/components/Terminal/hooks/terminal-init.ts +151 -0
- package/components/Terminal/hooks/touch-scroll.ts +155 -0
- package/components/Terminal/hooks/useTerminalConnection.ts +282 -0
- package/components/Terminal/hooks/useTerminalConnection.types.ts +39 -0
- package/components/Terminal/hooks/useTerminalSearch.ts +103 -0
- package/components/Terminal/hooks/websocket-connection.ts +274 -0
- package/components/Terminal/index.tsx +320 -0
- package/components/ThemeToggle.tsx +168 -0
- package/components/TmuxSessions.tsx +132 -0
- package/components/ToolCallDisplay.tsx +71 -0
- package/components/WorkerCard.tsx +245 -0
- package/components/a/ABadge.tsx +115 -0
- package/components/a/AButton.tsx +163 -0
- package/components/a/ADialog.tsx +93 -0
- package/components/a/ADropdownMenu.tsx +279 -0
- package/components/a/AIconButton.tsx +190 -0
- package/components/a/ASheet.tsx +150 -0
- package/components/a/ATooltip.tsx +77 -0
- package/components/a/index.ts +64 -0
- package/components/mobile/SwipeSidebar.tsx +122 -0
- package/components/ui/badge.tsx +41 -0
- package/components/ui/button.tsx +60 -0
- package/components/ui/context-menu.tsx +197 -0
- package/components/ui/dialog.tsx +143 -0
- package/components/ui/dropdown-menu.tsx +257 -0
- package/components/ui/input.tsx +21 -0
- package/components/ui/scroll-area.tsx +52 -0
- package/components/ui/select.tsx +159 -0
- package/components/ui/skeleton.tsx +111 -0
- package/components/ui/switch.tsx +31 -0
- package/components/ui/textarea.tsx +21 -0
- package/components/ui/tooltip.tsx +32 -0
- package/components/views/DesktopView.tsx +244 -0
- package/components/views/MobileView.tsx +110 -0
- package/components/views/types.ts +75 -0
- package/contexts/PaneContext.tsx +336 -0
- package/data/claude/index.ts +9 -0
- package/data/claude/keys.ts +6 -0
- package/data/claude/queries.ts +120 -0
- package/data/claude/useClaudeUpdates.ts +37 -0
- package/data/code-search/index.ts +2 -0
- package/data/code-search/keys.ts +7 -0
- package/data/code-search/queries.ts +61 -0
- package/data/dev-servers/index.ts +8 -0
- package/data/dev-servers/keys.ts +4 -0
- package/data/dev-servers/queries.ts +104 -0
- package/data/files/index.ts +3 -0
- package/data/files/keys.ts +4 -0
- package/data/files/queries.ts +25 -0
- package/data/git/keys.ts +15 -0
- package/data/git/queries.ts +395 -0
- package/data/groups/index.ts +1 -0
- package/data/groups/mutations.ts +95 -0
- package/data/projects/index.ts +10 -0
- package/data/projects/keys.ts +4 -0
- package/data/projects/queries.ts +193 -0
- package/data/repositories/index.ts +7 -0
- package/data/repositories/keys.ts +5 -0
- package/data/repositories/queries.ts +122 -0
- package/data/sessions/index.ts +12 -0
- package/data/sessions/keys.ts +8 -0
- package/data/sessions/queries.ts +218 -0
- package/data/statuses/index.ts +1 -0
- package/data/statuses/queries.ts +69 -0
- package/hooks/useCopyToClipboard.ts +48 -0
- package/hooks/useDevServersManager.ts +73 -0
- package/hooks/useDirectoryBrowser.ts +90 -0
- package/hooks/useDrawerAnimation.ts +27 -0
- package/hooks/useFileDrop.ts +87 -0
- package/hooks/useFileEditor.ts +184 -0
- package/hooks/useGroups.ts +37 -0
- package/hooks/useHomePath.ts +34 -0
- package/hooks/useKeyRepeat.ts +55 -0
- package/hooks/useKeybarVisibility.ts +42 -0
- package/hooks/useNotifications.ts +257 -0
- package/hooks/useProjects.ts +53 -0
- package/hooks/useSessionStatuses.ts +30 -0
- package/hooks/useSessions.ts +86 -0
- package/hooks/useSpeechRecognition.ts +124 -0
- package/hooks/useViewport.ts +32 -0
- package/hooks/useViewportHeight.ts +50 -0
- package/lib/async-operations.ts +35 -0
- package/lib/banner.ts +81 -0
- package/lib/claude/jsonl-cache.ts +86 -0
- package/lib/claude/jsonl-reader.ts +271 -0
- package/lib/claude/process-manager.ts +278 -0
- package/lib/claude/stream-parser.ts +173 -0
- package/lib/claude/types.ts +154 -0
- package/lib/claude/watcher.ts +71 -0
- package/lib/client/session-registry.ts +111 -0
- package/lib/code-search.ts +121 -0
- package/lib/db/index.ts +48 -0
- package/lib/db/migrations.ts +45 -0
- package/lib/db/queries.ts +460 -0
- package/lib/db/schema.ts +114 -0
- package/lib/db/types.ts +92 -0
- package/lib/db.ts +2 -0
- package/lib/dev-servers.ts +509 -0
- package/lib/diff-parser.ts +221 -0
- package/lib/env-setup.ts +285 -0
- package/lib/file-upload.ts +34 -0
- package/lib/file-utils.ts +50 -0
- package/lib/files.ts +207 -0
- package/lib/git-history.ts +294 -0
- package/lib/git-status.ts +391 -0
- package/lib/git.ts +257 -0
- package/lib/mcp-config.ts +81 -0
- package/lib/multi-repo-git.ts +179 -0
- package/lib/notifications.ts +219 -0
- package/lib/orchestration.ts +448 -0
- package/lib/panes.ts +232 -0
- package/lib/ports.ts +97 -0
- package/lib/pr-generation.ts +307 -0
- package/lib/pr.ts +234 -0
- package/lib/projects.ts +578 -0
- package/lib/providers/registry.ts +70 -0
- package/lib/providers.ts +121 -0
- package/lib/query-client.ts +14 -0
- package/lib/rangeSelectionUtils.ts +65 -0
- package/lib/status-detector.ts +375 -0
- package/lib/terminal-themes.ts +265 -0
- package/lib/theme-config.ts +327 -0
- package/lib/utils.ts +6 -0
- package/lib/worktrees.ts +262 -0
- package/mcp/orchestration-server.ts +438 -0
- package/package.json +139 -0
- package/postcss.config.mjs +7 -0
- package/public/icon.svg +10 -0
- package/public/icons/icon-128x128.png +0 -0
- package/public/icons/icon-144x144.png +0 -0
- package/public/icons/icon-152x152.png +0 -0
- package/public/icons/icon-192x192.png +0 -0
- package/public/icons/icon-384x384.png +0 -0
- package/public/icons/icon-512x512.png +0 -0
- package/public/icons/icon-72x72.png +0 -0
- package/public/icons/icon-96x96.png +0 -0
- package/public/manifest.json +61 -0
- package/public/sw.js +64 -0
- package/scripts/agent-os +91 -0
- package/scripts/install.sh +48 -0
- package/scripts/lib/ai-clis.sh +132 -0
- package/scripts/lib/commands.sh +487 -0
- package/scripts/lib/common.sh +89 -0
- package/scripts/lib/prerequisites.sh +462 -0
- package/scripts/setup.sh +134 -0
- package/server.ts +155 -0
- package/stores/fileOpen.ts +26 -0
- package/stores/index.ts +1 -0
- package/stores/initialPrompt.ts +24 -0
- package/stores/sessionSelection.ts +48 -0
- package/styles/themes.css +603 -0
- package/tsconfig.json +33 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Button } from "./ui/button";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import {
|
|
7
|
+
Circle,
|
|
8
|
+
Loader2,
|
|
9
|
+
AlertCircle,
|
|
10
|
+
CheckCircle,
|
|
11
|
+
XCircle,
|
|
12
|
+
Eye,
|
|
13
|
+
Send,
|
|
14
|
+
X,
|
|
15
|
+
ChevronDown,
|
|
16
|
+
ChevronRight,
|
|
17
|
+
GitBranch,
|
|
18
|
+
} from "lucide-react";
|
|
19
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
|
20
|
+
|
|
21
|
+
export type WorkerStatus =
|
|
22
|
+
| "pending"
|
|
23
|
+
| "running"
|
|
24
|
+
| "waiting"
|
|
25
|
+
| "idle"
|
|
26
|
+
| "completed"
|
|
27
|
+
| "failed"
|
|
28
|
+
| "dead";
|
|
29
|
+
|
|
30
|
+
export interface WorkerInfo {
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
task: string;
|
|
34
|
+
status: WorkerStatus;
|
|
35
|
+
worktreePath: string | null;
|
|
36
|
+
branchName: string | null;
|
|
37
|
+
createdAt: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface WorkerCardProps {
|
|
41
|
+
worker: WorkerInfo;
|
|
42
|
+
isExpanded?: boolean;
|
|
43
|
+
output?: string;
|
|
44
|
+
onToggleExpand?: () => void;
|
|
45
|
+
onViewOutput?: () => void;
|
|
46
|
+
onSendMessage?: (message: string) => void;
|
|
47
|
+
onKill?: () => void;
|
|
48
|
+
onAttach?: () => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const statusConfig: Record<
|
|
52
|
+
WorkerStatus,
|
|
53
|
+
{ icon: typeof Circle; color: string; label: string }
|
|
54
|
+
> = {
|
|
55
|
+
pending: { icon: Circle, color: "text-muted-foreground", label: "Pending" },
|
|
56
|
+
running: { icon: Loader2, color: "text-green-500", label: "Running" },
|
|
57
|
+
waiting: { icon: AlertCircle, color: "text-yellow-500", label: "Waiting" },
|
|
58
|
+
idle: { icon: Circle, color: "text-muted-foreground", label: "Idle" },
|
|
59
|
+
completed: { icon: CheckCircle, color: "text-green-500", label: "Completed" },
|
|
60
|
+
failed: { icon: XCircle, color: "text-red-500", label: "Failed" },
|
|
61
|
+
dead: { icon: XCircle, color: "text-red-500", label: "Dead" },
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export function WorkerCard({
|
|
65
|
+
worker,
|
|
66
|
+
isExpanded = false,
|
|
67
|
+
output,
|
|
68
|
+
onToggleExpand,
|
|
69
|
+
onViewOutput,
|
|
70
|
+
onSendMessage,
|
|
71
|
+
onKill,
|
|
72
|
+
onAttach,
|
|
73
|
+
}: WorkerCardProps) {
|
|
74
|
+
const [message, setMessage] = useState("");
|
|
75
|
+
const [showSendInput, setShowSendInput] = useState(false);
|
|
76
|
+
|
|
77
|
+
const config = statusConfig[worker.status];
|
|
78
|
+
const StatusIcon = config.icon;
|
|
79
|
+
const isActive = worker.status === "running" || worker.status === "waiting";
|
|
80
|
+
|
|
81
|
+
const handleSend = () => {
|
|
82
|
+
if (message.trim() && onSendMessage) {
|
|
83
|
+
onSendMessage(message.trim());
|
|
84
|
+
setMessage("");
|
|
85
|
+
setShowSendInput(false);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div
|
|
91
|
+
className={cn(
|
|
92
|
+
"bg-card rounded-lg border transition-colors",
|
|
93
|
+
isActive && "border-primary/30",
|
|
94
|
+
worker.status === "completed" && "border-green-500/30 bg-green-500/5",
|
|
95
|
+
worker.status === "failed" && "border-red-500/30 bg-red-500/5"
|
|
96
|
+
)}
|
|
97
|
+
>
|
|
98
|
+
{/* Header */}
|
|
99
|
+
<div
|
|
100
|
+
className="hover:bg-accent/30 flex cursor-pointer items-center gap-2 p-3"
|
|
101
|
+
onClick={onToggleExpand}
|
|
102
|
+
>
|
|
103
|
+
<button className="p-0.5">
|
|
104
|
+
{isExpanded ? (
|
|
105
|
+
<ChevronDown className="text-muted-foreground h-3 w-3" />
|
|
106
|
+
) : (
|
|
107
|
+
<ChevronRight className="text-muted-foreground h-3 w-3" />
|
|
108
|
+
)}
|
|
109
|
+
</button>
|
|
110
|
+
|
|
111
|
+
<StatusIcon
|
|
112
|
+
className={cn(
|
|
113
|
+
"h-4 w-4 flex-shrink-0",
|
|
114
|
+
config.color,
|
|
115
|
+
worker.status === "running" && "animate-spin"
|
|
116
|
+
)}
|
|
117
|
+
/>
|
|
118
|
+
|
|
119
|
+
<div className="min-w-0 flex-1">
|
|
120
|
+
<div className="flex items-center gap-2">
|
|
121
|
+
<span className="truncate text-sm font-medium">{worker.name}</span>
|
|
122
|
+
<span
|
|
123
|
+
className={cn(
|
|
124
|
+
"rounded px-1.5 py-0.5 text-xs",
|
|
125
|
+
config.color,
|
|
126
|
+
"bg-current/10"
|
|
127
|
+
)}
|
|
128
|
+
>
|
|
129
|
+
{config.label}
|
|
130
|
+
</span>
|
|
131
|
+
</div>
|
|
132
|
+
{worker.branchName && (
|
|
133
|
+
<div className="text-muted-foreground mt-0.5 flex items-center gap-1 text-xs">
|
|
134
|
+
<GitBranch className="h-3 w-3" />
|
|
135
|
+
<span className="truncate">{worker.branchName}</span>
|
|
136
|
+
</div>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
{/* Quick actions */}
|
|
141
|
+
<div className="flex gap-1" onClick={(e) => e.stopPropagation()}>
|
|
142
|
+
{isActive && onAttach && (
|
|
143
|
+
<Tooltip>
|
|
144
|
+
<TooltipTrigger asChild>
|
|
145
|
+
<Button variant="ghost" size="icon-sm" onClick={onAttach}>
|
|
146
|
+
<Eye className="h-3 w-3" />
|
|
147
|
+
</Button>
|
|
148
|
+
</TooltipTrigger>
|
|
149
|
+
<TooltipContent>Attach to terminal</TooltipContent>
|
|
150
|
+
</Tooltip>
|
|
151
|
+
)}
|
|
152
|
+
{isActive && onKill && (
|
|
153
|
+
<Tooltip>
|
|
154
|
+
<TooltipTrigger asChild>
|
|
155
|
+
<Button
|
|
156
|
+
variant="ghost"
|
|
157
|
+
size="icon-sm"
|
|
158
|
+
onClick={onKill}
|
|
159
|
+
className="text-red-500 hover:text-red-400"
|
|
160
|
+
>
|
|
161
|
+
<X className="h-3 w-3" />
|
|
162
|
+
</Button>
|
|
163
|
+
</TooltipTrigger>
|
|
164
|
+
<TooltipContent>Kill worker</TooltipContent>
|
|
165
|
+
</Tooltip>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
{/* Expanded content */}
|
|
171
|
+
{isExpanded && (
|
|
172
|
+
<div className="border-border/50 space-y-2 border-t px-3 pb-3">
|
|
173
|
+
{/* Task */}
|
|
174
|
+
<div className="pt-2">
|
|
175
|
+
<div className="text-muted-foreground mb-1 text-xs">Task:</div>
|
|
176
|
+
<div className="bg-muted/30 rounded p-2 font-mono text-sm text-xs">
|
|
177
|
+
{worker.task}
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
{/* Output preview */}
|
|
182
|
+
{output && (
|
|
183
|
+
<div>
|
|
184
|
+
<div className="text-muted-foreground mb-1 text-xs">
|
|
185
|
+
Recent output:
|
|
186
|
+
</div>
|
|
187
|
+
<pre className="bg-muted/30 max-h-32 overflow-x-auto overflow-y-auto rounded p-2 font-mono text-xs whitespace-pre-wrap">
|
|
188
|
+
{output.slice(-500)}
|
|
189
|
+
</pre>
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
{/* Actions */}
|
|
194
|
+
<div className="flex gap-2 pt-1">
|
|
195
|
+
{onViewOutput && (
|
|
196
|
+
<Button variant="outline" size="sm" onClick={onViewOutput}>
|
|
197
|
+
<Eye className="mr-1 h-3 w-3" />
|
|
198
|
+
Full output
|
|
199
|
+
</Button>
|
|
200
|
+
)}
|
|
201
|
+
|
|
202
|
+
{isActive && onSendMessage && !showSendInput && (
|
|
203
|
+
<Button
|
|
204
|
+
variant="outline"
|
|
205
|
+
size="sm"
|
|
206
|
+
onClick={() => setShowSendInput(true)}
|
|
207
|
+
>
|
|
208
|
+
<Send className="mr-1 h-3 w-3" />
|
|
209
|
+
Send input
|
|
210
|
+
</Button>
|
|
211
|
+
)}
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
{/* Send input form */}
|
|
215
|
+
{showSendInput && (
|
|
216
|
+
<div className="flex gap-2">
|
|
217
|
+
<input
|
|
218
|
+
type="text"
|
|
219
|
+
value={message}
|
|
220
|
+
onChange={(e) => setMessage(e.target.value)}
|
|
221
|
+
onKeyDown={(e) => {
|
|
222
|
+
if (e.key === "Enter") handleSend();
|
|
223
|
+
if (e.key === "Escape") setShowSendInput(false);
|
|
224
|
+
}}
|
|
225
|
+
placeholder="Type message..."
|
|
226
|
+
className="bg-muted/50 focus:bg-muted focus:ring-primary/50 flex-1 rounded px-2 py-1 text-sm focus:ring-1 focus:outline-none"
|
|
227
|
+
autoFocus
|
|
228
|
+
/>
|
|
229
|
+
<Button size="sm" onClick={handleSend}>
|
|
230
|
+
Send
|
|
231
|
+
</Button>
|
|
232
|
+
<Button
|
|
233
|
+
size="sm"
|
|
234
|
+
variant="ghost"
|
|
235
|
+
onClick={() => setShowSendInput(false)}
|
|
236
|
+
>
|
|
237
|
+
Cancel
|
|
238
|
+
</Button>
|
|
239
|
+
</div>
|
|
240
|
+
)}
|
|
241
|
+
</div>
|
|
242
|
+
)}
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ABadge - Standard badge component for the design system
|
|
3
|
+
*
|
|
4
|
+
* A consistent badge for labels, statuses, and feature indicators.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* // Simple badge
|
|
9
|
+
* <ABadge>Default</ABadge>
|
|
10
|
+
*
|
|
11
|
+
* // New feature indicator
|
|
12
|
+
* <ABadge variant="new">New</ABadge>
|
|
13
|
+
*
|
|
14
|
+
* // Beta indicator
|
|
15
|
+
* <ABadge variant="beta">Beta</ABadge>
|
|
16
|
+
*
|
|
17
|
+
* // Small size
|
|
18
|
+
* <ABadge size="sm" variant="new">New</ABadge>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
"use client";
|
|
23
|
+
|
|
24
|
+
import { Badge } from "@/components/ui/badge";
|
|
25
|
+
import { cn } from "@/lib/utils";
|
|
26
|
+
|
|
27
|
+
export type ABadgeSize = "sm" | "md";
|
|
28
|
+
export type ABadgeVariant =
|
|
29
|
+
| "default"
|
|
30
|
+
| "secondary"
|
|
31
|
+
| "destructive"
|
|
32
|
+
| "outline"
|
|
33
|
+
| "new"
|
|
34
|
+
| "beta"
|
|
35
|
+
| "pro"
|
|
36
|
+
| "waiting"
|
|
37
|
+
| "running"
|
|
38
|
+
| "idle";
|
|
39
|
+
|
|
40
|
+
export interface ABadgeProps {
|
|
41
|
+
/** Badge content */
|
|
42
|
+
children: React.ReactNode;
|
|
43
|
+
/** Badge style variant */
|
|
44
|
+
variant?: ABadgeVariant;
|
|
45
|
+
/** Badge size */
|
|
46
|
+
size?: ABadgeSize;
|
|
47
|
+
/** Additional className */
|
|
48
|
+
className?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const SIZE_CLASSES: Record<ABadgeSize, string> = {
|
|
52
|
+
sm: "h-4 px-1.5 py-0 text-[10px] leading-none",
|
|
53
|
+
md: "h-5 px-2 py-0 text-xs leading-none",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const VARIANT_CLASSES: Record<ABadgeVariant, string> = {
|
|
57
|
+
default: "",
|
|
58
|
+
secondary: "",
|
|
59
|
+
destructive: "",
|
|
60
|
+
outline: "",
|
|
61
|
+
new: "border-transparent bg-emerald-500/15 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400",
|
|
62
|
+
beta: "border-transparent bg-amber-500/15 text-amber-600 dark:bg-amber-500/20 dark:text-amber-400",
|
|
63
|
+
pro: "border-transparent bg-violet-500/15 text-violet-600 dark:bg-violet-500/20 dark:text-violet-400",
|
|
64
|
+
waiting:
|
|
65
|
+
"border-transparent bg-yellow-500/15 text-yellow-600 dark:bg-yellow-500/20 dark:text-yellow-400",
|
|
66
|
+
running:
|
|
67
|
+
"border-transparent bg-green-500/15 text-green-600 dark:bg-green-500/20 dark:text-green-400",
|
|
68
|
+
idle: "border-transparent bg-gray-500/15 text-gray-600 dark:bg-gray-500/20 dark:text-gray-400",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const BASE_VARIANT_MAP: Record<
|
|
72
|
+
ABadgeVariant,
|
|
73
|
+
"default" | "secondary" | "destructive" | "outline"
|
|
74
|
+
> = {
|
|
75
|
+
default: "default",
|
|
76
|
+
secondary: "secondary",
|
|
77
|
+
destructive: "destructive",
|
|
78
|
+
outline: "outline",
|
|
79
|
+
new: "secondary",
|
|
80
|
+
beta: "secondary",
|
|
81
|
+
pro: "secondary",
|
|
82
|
+
waiting: "secondary",
|
|
83
|
+
running: "secondary",
|
|
84
|
+
idle: "secondary",
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export function ABadge({
|
|
88
|
+
children,
|
|
89
|
+
variant = "default",
|
|
90
|
+
size = "md",
|
|
91
|
+
className,
|
|
92
|
+
}: ABadgeProps) {
|
|
93
|
+
const isCustomVariant = [
|
|
94
|
+
"new",
|
|
95
|
+
"beta",
|
|
96
|
+
"pro",
|
|
97
|
+
"waiting",
|
|
98
|
+
"running",
|
|
99
|
+
"idle",
|
|
100
|
+
].includes(variant);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Badge
|
|
104
|
+
variant={BASE_VARIANT_MAP[variant]}
|
|
105
|
+
className={cn(
|
|
106
|
+
"flex items-center justify-center font-medium",
|
|
107
|
+
SIZE_CLASSES[size],
|
|
108
|
+
isCustomVariant && VARIANT_CLASSES[variant],
|
|
109
|
+
className
|
|
110
|
+
)}
|
|
111
|
+
>
|
|
112
|
+
{children}
|
|
113
|
+
</Badge>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AButton - Standard button component for the design system
|
|
3
|
+
*
|
|
4
|
+
* A consistent button with optional tooltip, loading state, and icon support.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* // Simple button
|
|
9
|
+
* <AButton onClick={handleClick}>Save</AButton>
|
|
10
|
+
*
|
|
11
|
+
* // With icon
|
|
12
|
+
* <AButton icon={Plus} onClick={handleClick}>Add item</AButton>
|
|
13
|
+
*
|
|
14
|
+
* // With tooltip
|
|
15
|
+
* <AButton tooltip="Save changes" onClick={handleClick}>Save</AButton>
|
|
16
|
+
*
|
|
17
|
+
* // Loading state
|
|
18
|
+
* <AButton loading onClick={handleClick}>Saving...</AButton>
|
|
19
|
+
*
|
|
20
|
+
* // Ghost variant (no background/border)
|
|
21
|
+
* <AButton variant="ghost" onClick={handleClick}>Cancel</AButton>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
"use client";
|
|
26
|
+
|
|
27
|
+
import { forwardRef } from "react";
|
|
28
|
+
import type { LucideIcon } from "lucide-react";
|
|
29
|
+
import { Loader2 } from "lucide-react";
|
|
30
|
+
import { Button } from "@/components/ui/button";
|
|
31
|
+
import { ATooltip } from "@/components/a/ATooltip";
|
|
32
|
+
import { cn } from "@/lib/utils";
|
|
33
|
+
|
|
34
|
+
export type AButtonSize = "sm" | "md" | "lg";
|
|
35
|
+
export type AButtonVariant =
|
|
36
|
+
| "default"
|
|
37
|
+
| "ghost"
|
|
38
|
+
| "outline"
|
|
39
|
+
| "secondary"
|
|
40
|
+
| "destructive"
|
|
41
|
+
| "link";
|
|
42
|
+
|
|
43
|
+
export interface AButtonProps extends Omit<
|
|
44
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
45
|
+
"children"
|
|
46
|
+
> {
|
|
47
|
+
/** Button content */
|
|
48
|
+
children?: React.ReactNode;
|
|
49
|
+
/** Optional Lucide icon component (shown before text) */
|
|
50
|
+
icon?: LucideIcon;
|
|
51
|
+
/** Optional icon shown after text */
|
|
52
|
+
iconRight?: LucideIcon;
|
|
53
|
+
/** Optional tooltip text */
|
|
54
|
+
tooltip?: string;
|
|
55
|
+
/** Optional keyboard shortcut hint for tooltip */
|
|
56
|
+
shortcut?: string;
|
|
57
|
+
/** Tooltip position */
|
|
58
|
+
tooltipSide?: "top" | "right" | "bottom" | "left";
|
|
59
|
+
/** Loading state - shows spinner and disables button */
|
|
60
|
+
loading?: boolean;
|
|
61
|
+
/** Button size variant */
|
|
62
|
+
size?: AButtonSize;
|
|
63
|
+
/** Button style variant */
|
|
64
|
+
variant?: AButtonVariant;
|
|
65
|
+
/** Make the button take full width */
|
|
66
|
+
fullWidth?: boolean;
|
|
67
|
+
/** Additional className for the icon */
|
|
68
|
+
iconClassName?: string;
|
|
69
|
+
/** Additional className */
|
|
70
|
+
className?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const SIZE_CLASSES: Record<AButtonSize, { button: string; icon: string }> = {
|
|
74
|
+
sm: { button: "h-7 px-2 text-xs", icon: "h-3.5 w-3.5" },
|
|
75
|
+
md: { button: "h-8 px-3 text-sm", icon: "h-4 w-4" },
|
|
76
|
+
lg: { button: "h-10 px-4 text-base", icon: "h-5 w-5" },
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const VARIANT_MAP: Record<
|
|
80
|
+
AButtonVariant,
|
|
81
|
+
"default" | "ghost" | "outline" | "secondary" | "destructive" | "link"
|
|
82
|
+
> = {
|
|
83
|
+
default: "default",
|
|
84
|
+
ghost: "ghost",
|
|
85
|
+
outline: "outline",
|
|
86
|
+
secondary: "secondary",
|
|
87
|
+
destructive: "destructive",
|
|
88
|
+
link: "link",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const AButton = forwardRef<HTMLButtonElement, AButtonProps>(
|
|
92
|
+
(
|
|
93
|
+
{
|
|
94
|
+
children,
|
|
95
|
+
icon: Icon,
|
|
96
|
+
iconRight: IconRight,
|
|
97
|
+
tooltip,
|
|
98
|
+
shortcut,
|
|
99
|
+
tooltipSide = "bottom",
|
|
100
|
+
loading = false,
|
|
101
|
+
size = "md",
|
|
102
|
+
variant = "default",
|
|
103
|
+
fullWidth = false,
|
|
104
|
+
iconClassName,
|
|
105
|
+
className,
|
|
106
|
+
disabled,
|
|
107
|
+
...props
|
|
108
|
+
},
|
|
109
|
+
ref
|
|
110
|
+
) => {
|
|
111
|
+
const sizeClasses = SIZE_CLASSES[size];
|
|
112
|
+
const isDisabled = disabled || loading;
|
|
113
|
+
|
|
114
|
+
const button = (
|
|
115
|
+
<Button
|
|
116
|
+
ref={ref}
|
|
117
|
+
variant={VARIANT_MAP[variant]}
|
|
118
|
+
disabled={isDisabled}
|
|
119
|
+
className={cn(
|
|
120
|
+
sizeClasses.button,
|
|
121
|
+
fullWidth && "w-full",
|
|
122
|
+
variant === "ghost" &&
|
|
123
|
+
"border-0 shadow-none ring-0 focus:ring-0 focus-visible:ring-0",
|
|
124
|
+
className
|
|
125
|
+
)}
|
|
126
|
+
{...props}
|
|
127
|
+
>
|
|
128
|
+
{loading ? (
|
|
129
|
+
<Loader2 className={cn(sizeClasses.icon, "mr-2 animate-spin")} />
|
|
130
|
+
) : Icon ? (
|
|
131
|
+
<Icon
|
|
132
|
+
className={cn(sizeClasses.icon, children && "mr-2", iconClassName)}
|
|
133
|
+
/>
|
|
134
|
+
) : null}
|
|
135
|
+
|
|
136
|
+
{children}
|
|
137
|
+
|
|
138
|
+
{IconRight && !loading && (
|
|
139
|
+
<IconRight
|
|
140
|
+
className={cn(sizeClasses.icon, children && "ml-2", iconClassName)}
|
|
141
|
+
/>
|
|
142
|
+
)}
|
|
143
|
+
</Button>
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
if (tooltip) {
|
|
147
|
+
return (
|
|
148
|
+
<ATooltip
|
|
149
|
+
content={tooltip}
|
|
150
|
+
shortcut={shortcut}
|
|
151
|
+
side={tooltipSide}
|
|
152
|
+
disabled={isDisabled}
|
|
153
|
+
>
|
|
154
|
+
{button}
|
|
155
|
+
</ATooltip>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return button;
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
AButton.displayName = "AButton";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADialog - Reusable dialog component for the design system
|
|
3
|
+
*
|
|
4
|
+
* A modal dialog with optional icon, header, scrollable content, and footer.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <ADialog
|
|
9
|
+
* open={isOpen}
|
|
10
|
+
* onOpenChange={setIsOpen}
|
|
11
|
+
* title="Settings"
|
|
12
|
+
* description="Manage your preferences"
|
|
13
|
+
* icon={<Settings />}
|
|
14
|
+
* footer={<Button>Save</Button>}
|
|
15
|
+
* >
|
|
16
|
+
* <SettingsContent />
|
|
17
|
+
* </ADialog>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
"use client";
|
|
22
|
+
|
|
23
|
+
import { ReactNode } from "react";
|
|
24
|
+
import {
|
|
25
|
+
Dialog,
|
|
26
|
+
DialogContent,
|
|
27
|
+
DialogDescription,
|
|
28
|
+
DialogHeader,
|
|
29
|
+
DialogTitle,
|
|
30
|
+
} from "@/components/ui/dialog";
|
|
31
|
+
import { cn } from "@/lib/utils";
|
|
32
|
+
|
|
33
|
+
export interface ADialogProps {
|
|
34
|
+
/** Controlled open state */
|
|
35
|
+
open: boolean;
|
|
36
|
+
/** Callback when open state changes */
|
|
37
|
+
onOpenChange: (open: boolean) => void;
|
|
38
|
+
/** Dialog title */
|
|
39
|
+
title: string;
|
|
40
|
+
/** Optional description below the title */
|
|
41
|
+
description?: string;
|
|
42
|
+
/** Optional icon to show next to title */
|
|
43
|
+
icon?: ReactNode;
|
|
44
|
+
/** Main content */
|
|
45
|
+
children: ReactNode;
|
|
46
|
+
/** Optional footer content (typically action buttons) */
|
|
47
|
+
footer?: ReactNode;
|
|
48
|
+
/** Maximum width class (default: "sm:max-w-lg") */
|
|
49
|
+
maxWidth?: string;
|
|
50
|
+
/** Additional className for the dialog content */
|
|
51
|
+
className?: string;
|
|
52
|
+
/** Additional className for the content container */
|
|
53
|
+
contentClassName?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function ADialog({
|
|
57
|
+
open,
|
|
58
|
+
onOpenChange,
|
|
59
|
+
title,
|
|
60
|
+
description,
|
|
61
|
+
icon,
|
|
62
|
+
children,
|
|
63
|
+
footer,
|
|
64
|
+
maxWidth = "sm:max-w-lg",
|
|
65
|
+
className,
|
|
66
|
+
contentClassName,
|
|
67
|
+
}: ADialogProps) {
|
|
68
|
+
return (
|
|
69
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
70
|
+
<DialogContent className={cn(maxWidth, className)}>
|
|
71
|
+
<DialogHeader>
|
|
72
|
+
<div className="flex items-center gap-2">
|
|
73
|
+
{icon && (
|
|
74
|
+
<span className="text-foreground [&>svg]:h-5 [&>svg]:w-5">
|
|
75
|
+
{icon}
|
|
76
|
+
</span>
|
|
77
|
+
)}
|
|
78
|
+
<DialogTitle>{title}</DialogTitle>
|
|
79
|
+
</div>
|
|
80
|
+
{description && <DialogDescription>{description}</DialogDescription>}
|
|
81
|
+
</DialogHeader>
|
|
82
|
+
|
|
83
|
+
<div className={cn("py-4", contentClassName)}>{children}</div>
|
|
84
|
+
|
|
85
|
+
{footer && (
|
|
86
|
+
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
|
87
|
+
{footer}
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
</DialogContent>
|
|
91
|
+
</Dialog>
|
|
92
|
+
);
|
|
93
|
+
}
|