diff --git a/archon-ui-main/src/features/style-guide/layouts/AgentWorkOrderLayoutExample.tsx b/archon-ui-main/src/features/style-guide/layouts/AgentWorkOrderLayoutExample.tsx
index 49eabd9d..5540ed6a 100644
--- a/archon-ui-main/src/features/style-guide/layouts/AgentWorkOrderLayoutExample.tsx
+++ b/archon-ui-main/src/features/style-guide/layouts/AgentWorkOrderLayoutExample.tsx
@@ -1,6 +1,8 @@
import {
Activity,
CheckCircle2,
+ ChevronDown,
+ ChevronUp,
Clock,
Copy,
Eye,
@@ -10,6 +12,7 @@ import {
Pin,
Play,
Plus,
+ Search,
Trash2,
} from "lucide-react";
import { useState } from "react";
@@ -24,6 +27,7 @@ import { SelectableCard } from "@/features/ui/primitives/selectable-card";
import { cn } from "@/features/ui/primitives/styles";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/features/ui/primitives/tooltip";
import { AgentWorkOrderExample } from "./AgentWorkOrderExample";
+import { RealTimeStatsExample } from "./components/RealTimeStatsExample";
const MOCK_REPOSITORIES = [
{
@@ -69,7 +73,7 @@ interface WorkOrder {
const MOCK_WORK_ORDERS: WorkOrder[] = [
{
- id: "wo-1",
+ id: "wo-1dc27d9e",
repositoryId: "1",
repositoryName: "archon-frontend",
request: "Add dark mode toggle to settings page",
@@ -78,7 +82,7 @@ const MOCK_WORK_ORDERS: WorkOrder[] = [
createdAt: "2024-01-15T10:30:00Z",
},
{
- id: "wo-2",
+ id: "wo-2af8b3c1",
repositoryId: "1",
repositoryName: "archon-frontend",
request: "Refactor navigation component to use new design system",
@@ -87,7 +91,7 @@ const MOCK_WORK_ORDERS: WorkOrder[] = [
createdAt: "2024-01-15T09:15:00Z",
},
{
- id: "wo-3",
+ id: "wo-4e372af3",
repositoryId: "2",
repositoryName: "archon-backend",
request: "Implement caching layer for API responses",
@@ -96,7 +100,7 @@ const MOCK_WORK_ORDERS: WorkOrder[] = [
createdAt: "2024-01-14T16:45:00Z",
},
{
- id: "wo-4",
+ id: "wo-8b91f2d6",
repositoryId: "2",
repositoryName: "archon-backend",
request: "Add rate limiting to authentication endpoints",
@@ -105,7 +109,7 @@ const MOCK_WORK_ORDERS: WorkOrder[] = [
createdAt: "2024-01-14T14:20:00Z",
},
{
- id: "wo-5",
+ id: "wo-5c7d4a89",
repositoryId: "1",
repositoryName: "archon-frontend",
request: "Fix responsive layout issues on mobile devices",
@@ -114,7 +118,7 @@ const MOCK_WORK_ORDERS: WorkOrder[] = [
createdAt: "2024-01-13T11:00:00Z",
},
{
- id: "wo-6",
+ id: "wo-9f3e1b5a",
repositoryId: "3",
repositoryName: "archon-docs",
request: "Update API documentation with new endpoints",
@@ -126,7 +130,7 @@ const MOCK_WORK_ORDERS: WorkOrder[] = [
export const AgentWorkOrderLayoutExample = () => {
const [selectedRepositoryId, setSelectedRepositoryId] = useState("1");
- const [layoutMode, setLayoutMode] = useState<"horizontal" | "sidebar">("horizontal");
+ const [layoutMode, setLayoutMode] = useState<"horizontal" | "sidebar">("sidebar");
const [sidebarExpanded, setSidebarExpanded] = useState(true);
const [showAddRepoModal, setShowAddRepoModal] = useState(false);
const [showNewWorkOrderModal, setShowNewWorkOrderModal] = useState(false);
@@ -134,6 +138,7 @@ export const AgentWorkOrderLayoutExample = () => {
const [activeTab, setActiveTab] = useState
("all");
const [showDetailView, setShowDetailView] = useState(false);
const [selectedWorkOrderId, setSelectedWorkOrderId] = useState(null);
+ const [searchQuery, setSearchQuery] = useState("");
const selectedRepository = MOCK_REPOSITORIES.find((r) => r.id === selectedRepositoryId);
const selectedWorkOrder = workOrders.find((wo) => wo.id === selectedWorkOrderId);
@@ -183,9 +188,42 @@ export const AgentWorkOrderLayoutExample = () => {
return (
- {/* Layout Mode Toggle */}
-
-
+ {/* Header Section */}
+
+ {/* Title */}
+
Agent Work Orders
+
+ {/* Search Bar */}
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10"
+ aria-label="Search repositories"
+ />
+
+
+ {/* View Toggle - Sidebar is default/primary */}
+
+ setLayoutMode("sidebar")}
+ className={cn(
+ "px-3",
+ layoutMode === "sidebar" && "bg-purple-500/20 dark:bg-purple-500/30 text-purple-400 dark:text-purple-300",
+ )}
+ aria-label="Switch to sidebar layout"
+ aria-pressed={layoutMode === "sidebar"}
+ >
+
+
{
>
- setLayoutMode("sidebar")}
- className={cn(
- "px-3",
- layoutMode === "sidebar" && "bg-purple-500/20 dark:bg-purple-500/30 text-purple-400 dark:text-purple-300",
- )}
- aria-label="Switch to sidebar layout"
- aria-pressed={layoutMode === "sidebar"}
- >
-
-
+
+ {/* New Repo Button */}
+
setShowAddRepoModal(true)} aria-label="Add new repository">
+
+ New Repo
+
+ {/* Add Repository Modal */}
+
+
{layoutMode === "horizontal" ? (
<>
{/* Horizontal Repository Cards - ONLY cards scroll, not whole page */}
@@ -233,8 +267,6 @@ export const AgentWorkOrderLayoutExample = () => {
}}
/>
))}
- {/* Add Repository Button */}
-
@@ -756,8 +788,9 @@ const WorkOrdersTableView = ({
-
- Work Order ID
+ WO ID
+
+ Repository
Request Summary
@@ -783,7 +816,7 @@ const WorkOrdersTableView = ({
);
};
-// Work Order Row with status-based styling
+// Work Order Row with status-based styling and expandable real-time stats
const WorkOrderRow = ({
workOrder,
index,
@@ -795,103 +828,165 @@ const WorkOrderRow = ({
onStart: () => void;
onViewDetails: () => void;
}) => {
+ const [isExpanded, setIsExpanded] = useState(false);
+
// Status colors - STATIC lookup with all properties
const statusColors: Record<
WorkOrderStatus,
- { color: "pink" | "cyan" | "blue" | "orange" | "purple" | "green"; edge: string; glow: string; label: string }
+ {
+ color: "pink" | "cyan" | "blue" | "orange" | "purple" | "green";
+ edge: string;
+ glow: string;
+ label: string;
+ stepNumber: number;
+ }
> = {
pending: {
color: "pink",
edge: "bg-pink-500",
glow: "rgba(236,72,153,0.5)",
label: "Pending",
+ stepNumber: 0,
},
create_branch: {
color: "cyan",
edge: "bg-cyan-500",
glow: "rgba(34,211,238,0.5)",
label: "+ Branch",
+ stepNumber: 1,
},
plan: {
color: "blue",
edge: "bg-blue-500",
glow: "rgba(59,130,246,0.5)",
label: "Planning",
+ stepNumber: 2,
},
execute: {
color: "orange",
edge: "bg-orange-500",
glow: "rgba(249,115,22,0.5)",
label: "Executing",
+ stepNumber: 3,
},
commit: {
color: "purple",
edge: "bg-purple-500",
glow: "rgba(168,85,247,0.5)",
label: "Commit",
+ stepNumber: 4,
},
create_pr: {
color: "green",
edge: "bg-green-500",
glow: "rgba(34,197,94,0.5)",
label: "Create PR",
+ stepNumber: 5,
},
};
const colors = statusColors[workOrder.status];
+ const canExpand = workOrder.status !== "pending";
+
+ const handleStart = () => {
+ setIsExpanded(true); // Auto-expand when started
+ onStart();
+ };
return (
-
- {/* Status indicator - glowing circle */}
-
-
-
-
- {/* Work Order ID */}
-
- {workOrder.id}
-
-
- {/* Request Summary */}
-
- {workOrder.request}
-
-
- {/* Status Badge - using StatPill */}
-
-
-
-
- {/* Actions */}
-
- {workOrder.status === "pending" ? (
-
-
- Start
-
- ) : (
-
-
- Observe
-
+ <>
+
-
+ >
+ {/* Status indicator - glowing circle with optional collapse button */}
+
+
+ {canExpand && (
+
setIsExpanded(!isExpanded)}
+ className="p-0.5 hover:bg-gray-200 dark:hover:bg-gray-700 rounded transition-colors"
+ aria-label={isExpanded ? "Collapse details" : "Expand details"}
+ aria-expanded={isExpanded}
+ >
+ {isExpanded ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+
+
+
+ {/* Work Order ID */}
+
+ {workOrder.id}
+
+
+ {/* Repository */}
+
+ {workOrder.repositoryName}
+
+
+ {/* Request Summary */}
+
+ {workOrder.request}
+
+
+ {/* Status Badge - using StatPill */}
+
+
+
+
+ {/* Actions */}
+
+ {workOrder.status === "pending" ? (
+
+
+ Start
+
+ ) : (
+
+
+ Details
+
+ )}
+
+
+
+ {/* Expanded row with real-time stats */}
+ {isExpanded && canExpand && (
+
+
+
+
+
+ )}
+ >
);
};
@@ -926,23 +1021,6 @@ const AddRepositoryModal = ({ open, onOpenChange }: { open: boolean; onOpenChang
return (
-
-
-
- Add Repository
-
-
Add Repository
diff --git a/archon-ui-main/src/features/style-guide/layouts/components/ExecutionLogsExample.tsx b/archon-ui-main/src/features/style-guide/layouts/components/ExecutionLogsExample.tsx
new file mode 100644
index 00000000..e9945ca7
--- /dev/null
+++ b/archon-ui-main/src/features/style-guide/layouts/components/ExecutionLogsExample.tsx
@@ -0,0 +1,212 @@
+import { Trash2 } from "lucide-react";
+import { useState } from "react";
+import { Button } from "@/features/ui/primitives/button";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/features/ui/primitives/select";
+import { cn } from "@/features/ui/primitives/styles";
+import { Switch } from "@/features/ui/primitives/switch";
+
+interface ExecutionLogsExampleProps {
+ /** Work order status to generate appropriate mock logs */
+ status: string;
+}
+
+interface MockLog {
+ timestamp: string;
+ level: "info" | "warning" | "error" | "debug";
+ event: string;
+ step?: string;
+ progress?: string;
+}
+
+/**
+ * Get color class for log level badge - STATIC lookup
+ */
+const logLevelColors: Record = {
+ info: "bg-blue-500/20 text-blue-600 dark:text-blue-400 border-blue-400/30",
+ warning: "bg-yellow-500/20 text-yellow-600 dark:text-yellow-400 border-yellow-400/30",
+ error: "bg-red-500/20 text-red-600 dark:text-red-400 border-red-400/30",
+ debug: "bg-gray-500/20 text-gray-600 dark:text-gray-400 border-gray-400/30",
+};
+
+/**
+ * Format timestamp to relative time
+ */
+function formatRelativeTime(timestamp: string): string {
+ const now = Date.now();
+ const logTime = new Date(timestamp).getTime();
+ const diffSeconds = Math.floor((now - logTime) / 1000);
+
+ if (diffSeconds < 60) return `${diffSeconds}s ago`;
+ if (diffSeconds < 3600) return `${Math.floor(diffSeconds / 60)}m ago`;
+ return `${Math.floor(diffSeconds / 3600)}h ago`;
+}
+
+/**
+ * Individual log entry component
+ */
+function LogEntryRow({ log }: { log: MockLog }) {
+ const colorClass = logLevelColors[log.level] || logLevelColors.debug;
+
+ return (
+
+
+ {formatRelativeTime(log.timestamp)}
+
+
+ {log.level}
+
+ {log.step && [{log.step}] }
+ {log.event}
+ {log.progress && (
+ {log.progress}
+ )}
+
+ );
+}
+
+export function ExecutionLogsExample({ status }: ExecutionLogsExampleProps) {
+ const [autoScroll, setAutoScroll] = useState(true);
+ const [levelFilter, setLevelFilter] = useState("all");
+
+ // Generate mock logs based on status
+ const generateMockLogs = (): MockLog[] => {
+ const now = Date.now();
+ const baseTime = now - 300000; // 5 minutes ago
+
+ const logs: MockLog[] = [
+ { timestamp: new Date(baseTime).toISOString(), level: "info", event: "workflow_started" },
+ { timestamp: new Date(baseTime + 1000).toISOString(), level: "info", event: "sandbox_setup_started" },
+ {
+ timestamp: new Date(baseTime + 3000).toISOString(),
+ level: "info",
+ event: "repository_cloned",
+ step: "setup",
+ },
+ { timestamp: new Date(baseTime + 5000).toISOString(), level: "info", event: "sandbox_setup_completed" },
+ ];
+
+ if (status !== "pending") {
+ logs.push(
+ {
+ timestamp: new Date(baseTime + 10000).toISOString(),
+ level: "info",
+ event: "step_started",
+ step: "create-branch",
+ progress: "1/5",
+ },
+ {
+ timestamp: new Date(baseTime + 12000).toISOString(),
+ level: "info",
+ event: "agent_command_started",
+ step: "create-branch",
+ },
+ {
+ timestamp: new Date(baseTime + 45000).toISOString(),
+ level: "info",
+ event: "branch_created",
+ step: "create-branch",
+ },
+ );
+ }
+
+ if (status === "plan" || status === "execute" || status === "commit" || status === "create_pr") {
+ logs.push(
+ {
+ timestamp: new Date(baseTime + 60000).toISOString(),
+ level: "info",
+ event: "step_started",
+ step: "planning",
+ progress: "2/5",
+ },
+ {
+ timestamp: new Date(baseTime + 120000).toISOString(),
+ level: "debug",
+ event: "analyzing_codebase",
+ step: "planning",
+ },
+ );
+ }
+
+ return logs;
+ };
+
+ const mockLogs = generateMockLogs();
+ const filteredLogs = levelFilter === "all" ? mockLogs : mockLogs.filter((log) => log.level === levelFilter);
+
+ return (
+
+ {/* Header with controls */}
+
+
+
Execution Logs
+
+ {/* Live indicator */}
+
+
+
({filteredLogs.length} entries)
+
+
+ {/* Controls */}
+
+ {/* Level filter using proper Select primitive */}
+
+
+
+
+
+ All Levels
+ Info
+ Warning
+ Error
+ Debug
+
+
+
+ {/* Auto-scroll toggle using Switch primitive */}
+
+
+ Auto-scroll:
+
+
+
+ {autoScroll ? "ON" : "OFF"}
+
+
+
+ {/* Clear logs button */}
+
+
+
+
+
+
+ {/* Log content - scrollable area */}
+
+ {filteredLogs.length === 0 ? (
+
+
No logs match the current filter
+
+ ) : (
+
+ {filteredLogs.map((log, index) => (
+
+ ))}
+
+ )}
+
+
+ );
+}
diff --git a/archon-ui-main/src/features/style-guide/layouts/components/RealTimeStatsExample.tsx b/archon-ui-main/src/features/style-guide/layouts/components/RealTimeStatsExample.tsx
new file mode 100644
index 00000000..aa554701
--- /dev/null
+++ b/archon-ui-main/src/features/style-guide/layouts/components/RealTimeStatsExample.tsx
@@ -0,0 +1,151 @@
+import { Activity, ChevronDown, ChevronUp, Clock, TrendingUp } from "lucide-react";
+import { useState } from "react";
+import { Button } from "@/features/ui/primitives/button";
+import { ExecutionLogsExample } from "./ExecutionLogsExample";
+
+interface RealTimeStatsExampleProps {
+ /** Work order status for determining progress */
+ status: string;
+ /** Step number (1-5) */
+ stepNumber: number;
+}
+
+/**
+ * Format elapsed seconds to human-readable duration
+ */
+function formatDuration(seconds: number): string {
+ const hours = Math.floor(seconds / 3600);
+ const minutes = Math.floor((seconds % 3600) / 60);
+ const secs = seconds % 60;
+
+ if (hours > 0) {
+ return `${hours}h ${minutes}m ${secs}s`;
+ }
+ if (minutes > 0) {
+ return `${minutes}m ${secs}s`;
+ }
+ return `${secs}s`;
+}
+
+export function RealTimeStatsExample({ status, stepNumber }: RealTimeStatsExampleProps) {
+ const [showLogs, setShowLogs] = useState(false);
+
+ // Mock data based on status
+ const stepNames: Record = {
+ create_branch: "create-branch",
+ plan: "planning",
+ execute: "execute",
+ commit: "commit",
+ create_pr: "create-pr",
+ };
+
+ const currentStep = stepNames[status] || "initializing";
+ const progressPct = (stepNumber / 5) * 100;
+ const mockElapsedSeconds = stepNumber * 120; // 2 minutes per step
+
+ const activities: Record = {
+ create_branch: "Creating new branch for work order...",
+ plan: "Analyzing codebase and generating implementation plan...",
+ execute: "Writing code and applying changes...",
+ commit: "Committing changes to branch...",
+ create_pr: "Creating pull request on GitHub...",
+ };
+
+ const currentActivity = activities[status] || "Initializing workflow...";
+
+ return (
+
+
+
+
+ Real-Time Execution
+
+
+
+ {/* Current Step */}
+
+
Current Step
+
+ {currentStep}
+ ({stepNumber}/5)
+
+
+
+ {/* Progress */}
+
+
+ {/* Elapsed Time */}
+
+
+
+ Elapsed Time
+
+
+ {formatDuration(mockElapsedSeconds)}
+
+
+
+
+ {/* Latest Activity with Status Indicator - at top */}
+
+
+
+
+ Latest Activity:
+
+
{currentActivity}
+
+ {/* Status Indicator - right side of Latest Activity */}
+
+
+
+
+ {/* Show Execution Logs button - at bottom */}
+
+ setShowLogs(!showLogs)}
+ className="w-full justify-center text-cyan-600 dark:text-cyan-400 hover:bg-cyan-500/10"
+ aria-label={showLogs ? "Hide execution logs" : "Show execution logs"}
+ aria-expanded={showLogs}
+ >
+ {showLogs ? (
+ <>
+
+ Hide Execution Logs
+ >
+ ) : (
+ <>
+
+ Show Execution Logs
+ >
+ )}
+
+
+
+
+ {/* Collapsible Execution Logs */}
+ {showLogs &&
}
+
+ );
+}
diff --git a/archon-ui-main/src/features/style-guide/tabs/LayoutsTab.tsx b/archon-ui-main/src/features/style-guide/tabs/LayoutsTab.tsx
index b07deb84..a380abb7 100644
--- a/archon-ui-main/src/features/style-guide/tabs/LayoutsTab.tsx
+++ b/archon-ui-main/src/features/style-guide/tabs/LayoutsTab.tsx
@@ -1,6 +1,5 @@
import { Briefcase, Database, FileText, FolderKanban, Navigation, Settings } from "lucide-react";
import { useState } from "react";
-import { AgentWorkOrderExample } from "../layouts/AgentWorkOrderExample";
import { AgentWorkOrderLayoutExample } from "../layouts/AgentWorkOrderLayoutExample";
import { DocumentBrowserExample } from "../layouts/DocumentBrowserExample";
import { KnowledgeLayoutExample } from "../layouts/KnowledgeLayoutExample";
diff --git a/docker-compose.yml b/docker-compose.yml
index 68fdffb7..f985da73 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -172,6 +172,7 @@ services:
- SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
+ - CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN:-}
- LOGFIRE_TOKEN=${LOGFIRE_TOKEN:-}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
- AGENT_WORK_ORDERS_PORT=${AGENT_WORK_ORDERS_PORT:-8053}
diff --git a/python/Dockerfile.agent-work-orders b/python/Dockerfile.agent-work-orders
index 72dc2ebc..d7da368d 100644
--- a/python/Dockerfile.agent-work-orders
+++ b/python/Dockerfile.agent-work-orders
@@ -59,6 +59,10 @@ RUN mkdir -p /repos /tmp/agent-work-orders && \
USER agentuser
RUN curl -fsSL https://claude.ai/install.sh | bash
+# Configure git to use gh CLI for GitHub authentication
+# This allows git clone to authenticate using GH_TOKEN environment variable
+RUN git config --global credential.helper '!gh auth git-credential'
+
# Set environment variables
ENV PYTHONPATH="/app:$PYTHONPATH"
ENV PYTHONUNBUFFERED=1