rax-flow 0.1.8 → 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 (35) hide show
  1. package/dist/tui/App.d.ts.map +1 -1
  2. package/dist/tui/App.js +15 -7
  3. package/dist/tui/App.js.map +1 -1
  4. package/dist/tui/components/Header.d.ts.map +1 -1
  5. package/dist/tui/components/Header.js +5 -1
  6. package/dist/tui/components/Header.js.map +1 -1
  7. package/dist/tui/components/LogsPanel.d.ts +7 -0
  8. package/dist/tui/components/LogsPanel.d.ts.map +1 -0
  9. package/dist/tui/components/LogsPanel.js +7 -0
  10. package/dist/tui/components/LogsPanel.js.map +1 -0
  11. package/dist/tui/components/MemoryPanel.d.ts +19 -0
  12. package/dist/tui/components/MemoryPanel.d.ts.map +1 -0
  13. package/dist/tui/components/MemoryPanel.js +24 -0
  14. package/dist/tui/components/MemoryPanel.js.map +1 -0
  15. package/dist/tui/components/MetricsPanel.d.ts +13 -0
  16. package/dist/tui/components/MetricsPanel.d.ts.map +1 -0
  17. package/dist/tui/components/MetricsPanel.js +14 -0
  18. package/dist/tui/components/MetricsPanel.js.map +1 -0
  19. package/dist/tui/hooks/useAppState.d.ts +7 -0
  20. package/dist/tui/hooks/useAppState.d.ts.map +1 -1
  21. package/dist/tui/hooks/useAppState.js +141 -53
  22. package/dist/tui/hooks/useAppState.js.map +1 -1
  23. package/dist/tui/services/orchestrator.d.ts +16 -0
  24. package/dist/tui/services/orchestrator.d.ts.map +1 -0
  25. package/dist/tui/services/orchestrator.js +108 -0
  26. package/dist/tui/services/orchestrator.js.map +1 -0
  27. package/package.json +1 -1
  28. package/src/tui/App.tsx +50 -17
  29. package/src/tui/components/Header.tsx +18 -9
  30. package/src/tui/components/LogsPanel.tsx +37 -0
  31. package/src/tui/components/MemoryPanel.tsx +99 -0
  32. package/src/tui/components/MetricsPanel.tsx +108 -0
  33. package/src/tui/hooks/useAppState.ts +181 -62
  34. package/src/tui/services/orchestrator.ts +142 -0
  35. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,16 @@
1
+ import { RuntimeEvent, WorkflowGraph } from "rax-flow-core";
2
+ export interface OrchestratorService {
3
+ run(prompt: string): Promise<void>;
4
+ onEvent(handler: (event: RuntimeEvent) => void): () => void;
5
+ getStatus(): OrchestratorStatus;
6
+ stop(): void;
7
+ }
8
+ export interface OrchestratorStatus {
9
+ isRunning: boolean;
10
+ currentTaskId: string | null;
11
+ workflow: WorkflowGraph | null;
12
+ fitness: number;
13
+ }
14
+ export declare function createOrchestrator(): OrchestratorService;
15
+ export type { RuntimeEvent, WorkflowGraph };
16
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/tui/services/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EAGZ,aAAa,EAKd,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5D,SAAS,IAAI,kBAAkB,CAAC;IAChC,IAAI,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AA4DD,wBAAgB,kBAAkB,IAAI,mBAAmB,CAuDxD;AAED,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,108 @@
1
+ import { CoreOrchestrator, } from "rax-flow-core";
2
+ function createMockProvider() {
3
+ return {
4
+ async callModel(prompt, options) {
5
+ await new Promise((r) => setTimeout(r, 300 + Math.random() * 500));
6
+ return {
7
+ provider: "mock",
8
+ model: "mock-model",
9
+ latencyMs: 300 + Math.floor(Math.random() * 200),
10
+ output: `Processed: ${prompt.slice(0, 50)}...`,
11
+ usage: { promptTokens: 100, completionTokens: 50, totalTokens: 150 },
12
+ };
13
+ },
14
+ async callStructured(prompt, schema, options) {
15
+ const response = await this.callModel(prompt, options);
16
+ return {
17
+ ...response,
18
+ output: {},
19
+ };
20
+ },
21
+ async healthCheck() {
22
+ return true;
23
+ },
24
+ };
25
+ }
26
+ function createAgent(name, role) {
27
+ return {
28
+ name,
29
+ role,
30
+ activationWhen: `intent == "${name.toLowerCase()}"`,
31
+ inputSchema: { type: "object" },
32
+ outputSchema: { type: "object" },
33
+ async run(input) {
34
+ await new Promise((r) => setTimeout(r, 200 + Math.random() * 300));
35
+ return {
36
+ agent: name,
37
+ success: true,
38
+ confidence: 0.85 + Math.random() * 0.1,
39
+ risks: [],
40
+ logs: [`Executed ${name}`],
41
+ data: { result: `Processed: ${input.userPrompt.slice(0, 50)}...` },
42
+ usage: { promptTokens: 100, completionTokens: 50, totalTokens: 150 },
43
+ };
44
+ },
45
+ };
46
+ }
47
+ const DEFAULT_AGENTS = [
48
+ createAgent("IntentClassifier", "Classifies user intent"),
49
+ createAgent("TaskPlanner", "Decomposes tasks"),
50
+ createAgent("SpecAgent", "Writes specifications"),
51
+ createAgent("ArchitectureAgent", "Designs architecture"),
52
+ createAgent("CodeGenerator", "Generates code"),
53
+ createAgent("TestAgent", "Runs tests"),
54
+ createAgent("FixAgent", "Fixes issues"),
55
+ createAgent("ValidatorAgent", "Validates outputs"),
56
+ ];
57
+ export function createOrchestrator() {
58
+ const providers = {
59
+ host: createMockProvider(),
60
+ };
61
+ const agents = {};
62
+ for (const agent of DEFAULT_AGENTS) {
63
+ agents[agent.name] = agent;
64
+ }
65
+ const orchestrator = new CoreOrchestrator(providers, agents);
66
+ let isRunning = false;
67
+ let currentTaskId = null;
68
+ let fitness = 0.87;
69
+ orchestrator.initialize().catch(() => { });
70
+ return {
71
+ async run(prompt) {
72
+ if (isRunning)
73
+ return;
74
+ isRunning = true;
75
+ currentTaskId = `task-${Date.now()}`;
76
+ try {
77
+ await orchestrator.run({
78
+ taskId: currentTaskId,
79
+ userPrompt: prompt,
80
+ });
81
+ fitness = Math.min(fitness + 0.02, 0.99);
82
+ }
83
+ catch (error) {
84
+ console.error("Orchestrator error:", error);
85
+ }
86
+ finally {
87
+ currentTaskId = null;
88
+ isRunning = false;
89
+ }
90
+ },
91
+ onEvent(handler) {
92
+ return orchestrator.onEvent(handler);
93
+ },
94
+ getStatus() {
95
+ return {
96
+ isRunning,
97
+ currentTaskId,
98
+ workflow: null,
99
+ fitness,
100
+ };
101
+ },
102
+ stop() {
103
+ isRunning = false;
104
+ currentTaskId = null;
105
+ },
106
+ };
107
+ }
108
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../../src/tui/services/orchestrator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rax-flow",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/tui/App.tsx CHANGED
@@ -1,14 +1,19 @@
1
- import React, { useState, useEffect } from "react";
1
+ import React, { useState, useEffect, useRef } from "react";
2
2
  import { Box, Text, useApp, useInput } from "ink";
3
3
  import { Header } from "./components/Header.js";
4
4
  import { ChatPanel } from "./components/ChatPanel.js";
5
5
  import { StatusPanel } from "./components/StatusPanel.js";
6
6
  import { DAGPanel } from "./components/DAGPanel.js";
7
+ import { LogsPanel } from "./components/LogsPanel.js";
8
+ import { MetricsPanel } from "./components/MetricsPanel.js";
9
+ import { MemoryPanel } from "./components/MemoryPanel.js";
7
10
  import { InputBar } from "./components/InputBar.js";
8
11
  import { HelpOverlay } from "./components/HelpOverlay.js";
9
12
  import { useAppState } from "./hooks/useAppState.js";
10
13
 
11
- type ActivePanel = "chat" | "dag" | "status";
14
+ type ActivePanel = "chat" | "dag" | "status" | "logs" | "metrics" | "memory";
15
+
16
+ const PANEL_ORDER: ActivePanel[] = ["chat", "dag", "status", "logs", "metrics", "memory"];
12
17
 
13
18
  export function App() {
14
19
  const { exit } = useApp();
@@ -16,6 +21,7 @@ export function App() {
16
21
  const [activePanel, setActivePanel] = useState<ActivePanel>("chat");
17
22
  const [showHelp, setShowHelp] = useState(false);
18
23
  const [tick, setTick] = useState(0);
24
+ const [viewMode, setViewMode] = useState<"full" | "compact">("full");
19
25
 
20
26
  useEffect(() => {
21
27
  const interval = setInterval(() => {
@@ -32,7 +38,9 @@ export function App() {
32
38
  exit();
33
39
  }
34
40
  if (key.escape) {
35
- setShowHelp(false);
41
+ if (showHelp) {
42
+ setShowHelp(false);
43
+ }
36
44
  }
37
45
  if (input === "?" && !showHelp) {
38
46
  setShowHelp(true);
@@ -40,13 +48,14 @@ export function App() {
40
48
  }
41
49
  if (showHelp) return;
42
50
 
43
- if (key.return && input === "") {
44
- }
45
-
46
51
  if (key.tab) {
47
- const panels: ActivePanel[] = ["chat", "dag", "status"];
48
- const currentIndex = panels.indexOf(activePanel);
49
- setActivePanel(panels[(currentIndex + 1) % panels.length]);
52
+ const currentIndex = PANEL_ORDER.indexOf(activePanel);
53
+ const nextIndex = (currentIndex + 1) % PANEL_ORDER.length;
54
+ setActivePanel(PANEL_ORDER[nextIndex]);
55
+ }
56
+
57
+ if (key.leftArrow) {
58
+ setViewMode(viewMode === "full" ? "compact" : "full");
50
59
  }
51
60
  });
52
61
 
@@ -77,7 +86,7 @@ export function App() {
77
86
  tick={tick}
78
87
  activePanel={activePanel}
79
88
  />
80
-
89
+
81
90
  {showHelp ? (
82
91
  <HelpOverlay onDismiss={() => setShowHelp(false)} />
83
92
  ) : (
@@ -93,13 +102,37 @@ export function App() {
93
102
  tick={tick}
94
103
  isActive={activePanel === "dag"}
95
104
  />
96
- <StatusPanel
97
- agents={state.agents}
98
- providers={state.providers}
99
- fitness={state.fitness}
100
- currentWorkflow={state.currentWorkflow}
101
- isActive={activePanel === "status"}
102
- />
105
+ {viewMode === "full" && (
106
+ <>
107
+ <LogsPanel
108
+ logs={state.logs}
109
+ isActive={activePanel === "logs"}
110
+ />
111
+ <Box flexDirection="column">
112
+ <MetricsPanel
113
+ metrics={state.metrics}
114
+ fitness={state.fitness}
115
+ isActive={activePanel === "metrics"}
116
+ />
117
+ <MemoryPanel
118
+ nodes={[]}
119
+ edges={[]}
120
+ nodeCount={247}
121
+ cacheHitRate={94}
122
+ isActive={activePanel === "memory"}
123
+ />
124
+ </Box>
125
+ </>
126
+ )}
127
+ {viewMode === "compact" && (
128
+ <StatusPanel
129
+ agents={state.agents}
130
+ providers={state.providers}
131
+ fitness={state.fitness}
132
+ currentWorkflow={state.currentWorkflow}
133
+ isActive={activePanel === "status"}
134
+ />
135
+ )}
103
136
  </Box>
104
137
  <InputBar
105
138
  onSubmit={handleSubmit}
@@ -15,6 +15,9 @@ const panelNames: Record<string, string> = {
15
15
  chat: "CHAT",
16
16
  dag: "DAG",
17
17
  status: "STATUS",
18
+ logs: "LOGS",
19
+ metrics: "METRICS",
20
+ memory: "MEMORY",
18
21
  };
19
22
 
20
23
  export function Header({ projectName, agentCount, provider, status, tick, activePanel }: HeaderProps) {
@@ -34,6 +37,8 @@ export function Header({ projectName, agentCount, provider, status, tick, active
34
37
  ? spinnerFrames[tick % spinnerFrames.length]
35
38
  : status === "error" ? "✗" : "●";
36
39
 
40
+ const panels = ["chat", "dag", "logs", "metrics", "memory"] as const;
41
+
37
42
  return (
38
43
  <Box
39
44
  flexDirection="column"
@@ -61,15 +66,19 @@ export function Header({ projectName, agentCount, provider, status, tick, active
61
66
  <Text color={statusColors[status]}> {animatedStatus} {statusText[status]}</Text>
62
67
  </Box>
63
68
  </Box>
64
- <Box flexDirection="row" paddingX={1}>
65
- {(["chat", "dag", "status"] as const).map((panel) => (
66
- <Box key={panel} marginRight={2}>
67
- <Text color={activePanel === panel ? "#f97316" : "gray"} bold={activePanel === panel}>
68
- [{panelNames[panel]}]
69
- </Text>
70
- </Box>
71
- ))}
72
- <Text color="gray">| Tab: Changer │ ?: Aide │ Ctrl+C: Quitter</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>
73
82
  </Box>
74
83
  </Box>
75
84
  );
@@ -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
+ }