rax-flow 0.1.7 → 0.1.9

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.
Files changed (56) hide show
  1. package/dist/tui/App.d.ts.map +1 -1
  2. package/dist/tui/App.js +43 -3
  3. package/dist/tui/App.js.map +1 -1
  4. package/dist/tui/components/ChatPanel.d.ts +2 -1
  5. package/dist/tui/components/ChatPanel.d.ts.map +1 -1
  6. package/dist/tui/components/ChatPanel.js +3 -2
  7. package/dist/tui/components/ChatPanel.js.map +1 -1
  8. package/dist/tui/components/DAGPanel.d.ts +24 -0
  9. package/dist/tui/components/DAGPanel.d.ts.map +1 -0
  10. package/dist/tui/components/DAGPanel.js +30 -0
  11. package/dist/tui/components/DAGPanel.js.map +1 -0
  12. package/dist/tui/components/Header.d.ts +3 -1
  13. package/dist/tui/components/Header.d.ts.map +1 -1
  14. package/dist/tui/components/Header.js +15 -3
  15. package/dist/tui/components/Header.js.map +1 -1
  16. package/dist/tui/components/HelpOverlay.d.ts +6 -0
  17. package/dist/tui/components/HelpOverlay.d.ts.map +1 -0
  18. package/dist/tui/components/HelpOverlay.js +42 -0
  19. package/dist/tui/components/HelpOverlay.js.map +1 -0
  20. package/dist/tui/components/LogsPanel.d.ts +7 -0
  21. package/dist/tui/components/LogsPanel.d.ts.map +1 -0
  22. package/dist/tui/components/LogsPanel.js +7 -0
  23. package/dist/tui/components/LogsPanel.js.map +1 -0
  24. package/dist/tui/components/MemoryPanel.d.ts +19 -0
  25. package/dist/tui/components/MemoryPanel.d.ts.map +1 -0
  26. package/dist/tui/components/MemoryPanel.js +24 -0
  27. package/dist/tui/components/MemoryPanel.js.map +1 -0
  28. package/dist/tui/components/MetricsPanel.d.ts +13 -0
  29. package/dist/tui/components/MetricsPanel.d.ts.map +1 -0
  30. package/dist/tui/components/MetricsPanel.js +14 -0
  31. package/dist/tui/components/MetricsPanel.js.map +1 -0
  32. package/dist/tui/components/StatusPanel.d.ts +2 -1
  33. package/dist/tui/components/StatusPanel.d.ts.map +1 -1
  34. package/dist/tui/components/StatusPanel.js +7 -6
  35. package/dist/tui/components/StatusPanel.js.map +1 -1
  36. package/dist/tui/hooks/useAppState.d.ts +24 -0
  37. package/dist/tui/hooks/useAppState.d.ts.map +1 -1
  38. package/dist/tui/hooks/useAppState.js +194 -43
  39. package/dist/tui/hooks/useAppState.js.map +1 -1
  40. package/dist/tui/services/orchestrator.d.ts +16 -0
  41. package/dist/tui/services/orchestrator.d.ts.map +1 -0
  42. package/dist/tui/services/orchestrator.js +108 -0
  43. package/dist/tui/services/orchestrator.js.map +1 -0
  44. package/package.json +1 -1
  45. package/src/tui/App.tsx +104 -19
  46. package/src/tui/components/ChatPanel.tsx +8 -4
  47. package/src/tui/components/DAGPanel.tsx +116 -0
  48. package/src/tui/components/Header.tsx +51 -19
  49. package/src/tui/components/HelpOverlay.tsx +83 -0
  50. package/src/tui/components/LogsPanel.tsx +37 -0
  51. package/src/tui/components/MemoryPanel.tsx +99 -0
  52. package/src/tui/components/MetricsPanel.tsx +108 -0
  53. package/src/tui/components/StatusPanel.tsx +13 -8
  54. package/src/tui/hooks/useAppState.ts +259 -44
  55. package/src/tui/services/orchestrator.ts +142 -0
  56. package/tsconfig.tsbuildinfo +1 -1
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Box, Text, useInput } from "ink";
2
+ import { Box, Text } from "ink";
3
3
 
4
4
  interface Message {
5
5
  id: string;
@@ -12,6 +12,7 @@ interface Message {
12
12
  interface ChatPanelProps {
13
13
  messages: Message[];
14
14
  isProcessing: boolean;
15
+ isActive: boolean;
15
16
  }
16
17
 
17
18
  function formatTime(date: Date): string {
@@ -22,7 +23,7 @@ function formatTime(date: Date): string {
22
23
  });
23
24
  }
24
25
 
25
- function MessageItem({ message }: { message: Message; key?: string }) {
26
+ function MessageItem({ message }: { message: Message }) {
26
27
  const typeColors: Record<string, string> = {
27
28
  user: "cyan",
28
29
  system: "gray",
@@ -51,18 +52,21 @@ function MessageItem({ message }: { message: Message; key?: string }) {
51
52
  );
52
53
  }
53
54
 
54
- export function ChatPanel({ messages, isProcessing }: ChatPanelProps) {
55
+ export function ChatPanel({ messages, isProcessing, isActive }: ChatPanelProps) {
56
+ const borderColor = isActive ? "#f97316" : "gray";
57
+
55
58
  return (
56
59
  <Box
57
60
  flexDirection="column"
58
61
  flexGrow={2}
59
62
  borderStyle="single"
60
- borderColor="gray"
63
+ borderColor={borderColor}
61
64
  paddingX={1}
62
65
  >
63
66
  <Box borderStyle="single" borderColor="#f97316" marginBottom={1}>
64
67
  <Text color="#f97316" bold>CHAT</Text>
65
68
  <Text color="gray"> — Tapez /help pour les commandes</Text>
69
+ {isActive && <Text color="yellow"> [ACTIF]</Text>}
66
70
  </Box>
67
71
  <Box flexDirection="column" flexGrow={1} overflow="hidden">
68
72
  {messages.slice(-15).map((msg) => (
@@ -0,0 +1,116 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface DAGNode {
5
+ id: string;
6
+ name: string;
7
+ status: "pending" | "running" | "done" | "error";
8
+ agent?: string;
9
+ }
10
+
11
+ interface DAGLevel {
12
+ name: string;
13
+ progress: number;
14
+ nodes: DAGNode[];
15
+ }
16
+
17
+ interface WorkflowState {
18
+ levels: DAGLevel[];
19
+ currentLevel: number;
20
+ totalProgress: number;
21
+ }
22
+
23
+ interface DAGPanelProps {
24
+ workflowState: WorkflowState;
25
+ tick: number;
26
+ isActive: boolean;
27
+ }
28
+
29
+ const statusIcons: Record<string, { icon: string; color: string }> = {
30
+ pending: { icon: "○", color: "gray" },
31
+ running: { icon: "▶", color: "yellow" },
32
+ done: { icon: "●", color: "green" },
33
+ error: { icon: "✗", color: "red" },
34
+ };
35
+
36
+ const spinnerFrames = ["◐", "◓", "◑", "◒"];
37
+
38
+ function ProgressBar({ progress, width = 20 }: { progress: number; width?: number }) {
39
+ const filled = Math.round((progress / 100) * width);
40
+ const empty = width - filled;
41
+ const bar = "█".repeat(filled) + "░".repeat(empty);
42
+ return (
43
+ <Text color={progress >= 100 ? "green" : progress > 0 ? "yellow" : "gray"}>
44
+ {bar}
45
+ </Text>
46
+ );
47
+ }
48
+
49
+ function DAGNodeItem({ node, tick }: { node: DAGNode; tick: number }) {
50
+ const { icon, color } = statusIcons[node.status];
51
+ const animatedIcon = node.status === "running"
52
+ ? spinnerFrames[tick % spinnerFrames.length]
53
+ : icon;
54
+
55
+ return (
56
+ <Box flexDirection="row" marginLeft={2}>
57
+ <Text color={color}>{animatedIcon}</Text>
58
+ <Text color="white"> {node.name}</Text>
59
+ {node.agent && <Text color="gray"> [{node.agent}]</Text>}
60
+ </Box>
61
+ );
62
+ }
63
+
64
+ function DAGLevelView({ level, tick, isActive }: { level: DAGLevel; tick: number; isActive: boolean }) {
65
+ return (
66
+ <Box flexDirection="column" marginBottom={1}>
67
+ <Box flexDirection="row">
68
+ <Text color={isActive ? "#f97316" : "gray"} bold={isActive}>
69
+ {level.name}
70
+ </Text>
71
+ <Text color="gray"> </Text>
72
+ <ProgressBar progress={level.progress} width={12} />
73
+ <Text color="gray"> {level.progress}%</Text>
74
+ </Box>
75
+ {level.nodes.map((node) => (
76
+ <DAGNodeItem key={node.id} node={node} tick={tick} />
77
+ ))}
78
+ </Box>
79
+ );
80
+ }
81
+
82
+ export function DAGPanel({ workflowState, tick, isActive }: DAGPanelProps) {
83
+ const borderColor = isActive ? "#f97316" : "gray";
84
+
85
+ return (
86
+ <Box
87
+ flexDirection="column"
88
+ width={40}
89
+ borderStyle="single"
90
+ borderColor={borderColor}
91
+ paddingX={1}
92
+ >
93
+ <Box borderStyle="single" borderColor="#f97316" marginBottom={1}>
94
+ <Text color="#f97316" bold>DAG</Text>
95
+ <Text color="gray"> EXECUTION</Text>
96
+ </Box>
97
+
98
+ <Box flexDirection="column" flexGrow={1}>
99
+ {workflowState.levels.map((level, index) => (
100
+ <DAGLevelView
101
+ key={level.name}
102
+ level={level}
103
+ tick={tick}
104
+ isActive={index === workflowState.currentLevel}
105
+ />
106
+ ))}
107
+ </Box>
108
+
109
+ <Box borderStyle="single" borderColor="gray" marginTop={1}>
110
+ <Text color="gray">Total: </Text>
111
+ <ProgressBar progress={workflowState.totalProgress} width={10} />
112
+ <Text color="white"> {workflowState.totalProgress}%</Text>
113
+ </Box>
114
+ </Box>
115
+ );
116
+ }
@@ -6,9 +6,21 @@ interface HeaderProps {
6
6
  agentCount: number;
7
7
  provider: string;
8
8
  status: "ready" | "running" | "error";
9
+ tick: number;
10
+ activePanel: string;
9
11
  }
10
12
 
11
- export function Header({ projectName, agentCount, provider, status }: HeaderProps) {
13
+ const spinnerFrames = ["◐", "◓", "◑", "◒"];
14
+ const panelNames: Record<string, string> = {
15
+ chat: "CHAT",
16
+ dag: "DAG",
17
+ status: "STATUS",
18
+ logs: "LOGS",
19
+ metrics: "METRICS",
20
+ memory: "MEMORY",
21
+ };
22
+
23
+ export function Header({ projectName, agentCount, provider, status, tick, activePanel }: HeaderProps) {
12
24
  const statusColors = {
13
25
  ready: "green",
14
26
  running: "yellow",
@@ -21,32 +33,52 @@ export function Header({ projectName, agentCount, provider, status }: HeaderProp
21
33
  error: "ERROR",
22
34
  };
23
35
 
24
- const statusIcon = status === "running" ? "▶" : status === "error" ? "✗" : "●";
36
+ const animatedStatus = status === "running"
37
+ ? spinnerFrames[tick % spinnerFrames.length]
38
+ : status === "error" ? "✗" : "●";
39
+
40
+ const panels = ["chat", "dag", "logs", "metrics", "memory"] as const;
25
41
 
26
42
  return (
27
43
  <Box
28
- flexDirection="row"
29
- justifyContent="space-between"
30
- alignItems="center"
31
- paddingX={1}
44
+ flexDirection="column"
32
45
  borderStyle="single"
33
46
  borderColor="gray"
34
47
  width="100%"
35
48
  >
36
- <Box flexDirection="row" alignItems="center">
37
- <Text color="#f97316" bold>■</Text>
38
- <Text color="white" bold> RAX-FLOW</Text>
39
- <Text color="gray"> HUB</Text>
49
+ <Box
50
+ flexDirection="row"
51
+ justifyContent="space-between"
52
+ alignItems="center"
53
+ paddingX={1}
54
+ >
55
+ <Box flexDirection="row" alignItems="center">
56
+ <Text color="#f97316" bold>■</Text>
57
+ <Text color="white" bold> RAX-FLOW</Text>
58
+ <Text color="gray"> HUB</Text>
59
+ </Box>
60
+ <Box flexDirection="row" alignItems="center">
61
+ <Text color="gray">Project:</Text>
62
+ <Text color="cyan"> {projectName}</Text>
63
+ <Text color="gray"> │ Agents:</Text>
64
+ <Text color="green"> {agentCount}/12</Text>
65
+ <Text color="gray"> │ [{provider}]</Text>
66
+ <Text color={statusColors[status]}> {animatedStatus} {statusText[status]}</Text>
67
+ </Box>
40
68
  </Box>
41
- <Box flexDirection="row" alignItems="center" gap={2}>
42
- <Text color="gray">Project:</Text>
43
- <Text color="cyan">{projectName}</Text>
44
- <Text color="gray">│</Text>
45
- <Text color="gray">Agents:</Text>
46
- <Text color="green">{agentCount}/12</Text>
47
- <Text color="gray">│</Text>
48
- <Text color="gray">[{provider}]</Text>
49
- <Text color={statusColors[status]}> {statusIcon} {statusText[status]}</Text>
69
+ <Box flexDirection="row" paddingX={1} justifyContent="space-between">
70
+ <Box flexDirection="row">
71
+ {panels.map((panel) => (
72
+ <Box key={panel} marginRight={1}>
73
+ <Text color={activePanel === panel ? "#f97316" : "gray"} bold={activePanel === panel}>
74
+ [{panelNames[panel]}]
75
+ </Text>
76
+ </Box>
77
+ ))}
78
+ </Box>
79
+ <Box flexDirection="row">
80
+ <Text color="gray">Tab: Switch │ ←: Toggle view │ ?: Help │ Ctrl+C: Quit</Text>
81
+ </Box>
50
82
  </Box>
51
83
  </Box>
52
84
  );
@@ -0,0 +1,83 @@
1
+ import React from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+
4
+ interface HelpOverlayProps {
5
+ onDismiss: () => void;
6
+ }
7
+
8
+ export function HelpOverlay({ onDismiss }: HelpOverlayProps) {
9
+ useInput((input, key) => {
10
+ if (key.escape || input === "q") {
11
+ onDismiss();
12
+ }
13
+ });
14
+
15
+ const sections = [
16
+ {
17
+ title: "COMMANDES",
18
+ items: [
19
+ ["/run <prompt>", "Exécuter un workflow"],
20
+ ["/status", "État du système"],
21
+ ["/agents", "Liste des agents"],
22
+ ["/providers", "Liste des providers"],
23
+ ["/workflows", "Blueprints disponibles"],
24
+ ["/help, ?", "Cette aide"],
25
+ ["/exit", "Quitter"],
26
+ ],
27
+ },
28
+ {
29
+ title: "NAVIGATION",
30
+ items: [
31
+ ["Tab", "Changer de panel actif"],
32
+ ["F1-F8", "Aller au panel spécifique"],
33
+ ["Ctrl+C", "Quitter"],
34
+ ["Esc", "Fermer l'aide"],
35
+ ],
36
+ },
37
+ {
38
+ title: "PANELS",
39
+ items: [
40
+ ["CHAT", "Messages et interaction"],
41
+ ["DAG", "Visualisation du workflow"],
42
+ ["STATUS", "Agents et providers"],
43
+ ],
44
+ },
45
+ ];
46
+
47
+ return (
48
+ <Box
49
+ flexDirection="column"
50
+ flexGrow={1}
51
+ borderStyle="double"
52
+ borderColor="#f97316"
53
+ paddingX={2}
54
+ >
55
+ <Box marginBottom={1}>
56
+ <Text color="#f97316" bold>■ RAX-FLOW HELP</Text>
57
+ <Text color="gray"> — [Esc] pour fermer</Text>
58
+ </Box>
59
+
60
+ <Box flexDirection="row" flexGrow={1}>
61
+ {sections.map((section) => (
62
+ <Box key={section.title} flexDirection="column" width={30}>
63
+ <Text color="gray" bold underline>
64
+ {section.title}
65
+ </Text>
66
+ <Box flexDirection="column" marginTop={1}>
67
+ {section.items.map(([cmd, desc]) => (
68
+ <Box key={cmd} flexDirection="row" marginBottom={1}>
69
+ <Text color="cyan">{cmd.padEnd(16)}</Text>
70
+ <Text color="white">{desc}</Text>
71
+ </Box>
72
+ ))}
73
+ </Box>
74
+ </Box>
75
+ ))}
76
+ </Box>
77
+
78
+ <Box borderStyle="single" borderColor="gray" marginTop={1}>
79
+ <Text color="gray">Pour exécuter un workflow, tapez simplement votre prompt ou /run "..."</Text>
80
+ </Box>
81
+ </Box>
82
+ );
83
+ }
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface LogsPanelProps {
5
+ logs: string[];
6
+ isActive: boolean;
7
+ }
8
+
9
+ export function LogsPanel({ logs, isActive }: LogsPanelProps) {
10
+ const borderColor = isActive ? "#f97316" : "gray";
11
+
12
+ return (
13
+ <Box
14
+ flexDirection="column"
15
+ flexGrow={1}
16
+ borderStyle="single"
17
+ borderColor={borderColor}
18
+ paddingX={1}
19
+ >
20
+ <Box borderStyle="single" borderColor="#f97316" marginBottom={1}>
21
+ <Text color="#f97316" bold>LOGS</Text>
22
+ <Text color="gray"> STREAM</Text>
23
+ {isActive && <Text color="yellow"> [ACTIF]</Text>}
24
+ </Box>
25
+ <Box flexDirection="column" flexGrow={1} overflow="hidden">
26
+ {logs.slice(-12).map((log, index) => (
27
+ <Text key={index} color="white" wrap="truncate">
28
+ {log}
29
+ </Text>
30
+ ))}
31
+ {logs.length === 0 && (
32
+ <Text color="gray">Aucun log. Lancez un workflow pour voir les logs.</Text>
33
+ )}
34
+ </Box>
35
+ </Box>
36
+ );
37
+ }
@@ -0,0 +1,99 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface MemoryNode {
5
+ id: string;
6
+ type: string;
7
+ label: string;
8
+ }
9
+
10
+ interface MemoryEdge {
11
+ from: string;
12
+ to: string;
13
+ }
14
+
15
+ interface MemoryPanelProps {
16
+ nodes: MemoryNode[];
17
+ edges: MemoryEdge[];
18
+ nodeCount: number;
19
+ cacheHitRate: number;
20
+ isActive: boolean;
21
+ }
22
+
23
+ const DEFAULT_NODES: MemoryNode[] = [
24
+ { id: "1", type: "action", label: "code_gen" },
25
+ { id: "2", type: "file", label: "auth.ts" },
26
+ { id: "3", type: "task", label: "login" },
27
+ { id: "4", type: "test", label: "auth.test" },
28
+ ];
29
+
30
+ const DEFAULT_EDGES: MemoryEdge[] = [
31
+ { from: "1", to: "2" },
32
+ { from: "2", to: "3" },
33
+ { from: "3", to: "4" },
34
+ ];
35
+
36
+ export function MemoryPanel({ nodes, edges, nodeCount, cacheHitRate, isActive }: MemoryPanelProps) {
37
+ const borderColor = isActive ? "#f97316" : "gray";
38
+ const displayNodes = nodes.length > 0 ? nodes : DEFAULT_NODES;
39
+ const displayEdges = edges.length > 0 ? edges : DEFAULT_EDGES;
40
+
41
+ return (
42
+ <Box
43
+ flexDirection="column"
44
+ flexGrow={1}
45
+ borderStyle="single"
46
+ borderColor={borderColor}
47
+ paddingX={1}
48
+ >
49
+ <Box borderStyle="single" borderColor="#f97316" marginBottom={1}>
50
+ <Text color="#f97316" bold>MEMORY</Text>
51
+ <Text color="gray"> QSGM</Text>
52
+ {isActive && <Text color="yellow"> [ACTIF]</Text>}
53
+ </Box>
54
+
55
+ <Box flexDirection="column">
56
+ <Text color="gray" bold>QUANTUM SEMANTIC GRAPH</Text>
57
+ <Box flexDirection="row" marginTop={1}>
58
+ <Text color="white">Nodes: </Text>
59
+ <Text color="cyan" bold>{nodeCount}</Text>
60
+ <Text color="gray"> │ Cache: </Text>
61
+ <Text color="green">{cacheHitRate}%</Text>
62
+ </Box>
63
+ </Box>
64
+
65
+ <Box flexDirection="column" marginTop={1}>
66
+ <Text color="gray" bold>RECENT NODES</Text>
67
+ <Box flexDirection="column" marginTop={1}>
68
+ {displayNodes.slice(0, 5).map((node) => (
69
+ <Box key={node.id} flexDirection="row">
70
+ <Text color="gray">[{node.type}]</Text>
71
+ <Text color="white"> {node.label}</Text>
72
+ </Box>
73
+ ))}
74
+ </Box>
75
+ </Box>
76
+
77
+ <Box flexDirection="column" marginTop={1}>
78
+ <Text color="gray" bold>CONNECTIONS</Text>
79
+ <Box flexDirection="column" marginTop={1}>
80
+ {displayEdges.slice(0, 4).map((edge, i) => {
81
+ const fromNode = displayNodes.find((n) => n.id === edge.from);
82
+ const toNode = displayNodes.find((n) => n.id === edge.to);
83
+ return (
84
+ <Box key={i} flexDirection="row">
85
+ <Text color="white">{fromNode?.label || "?"}</Text>
86
+ <Text color="#f97316"> ──▶ </Text>
87
+ <Text color="white">{toNode?.label || "?"}</Text>
88
+ </Box>
89
+ );
90
+ })}
91
+ </Box>
92
+ </Box>
93
+
94
+ <Box marginTop={1}>
95
+ <Text color="gray" dimColor>Mutations this session: +{Math.floor(Math.random() * 4)}</Text>
96
+ </Box>
97
+ </Box>
98
+ );
99
+ }
@@ -0,0 +1,108 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface MetricsPanelProps {
5
+ metrics: {
6
+ sessions: number;
7
+ avgDuration: number;
8
+ successRate: number;
9
+ totalCost: number;
10
+ };
11
+ fitness: number;
12
+ isActive: boolean;
13
+ }
14
+
15
+ function ProgressBar({ value, max, width = 16 }: { value: number; max: number; width?: number }) {
16
+ const percent = Math.min((value / max) * 100, 100);
17
+ const filled = Math.round((percent / 100) * width);
18
+ const empty = width - filled;
19
+ const bar = "█".repeat(filled) + "░".repeat(empty);
20
+ return (
21
+ <Text color={percent >= 80 ? "green" : percent >= 50 ? "yellow" : "red"}>
22
+ {bar}
23
+ </Text>
24
+ );
25
+ }
26
+
27
+ export function MetricsPanel({ metrics, fitness, isActive }: MetricsPanelProps) {
28
+ const borderColor = isActive ? "#f97316" : "gray";
29
+
30
+ return (
31
+ <Box
32
+ flexDirection="column"
33
+ width={30}
34
+ borderStyle="single"
35
+ borderColor={borderColor}
36
+ paddingX={1}
37
+ >
38
+ <Box borderStyle="single" borderColor="#f97316" marginBottom={1}>
39
+ <Text color="#f97316" bold>METRICS</Text>
40
+ {isActive && <Text color="yellow"> [ACTIF]</Text>}
41
+ </Box>
42
+
43
+ <Box flexDirection="column">
44
+ <Text color="gray" bold>PERFORMANCE</Text>
45
+
46
+ <Box flexDirection="row" marginTop={1}>
47
+ <Text color="white">Sessions: </Text>
48
+ <Text color="cyan" bold>{metrics.sessions}</Text>
49
+ </Box>
50
+
51
+ <Box flexDirection="row">
52
+ <Text color="white">Duration: </Text>
53
+ <Text color="cyan">{metrics.avgDuration}ms</Text>
54
+ </Box>
55
+
56
+ <Box flexDirection="row">
57
+ <Text color="white">Success: </Text>
58
+ <Text color="green">{metrics.successRate}%</Text>
59
+ <Text color="gray"> </Text>
60
+ <ProgressBar value={metrics.successRate} max={100} width={8} />
61
+ </Box>
62
+
63
+ <Box flexDirection="row">
64
+ <Text color="white">Cost: </Text>
65
+ <Text color="yellow">${metrics.totalCost.toFixed(4)}</Text>
66
+ </Box>
67
+ </Box>
68
+
69
+ <Box flexDirection="column" marginTop={1}>
70
+ <Text color="gray" bold>FITNESS</Text>
71
+ <Box flexDirection="row">
72
+ <Text color={fitness >= 0.9 ? "green" : fitness >= 0.7 ? "yellow" : "red"} bold>
73
+ {fitness.toFixed(2)}
74
+ </Text>
75
+ <Text color="gray"> </Text>
76
+ <ProgressBar value={fitness} max={1} width={12} />
77
+ </Box>
78
+ <Text color="gray">
79
+ {fitness >= 0.9 ? "[OPTIMAL]" : fitness >= 0.7 ? "[GOOD]" : "[IMPROVING]"}
80
+ </Text>
81
+ </Box>
82
+
83
+ <Box flexDirection="column" marginTop={1}>
84
+ <Text color="gray" bold>TOP AGENTS</Text>
85
+ <Box flexDirection="column" marginTop={1}>
86
+ <Box flexDirection="row">
87
+ <Text color="white">CodeGenerator</Text>
88
+ <Text color="gray"> </Text>
89
+ <ProgressBar value={45} max={100} width={8} />
90
+ <Text color="gray"> 45%</Text>
91
+ </Box>
92
+ <Box flexDirection="row">
93
+ <Text color="white">TestAgent</Text>
94
+ <Text color="gray"> </Text>
95
+ <ProgressBar value={32} max={100} width={8} />
96
+ <Text color="gray"> 32%</Text>
97
+ </Box>
98
+ <Box flexDirection="row">
99
+ <Text color="white">FixAgent</Text>
100
+ <Text color="gray"> </Text>
101
+ <ProgressBar value={18} max={100} width={8} />
102
+ <Text color="gray"> 18%</Text>
103
+ </Box>
104
+ </Box>
105
+ </Box>
106
+ </Box>
107
+ );
108
+ }
@@ -19,6 +19,7 @@ interface StatusPanelProps {
19
19
  providers: Provider[];
20
20
  fitness: number;
21
21
  currentWorkflow: string | null;
22
+ isActive: boolean;
22
23
  }
23
24
 
24
25
  const statusIcons: Record<string, { icon: string; color: string }> = {
@@ -28,10 +29,10 @@ const statusIcons: Record<string, { icon: string; color: string }> = {
28
29
  done: { icon: "●", color: "green" },
29
30
  };
30
31
 
31
- function AgentRow({ agent, key }: { agent: Agent; key?: string }) {
32
+ function AgentRow({ agent }: { agent: Agent }) {
32
33
  const { icon, color } = statusIcons[agent.status];
33
34
  return (
34
- <Box key={key} flexDirection="row" justifyContent="space-between">
35
+ <Box flexDirection="row" justifyContent="space-between">
35
36
  <Text color={color}>{icon}</Text>
36
37
  <Text color="white">{agent.name.slice(0, 12).padEnd(12)}</Text>
37
38
  <Text color="gray">[{agent.provider}]</Text>
@@ -39,9 +40,9 @@ function AgentRow({ agent, key }: { agent: Agent; key?: string }) {
39
40
  );
40
41
  }
41
42
 
42
- function ProviderRow({ provider, key }: { provider: Provider; key?: string }) {
43
+ function ProviderRow({ provider }: { provider: Provider }) {
43
44
  return (
44
- <Box key={key} flexDirection="row" justifyContent="space-between">
45
+ <Box flexDirection="row" justifyContent="space-between">
45
46
  <Text color={provider.status === "active" ? "green" : "gray"}>
46
47
  {provider.status === "active" ? "●" : "○"}
47
48
  </Text>
@@ -51,20 +52,24 @@ function ProviderRow({ provider, key }: { provider: Provider; key?: string }) {
51
52
  );
52
53
  }
53
54
 
54
- export function StatusPanel({ agents, providers, fitness, currentWorkflow }: StatusPanelProps) {
55
+ export function StatusPanel({ agents, providers, fitness, currentWorkflow, isActive }: StatusPanelProps) {
55
56
  const fitnessColor = fitness >= 0.9 ? "green" : fitness >= 0.7 ? "yellow" : "red";
57
+ const borderColor = isActive ? "#f97316" : "gray";
56
58
 
57
59
  return (
58
- <Box flexDirection="column" width={35} borderStyle="single" borderColor="gray">
60
+ <Box flexDirection="column" width={30} borderStyle="single" borderColor={borderColor}>
59
61
  <Box borderStyle="single" borderColor="#f97316" marginBottom={1}>
60
62
  <Text color="#f97316" bold>STATUS</Text>
63
+ {isActive && <Text color="yellow"> [ACTIF]</Text>}
61
64
  </Box>
62
65
 
63
66
  <Box flexDirection="column" paddingX={1}>
64
67
  <Text color="gray" bold>WORKFLOW</Text>
65
68
  <Text color="white">{currentWorkflow || "Aucun"}</Text>
66
- <Text color="gray">Fitness: </Text>
67
- <Text color={fitnessColor} bold>{fitness.toFixed(2)}</Text>
69
+ <Box flexDirection="row">
70
+ <Text color="gray">Fitness: </Text>
71
+ <Text color={fitnessColor} bold>{fitness.toFixed(2)}</Text>
72
+ </Box>
68
73
  </Box>
69
74
 
70
75
  <Box flexDirection="column" paddingX={1} marginTop={1}>