rax-flow 0.1.9 → 0.2.0
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/dist/bin.js +8 -6
- package/dist/bin.js.map +1 -1
- package/dist/hub/commands/index.d.ts.map +1 -1
- package/dist/hub/commands/index.js +7 -4
- package/dist/hub/commands/index.js.map +1 -1
- package/dist/hub/event-listener.d.ts +6 -0
- package/dist/hub/event-listener.d.ts.map +1 -1
- package/dist/hub/event-listener.js +10 -6
- package/dist/hub/event-listener.js.map +1 -1
- package/dist/hub/index.d.ts.map +1 -1
- package/dist/hub/index.js +12 -0
- package/dist/hub/index.js.map +1 -1
- package/dist/setup/components/ApiKeyInput.d.ts +25 -0
- package/dist/setup/components/ApiKeyInput.d.ts.map +1 -0
- package/dist/setup/components/ApiKeyInput.js +54 -0
- package/dist/setup/components/ApiKeyInput.js.map +1 -0
- package/dist/setup/components/AsciiBanner.d.ts +22 -0
- package/dist/setup/components/AsciiBanner.d.ts.map +1 -0
- package/dist/setup/components/AsciiBanner.js +55 -0
- package/dist/setup/components/AsciiBanner.js.map +1 -0
- package/dist/setup/components/CliDetector.d.ts +17 -0
- package/dist/setup/components/CliDetector.d.ts.map +1 -0
- package/dist/setup/components/CliDetector.js +79 -0
- package/dist/setup/components/CliDetector.js.map +1 -0
- package/dist/setup/components/ModeSelector.d.ts +8 -0
- package/dist/setup/components/ModeSelector.d.ts.map +1 -0
- package/dist/setup/components/ModeSelector.js +76 -0
- package/dist/setup/components/ModeSelector.js.map +1 -0
- package/dist/setup/components/ProviderSelector.d.ts +18 -0
- package/dist/setup/components/ProviderSelector.d.ts.map +1 -0
- package/dist/setup/components/ProviderSelector.js +97 -0
- package/dist/setup/components/ProviderSelector.js.map +1 -0
- package/dist/setup/components/SetupWizard.d.ts +2 -0
- package/dist/setup/components/SetupWizard.d.ts.map +1 -0
- package/dist/setup/components/SetupWizard.js +212 -0
- package/dist/setup/components/SetupWizard.js.map +1 -0
- package/dist/setup/components/StepIndicator.d.ts +13 -0
- package/dist/setup/components/StepIndicator.d.ts.map +1 -0
- package/dist/setup/components/StepIndicator.js +18 -0
- package/dist/setup/components/StepIndicator.js.map +1 -0
- package/dist/setup/components/SuccessScreen.d.ts +18 -0
- package/dist/setup/components/SuccessScreen.d.ts.map +1 -0
- package/dist/setup/components/SuccessScreen.js +38 -0
- package/dist/setup/components/SuccessScreen.js.map +1 -0
- package/dist/setup/index.d.ts +12 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +29 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/setup/utils/cli-detection.d.ts +12 -0
- package/dist/setup/utils/cli-detection.d.ts.map +1 -0
- package/dist/setup/utils/cli-detection.js +83 -0
- package/dist/setup/utils/cli-detection.js.map +1 -0
- package/dist/setup/utils/config-writer.d.ts +43 -0
- package/dist/setup/utils/config-writer.d.ts.map +1 -0
- package/dist/setup/utils/config-writer.js +180 -0
- package/dist/setup/utils/config-writer.js.map +1 -0
- package/dist/tui/App.d.ts +2 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +78 -18
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/AgentStateIcon.d.ts +18 -0
- package/dist/tui/components/AgentStateIcon.d.ts.map +1 -0
- package/dist/tui/components/AgentStateIcon.js +57 -0
- package/dist/tui/components/AgentStateIcon.js.map +1 -0
- package/dist/tui/components/AnimatedBranch.d.ts +39 -0
- package/dist/tui/components/AnimatedBranch.d.ts.map +1 -0
- package/dist/tui/components/AnimatedBranch.js +64 -0
- package/dist/tui/components/AnimatedBranch.js.map +1 -0
- package/dist/tui/components/ChatPanel.d.ts +2 -1
- package/dist/tui/components/ChatPanel.d.ts.map +1 -1
- package/dist/tui/components/ChatPanel.js +47 -28
- package/dist/tui/components/ChatPanel.js.map +1 -1
- package/dist/tui/components/DAGPanel.d.ts +14 -2
- package/dist/tui/components/DAGPanel.d.ts.map +1 -1
- package/dist/tui/components/DAGPanel.js +48 -27
- package/dist/tui/components/DAGPanel.js.map +1 -1
- package/dist/tui/components/ExecutionTimeline.d.ts +34 -0
- package/dist/tui/components/ExecutionTimeline.d.ts.map +1 -0
- package/dist/tui/components/ExecutionTimeline.js +67 -0
- package/dist/tui/components/ExecutionTimeline.js.map +1 -0
- package/dist/tui/components/Header.d.ts +2 -1
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +23 -20
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/HelpOverlay.d.ts +2 -1
- package/dist/tui/components/HelpOverlay.d.ts.map +1 -1
- package/dist/tui/components/HelpOverlay.js +59 -41
- package/dist/tui/components/HelpOverlay.js.map +1 -1
- package/dist/tui/components/InputBar.d.ts +3 -1
- package/dist/tui/components/InputBar.d.ts.map +1 -1
- package/dist/tui/components/InputBar.js +12 -7
- package/dist/tui/components/InputBar.js.map +1 -1
- package/dist/tui/components/LogsPanel.d.ts +3 -1
- package/dist/tui/components/LogsPanel.d.ts.map +1 -1
- package/dist/tui/components/LogsPanel.js +52 -3
- package/dist/tui/components/LogsPanel.js.map +1 -1
- package/dist/tui/components/MemoryPanel.d.ts +8 -6
- package/dist/tui/components/MemoryPanel.d.ts.map +1 -1
- package/dist/tui/components/MemoryPanel.js +37 -10
- package/dist/tui/components/MemoryPanel.js.map +1 -1
- package/dist/tui/components/MetricsPanel.d.ts +12 -7
- package/dist/tui/components/MetricsPanel.d.ts.map +1 -1
- package/dist/tui/components/MetricsPanel.js +24 -11
- package/dist/tui/components/MetricsPanel.js.map +1 -1
- package/dist/tui/components/StatusPanel.d.ts +3 -1
- package/dist/tui/components/StatusPanel.d.ts.map +1 -1
- package/dist/tui/components/StatusPanel.js +20 -18
- package/dist/tui/components/StatusPanel.js.map +1 -1
- package/dist/tui/components/TaskTree.d.ts +28 -0
- package/dist/tui/components/TaskTree.d.ts.map +1 -0
- package/dist/tui/components/TaskTree.js +29 -0
- package/dist/tui/components/TaskTree.js.map +1 -0
- package/dist/tui/components/animations/ProgressBar.d.ts +39 -0
- package/dist/tui/components/animations/ProgressBar.d.ts.map +1 -0
- package/dist/tui/components/animations/ProgressBar.js +39 -0
- package/dist/tui/components/animations/ProgressBar.js.map +1 -0
- package/dist/tui/components/animations/Pulse.d.ts +17 -0
- package/dist/tui/components/animations/Pulse.d.ts.map +1 -0
- package/dist/tui/components/animations/Pulse.js +47 -0
- package/dist/tui/components/animations/Pulse.js.map +1 -0
- package/dist/tui/components/animations/Spinner.d.ts +13 -0
- package/dist/tui/components/animations/Spinner.d.ts.map +1 -0
- package/dist/tui/components/animations/Spinner.js +36 -0
- package/dist/tui/components/animations/Spinner.js.map +1 -0
- package/dist/tui/components/animations/StatusAnimator.d.ts +27 -0
- package/dist/tui/components/animations/StatusAnimator.d.ts.map +1 -0
- package/dist/tui/components/animations/StatusAnimator.js +85 -0
- package/dist/tui/components/animations/StatusAnimator.js.map +1 -0
- package/dist/tui/components/animations/TypingEffect.d.ts +26 -0
- package/dist/tui/components/animations/TypingEffect.d.ts.map +1 -0
- package/dist/tui/components/animations/TypingEffect.js +59 -0
- package/dist/tui/components/animations/TypingEffect.js.map +1 -0
- package/dist/tui/components/animations/index.d.ts +8 -0
- package/dist/tui/components/animations/index.d.ts.map +1 -0
- package/dist/tui/components/animations/index.js +6 -0
- package/dist/tui/components/animations/index.js.map +1 -0
- package/dist/tui/hooks/useAnimation.d.ts +42 -0
- package/dist/tui/hooks/useAnimation.d.ts.map +1 -0
- package/dist/tui/hooks/useAnimation.js +212 -0
- package/dist/tui/hooks/useAnimation.js.map +1 -0
- package/dist/tui/hooks/useAppState.d.ts +9 -6
- package/dist/tui/hooks/useAppState.d.ts.map +1 -1
- package/dist/tui/hooks/useAppState.js +84 -69
- package/dist/tui/hooks/useAppState.js.map +1 -1
- package/dist/tui/services/orchestrator.d.ts.map +1 -1
- package/dist/tui/services/orchestrator.js +47 -3
- package/dist/tui/services/orchestrator.js.map +1 -1
- package/dist/tui/styles/borders.d.ts +31 -0
- package/dist/tui/styles/borders.d.ts.map +1 -0
- package/dist/tui/styles/borders.js +47 -0
- package/dist/tui/styles/borders.js.map +1 -0
- package/dist/tui/styles/colors.d.ts +18 -0
- package/dist/tui/styles/colors.d.ts.map +1 -0
- package/dist/tui/styles/colors.js +18 -0
- package/dist/tui/styles/colors.js.map +1 -0
- package/dist/tui/styles/index.d.ts +6 -0
- package/dist/tui/styles/index.d.ts.map +1 -0
- package/dist/tui/styles/index.js +6 -0
- package/dist/tui/styles/index.js.map +1 -0
- package/dist/tui/styles/indicators.d.ts +67 -0
- package/dist/tui/styles/indicators.d.ts.map +1 -0
- package/dist/tui/styles/indicators.js +42 -0
- package/dist/tui/styles/indicators.js.map +1 -0
- package/dist/tui/styles/layout.d.ts +21 -0
- package/dist/tui/styles/layout.d.ts.map +1 -0
- package/dist/tui/styles/layout.js +42 -0
- package/dist/tui/styles/layout.js.map +1 -0
- package/dist/tui/styles/providers.d.ts +77 -0
- package/dist/tui/styles/providers.d.ts.map +1 -0
- package/dist/tui/styles/providers.js +31 -0
- package/dist/tui/styles/providers.js.map +1 -0
- package/dist/tui/utils/animation.d.ts +44 -0
- package/dist/tui/utils/animation.d.ts.map +1 -0
- package/dist/tui/utils/animation.js +107 -0
- package/dist/tui/utils/animation.js.map +1 -0
- package/package.json +8 -8
- package/src/bin.ts +8 -5
- package/src/hub/commands/index.ts +7 -4
- package/src/hub/event-listener.ts +14 -10
- package/src/hub/index.ts +14 -2
- package/src/setup/components/ApiKeyInput.tsx +158 -0
- package/src/setup/components/AsciiBanner.tsx +125 -0
- package/src/setup/components/CliDetector.tsx +230 -0
- package/src/setup/components/ModeSelector.tsx +137 -0
- package/src/setup/components/ProviderSelector.tsx +174 -0
- package/src/setup/components/SetupWizard.tsx +368 -0
- package/src/setup/components/StepIndicator.tsx +74 -0
- package/src/setup/components/SuccessScreen.tsx +229 -0
- package/src/setup/index.ts +34 -0
- package/src/setup/utils/cli-detection.ts +99 -0
- package/src/setup/utils/config-writer.ts +249 -0
- package/src/tui/App.tsx +95 -64
- package/src/tui/components/AgentStateIcon.tsx +84 -0
- package/src/tui/components/AnimatedBranch.tsx +134 -0
- package/src/tui/components/ChatPanel.tsx +85 -43
- package/src/tui/components/DAGPanel.tsx +150 -58
- package/src/tui/components/ExecutionTimeline.tsx +225 -0
- package/src/tui/components/Header.tsx +67 -43
- package/src/tui/components/HelpOverlay.tsx +118 -61
- package/src/tui/components/InputBar.tsx +33 -19
- package/src/tui/components/LogsPanel.tsx +106 -14
- package/src/tui/components/MemoryPanel.tsx +106 -42
- package/src/tui/components/MetricsPanel.tsx +102 -61
- package/src/tui/components/StatusPanel.tsx +84 -37
- package/src/tui/components/TaskTree.tsx +159 -0
- package/src/tui/components/animations/ProgressBar.tsx +160 -0
- package/src/tui/components/animations/Pulse.tsx +73 -0
- package/src/tui/components/animations/Spinner.tsx +54 -0
- package/src/tui/components/animations/StatusAnimator.tsx +153 -0
- package/src/tui/components/animations/TypingEffect.tsx +119 -0
- package/src/tui/components/animations/index.ts +16 -0
- package/src/tui/hooks/useAnimation.ts +290 -0
- package/src/tui/hooks/useAppState.ts +52 -32
- package/src/tui/services/orchestrator.ts +57 -4
- package/src/tui/styles/borders.ts +51 -0
- package/src/tui/styles/colors.ts +19 -0
- package/src/tui/styles/index.ts +20 -0
- package/src/tui/styles/indicators.ts +54 -0
- package/src/tui/styles/layout.ts +44 -0
- package/src/tui/styles/providers.ts +32 -0
- package/src/tui/utils/animation.ts +124 -0
- package/LICENSE +0 -21
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,31 +1,95 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { memo, useMemo } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
+
import { tuiColors } from "../styles/index.js";
|
|
4
|
+
import { AnimatedProgressBar, FitnessAnimator, Pulse } from "./animations/index.js";
|
|
5
|
+
|
|
6
|
+
interface MetricsData {
|
|
7
|
+
sessions: number;
|
|
8
|
+
avgDuration: number;
|
|
9
|
+
successRate: number;
|
|
10
|
+
totalCost: number;
|
|
11
|
+
totalRetries?: number;
|
|
12
|
+
totalEscalations?: number;
|
|
13
|
+
}
|
|
3
14
|
|
|
4
15
|
interface MetricsPanelProps {
|
|
5
|
-
metrics:
|
|
6
|
-
sessions: number;
|
|
7
|
-
avgDuration: number;
|
|
8
|
-
successRate: number;
|
|
9
|
-
totalCost: number;
|
|
10
|
-
};
|
|
16
|
+
metrics: MetricsData;
|
|
11
17
|
fitness: number;
|
|
12
18
|
isActive: boolean;
|
|
19
|
+
tick?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface AgentUsage {
|
|
23
|
+
name: string;
|
|
24
|
+
percent: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const TOP_AGENTS: AgentUsage[] = [
|
|
28
|
+
{ name: "CodeGenerator", percent: 45 },
|
|
29
|
+
{ name: "TestAgent", percent: 32 },
|
|
30
|
+
{ name: "FixAgent", percent: 18 },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
interface AnimatedMetricBarProps {
|
|
34
|
+
value: number;
|
|
35
|
+
max: number;
|
|
36
|
+
width?: number;
|
|
37
|
+
tick?: number;
|
|
38
|
+
animated?: boolean;
|
|
13
39
|
}
|
|
14
40
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
41
|
+
const AnimatedMetricBar = memo(function AnimatedMetricBar({
|
|
42
|
+
value,
|
|
43
|
+
max,
|
|
44
|
+
width = 16,
|
|
45
|
+
tick,
|
|
46
|
+
animated
|
|
47
|
+
}: AnimatedMetricBarProps) {
|
|
48
|
+
const percent = useMemo(() => Math.min((value / max) * 100, 100), [value, max]);
|
|
20
49
|
return (
|
|
21
|
-
<
|
|
22
|
-
{
|
|
23
|
-
|
|
50
|
+
<AnimatedProgressBar
|
|
51
|
+
progress={percent}
|
|
52
|
+
width={width}
|
|
53
|
+
tick={tick || 0}
|
|
54
|
+
animated={animated}
|
|
55
|
+
showPercentage={false}
|
|
56
|
+
/>
|
|
24
57
|
);
|
|
25
|
-
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const MetricsPanel = memo(function MetricsPanel({
|
|
61
|
+
metrics,
|
|
62
|
+
fitness,
|
|
63
|
+
isActive,
|
|
64
|
+
tick = 0
|
|
65
|
+
}: MetricsPanelProps) {
|
|
66
|
+
const borderColor = isActive ? tuiColors.primary : tuiColors.border;
|
|
67
|
+
const fitnessColor = fitness >= 0.9
|
|
68
|
+
? tuiColors.success
|
|
69
|
+
: fitness >= 0.7
|
|
70
|
+
? tuiColors.warning
|
|
71
|
+
: tuiColors.error;
|
|
26
72
|
|
|
27
|
-
|
|
28
|
-
|
|
73
|
+
const showSuccessPulse = metrics.successRate >= 90;
|
|
74
|
+
|
|
75
|
+
const costStr = useMemo(() => metrics.totalCost.toFixed(4), [metrics.totalCost]);
|
|
76
|
+
|
|
77
|
+
const agentElements = useMemo(() =>
|
|
78
|
+
TOP_AGENTS.map((agent, idx) => (
|
|
79
|
+
<Box key={agent.name} flexDirection="row">
|
|
80
|
+
<Text color={tuiColors.textPrimary}>{agent.name.padEnd(14)}</Text>
|
|
81
|
+
<AnimatedMetricBar
|
|
82
|
+
value={agent.percent}
|
|
83
|
+
max={100}
|
|
84
|
+
width={8}
|
|
85
|
+
tick={tick}
|
|
86
|
+
animated={isActive && idx === 0}
|
|
87
|
+
/>
|
|
88
|
+
<Text color={tuiColors.textTertiary}> {agent.percent}%</Text>
|
|
89
|
+
</Box>
|
|
90
|
+
)),
|
|
91
|
+
[tick, isActive]
|
|
92
|
+
);
|
|
29
93
|
|
|
30
94
|
return (
|
|
31
95
|
<Box
|
|
@@ -35,74 +99,51 @@ export function MetricsPanel({ metrics, fitness, isActive }: MetricsPanelProps)
|
|
|
35
99
|
borderColor={borderColor}
|
|
36
100
|
paddingX={1}
|
|
37
101
|
>
|
|
38
|
-
<Box
|
|
39
|
-
<Text color=
|
|
40
|
-
|
|
102
|
+
<Box marginBottom={1}>
|
|
103
|
+
<Text color={tuiColors.primary} bold>┌─</Text>
|
|
104
|
+
<Text color={tuiColors.primary} bold> PERFORMANCE </Text>
|
|
105
|
+
<Text color={tuiColors.textTertiary}>─────────────</Text>
|
|
41
106
|
</Box>
|
|
42
107
|
|
|
43
108
|
<Box flexDirection="column">
|
|
44
|
-
<Text color=
|
|
109
|
+
<Text color={tuiColors.textTertiary} bold>METRICS</Text>
|
|
45
110
|
|
|
46
111
|
<Box flexDirection="row" marginTop={1}>
|
|
47
|
-
<Text color=
|
|
48
|
-
<Text color=
|
|
112
|
+
<Text color={tuiColors.textSecondary}>Sessions:</Text>
|
|
113
|
+
<Text color={tuiColors.textPrimary} bold> {metrics.sessions}</Text>
|
|
49
114
|
</Box>
|
|
50
115
|
|
|
51
116
|
<Box flexDirection="row">
|
|
52
|
-
<Text color=
|
|
53
|
-
<Text color=
|
|
117
|
+
<Text color={tuiColors.textSecondary}>Avg Duration:</Text>
|
|
118
|
+
<Text color={tuiColors.textPrimary}> {metrics.avgDuration}ms</Text>
|
|
54
119
|
</Box>
|
|
55
120
|
|
|
56
121
|
<Box flexDirection="row">
|
|
57
|
-
<Text color=
|
|
58
|
-
<Text color=
|
|
59
|
-
<
|
|
60
|
-
<ProgressBar value={metrics.successRate} max={100} width={8} />
|
|
122
|
+
<Text color={tuiColors.textSecondary}>Success Rate:</Text>
|
|
123
|
+
<Text color={tuiColors.success}> {metrics.successRate}%</Text>
|
|
124
|
+
{showSuccessPulse && <Pulse interval={1000} color={tuiColors.success} type="breath" />}
|
|
61
125
|
</Box>
|
|
62
126
|
|
|
63
127
|
<Box flexDirection="row">
|
|
64
|
-
<Text color=
|
|
65
|
-
<Text color=
|
|
128
|
+
<Text color={tuiColors.textSecondary}>Cost:</Text>
|
|
129
|
+
<Text color={tuiColors.warning}> ${costStr}</Text>
|
|
66
130
|
</Box>
|
|
67
131
|
</Box>
|
|
68
132
|
|
|
69
133
|
<Box flexDirection="column" marginTop={1}>
|
|
70
|
-
<Text color=
|
|
134
|
+
<Text color={tuiColors.textTertiary} bold>FITNESS SCORE</Text>
|
|
135
|
+
<FitnessAnimator value={fitness} />
|
|
71
136
|
<Box flexDirection="row">
|
|
72
|
-
<
|
|
73
|
-
{fitness.toFixed(2)}
|
|
74
|
-
</Text>
|
|
75
|
-
<Text color="gray"> </Text>
|
|
76
|
-
<ProgressBar value={fitness} max={1} width={12} />
|
|
137
|
+
<AnimatedMetricBar value={fitness} max={1} width={12} tick={tick} animated={isActive} />
|
|
77
138
|
</Box>
|
|
78
|
-
<Text color="gray">
|
|
79
|
-
{fitness >= 0.9 ? "[OPTIMAL]" : fitness >= 0.7 ? "[GOOD]" : "[IMPROVING]"}
|
|
80
|
-
</Text>
|
|
81
139
|
</Box>
|
|
82
140
|
|
|
83
141
|
<Box flexDirection="column" marginTop={1}>
|
|
84
|
-
<Text color=
|
|
142
|
+
<Text color={tuiColors.textTertiary} bold>TOP AGENTS</Text>
|
|
85
143
|
<Box flexDirection="column" marginTop={1}>
|
|
86
|
-
|
|
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>
|
|
144
|
+
{agentElements}
|
|
104
145
|
</Box>
|
|
105
146
|
</Box>
|
|
106
147
|
</Box>
|
|
107
148
|
);
|
|
108
|
-
}
|
|
149
|
+
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { memo, useMemo } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
+
import { tuiColors, getStatusIndicator, getProviderTag } from "../styles/index.js";
|
|
4
|
+
import { Pulse, FitnessAnimator, StatusAnimator } from "./animations/index.js";
|
|
3
5
|
|
|
4
6
|
interface Agent {
|
|
5
7
|
name: string;
|
|
@@ -20,71 +22,116 @@ interface StatusPanelProps {
|
|
|
20
22
|
fitness: number;
|
|
21
23
|
currentWorkflow: string | null;
|
|
22
24
|
isActive: boolean;
|
|
25
|
+
tick?: number;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
28
|
+
interface AgentRowProps {
|
|
29
|
+
agent: Agent;
|
|
30
|
+
tick: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const AgentRow = memo(function AgentRow({ agent, tick }: AgentRowProps) {
|
|
34
|
+
const statusInfo = useMemo(() => getStatusIndicator(agent.status), [agent.status]);
|
|
35
|
+
const providerInfo = useMemo(() => getProviderTag(agent.provider), [agent.provider]);
|
|
31
36
|
|
|
32
|
-
function AgentRow({ agent }: { agent: Agent }) {
|
|
33
|
-
const { icon, color } = statusIcons[agent.status];
|
|
34
37
|
return (
|
|
35
|
-
<Box flexDirection="row"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
<Box flexDirection="row">
|
|
39
|
+
{agent.status === "running" ? (
|
|
40
|
+
<StatusAnimator status="running" showLabel={false} />
|
|
41
|
+
) : (
|
|
42
|
+
<Text color={statusInfo.color}>{statusInfo.icon}</Text>
|
|
43
|
+
)}
|
|
44
|
+
<Text color={tuiColors.textPrimary}> {agent.name.slice(0, 14).padEnd(14)}</Text>
|
|
45
|
+
<Text color={tuiColors.textTertiary}> {providerInfo.code}</Text>
|
|
46
|
+
<Text color={tuiColors.textSecondary}> {agent.status.toUpperCase().padEnd(8)}</Text>
|
|
39
47
|
</Box>
|
|
40
48
|
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
interface ProviderRowProps {
|
|
52
|
+
provider: Provider;
|
|
53
|
+
tick: number;
|
|
41
54
|
}
|
|
42
55
|
|
|
43
|
-
function ProviderRow({ provider }:
|
|
56
|
+
const ProviderRow = memo(function ProviderRow({ provider, tick }: ProviderRowProps) {
|
|
57
|
+
const isActive = provider.status === "active";
|
|
58
|
+
const providerInfo = useMemo(() => getProviderTag(provider.name), [provider.name]);
|
|
59
|
+
|
|
44
60
|
return (
|
|
45
|
-
<Box flexDirection="row"
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
<Box flexDirection="row">
|
|
62
|
+
{isActive ? (
|
|
63
|
+
<Pulse interval={800} color={tuiColors.success} type="breath" />
|
|
64
|
+
) : (
|
|
65
|
+
<Text color={tuiColors.textTertiary}>○</Text>
|
|
66
|
+
)}
|
|
67
|
+
<Text color={tuiColors.textPrimary}> {provider.name.padEnd(12)}</Text>
|
|
68
|
+
<Text color={tuiColors.textTertiary}> {provider.latency > 0 ? `${provider.latency}ms`.padStart(6) : "--".padStart(6)}</Text>
|
|
51
69
|
</Box>
|
|
52
70
|
);
|
|
53
|
-
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export const StatusPanel = memo(function StatusPanel({
|
|
74
|
+
agents,
|
|
75
|
+
providers,
|
|
76
|
+
fitness,
|
|
77
|
+
currentWorkflow,
|
|
78
|
+
isActive,
|
|
79
|
+
tick = 0
|
|
80
|
+
}: StatusPanelProps) {
|
|
81
|
+
const borderColor = isActive ? tuiColors.primary : tuiColors.border;
|
|
82
|
+
|
|
83
|
+
const activeAgents = useMemo(() =>
|
|
84
|
+
agents.filter(a => a.status === "running" || a.status === "queued").slice(0, 4),
|
|
85
|
+
[agents]
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const hasNoActiveAgents = activeAgents.length === 0;
|
|
54
89
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
90
|
+
const workflowDisplay = useMemo(() =>
|
|
91
|
+
currentWorkflow ? `▶ ${currentWorkflow.slice(0, 20)}...` : "○ None",
|
|
92
|
+
[currentWorkflow]
|
|
93
|
+
);
|
|
58
94
|
|
|
59
95
|
return (
|
|
60
96
|
<Box flexDirection="column" width={30} borderStyle="single" borderColor={borderColor}>
|
|
61
|
-
<Box
|
|
62
|
-
<Text color=
|
|
63
|
-
|
|
97
|
+
<Box paddingX={1}>
|
|
98
|
+
<Text color={tuiColors.primary} bold>┌─</Text>
|
|
99
|
+
<Text color={tuiColors.primary} bold> SYSTEM_STATUS </Text>
|
|
100
|
+
<Text color={tuiColors.textTertiary}>───────────</Text>
|
|
64
101
|
</Box>
|
|
65
102
|
|
|
66
103
|
<Box flexDirection="column" paddingX={1}>
|
|
67
|
-
<Text color=
|
|
68
|
-
<Text color="white">{currentWorkflow || "Aucun"}</Text>
|
|
104
|
+
<Text color={tuiColors.textTertiary} bold>ORCHESTRATOR</Text>
|
|
69
105
|
<Box flexDirection="row">
|
|
70
|
-
<Text color=
|
|
71
|
-
<Text color={
|
|
106
|
+
<Text color={tuiColors.textSecondary}>Status:</Text>
|
|
107
|
+
<Text color={tuiColors.success}> </Text>
|
|
108
|
+
<Pulse interval={600} color={tuiColors.success} type="breath" />
|
|
109
|
+
<Text color={tuiColors.success}> ACTIVE</Text>
|
|
72
110
|
</Box>
|
|
73
111
|
</Box>
|
|
74
112
|
|
|
75
113
|
<Box flexDirection="column" paddingX={1} marginTop={1}>
|
|
76
|
-
<Text color=
|
|
77
|
-
{
|
|
78
|
-
|
|
114
|
+
<Text color={tuiColors.textTertiary} bold>WORKFLOW</Text>
|
|
115
|
+
<Text color={tuiColors.textPrimary}>{workflowDisplay}</Text>
|
|
116
|
+
<FitnessAnimator value={fitness} />
|
|
117
|
+
</Box>
|
|
118
|
+
|
|
119
|
+
<Box flexDirection="column" paddingX={1} marginTop={1}>
|
|
120
|
+
<Text color={tuiColors.textTertiary} bold>ACTIVE AGENTS</Text>
|
|
121
|
+
{activeAgents.map((agent) => (
|
|
122
|
+
<AgentRow key={agent.name} agent={agent} tick={tick} />
|
|
79
123
|
))}
|
|
124
|
+
{hasNoActiveAgents && (
|
|
125
|
+
<Text color={tuiColors.textQuaternary}> ○ All idle</Text>
|
|
126
|
+
)}
|
|
80
127
|
</Box>
|
|
81
128
|
|
|
82
129
|
<Box flexDirection="column" paddingX={1} marginTop={1}>
|
|
83
|
-
<Text color=
|
|
130
|
+
<Text color={tuiColors.textTertiary} bold>PROVIDERS</Text>
|
|
84
131
|
{providers.map((provider) => (
|
|
85
|
-
<ProviderRow key={provider.name} provider={provider} />
|
|
132
|
+
<ProviderRow key={provider.name} provider={provider} tick={tick} />
|
|
86
133
|
))}
|
|
87
134
|
</Box>
|
|
88
135
|
</Box>
|
|
89
136
|
);
|
|
90
|
-
}
|
|
137
|
+
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import React, { memo, useMemo } from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { tuiColors, treeChars } from "../styles/index.js";
|
|
4
|
+
import { AgentStateIcon, AgentState } from "./AgentStateIcon.js";
|
|
5
|
+
import { AnimatedBranch } from "./AnimatedBranch.js";
|
|
6
|
+
|
|
7
|
+
export interface TaskNode {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
state: AgentState;
|
|
11
|
+
level: number;
|
|
12
|
+
detail?: string;
|
|
13
|
+
children?: TaskNode[];
|
|
14
|
+
executionTime?: number;
|
|
15
|
+
subtasks?: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface TaskNodeItemProps {
|
|
19
|
+
node: TaskNode;
|
|
20
|
+
tick: number;
|
|
21
|
+
isLast: boolean;
|
|
22
|
+
showDetail?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const TaskNodeItem = memo(function TaskNodeItem({ node, tick, isLast, showDetail = true }: TaskNodeItemProps) {
|
|
26
|
+
const indent = useMemo(() => " ".repeat(node.level), [node.level]);
|
|
27
|
+
const prefix = isLast ? treeChars.lastBranch : treeChars.branch;
|
|
28
|
+
const timeStr = node.executionTime ? `${node.executionTime.toFixed(1)}s` : "";
|
|
29
|
+
const paddedName = useMemo(() => node.name.padEnd(20), [node.name]);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Box flexDirection="column">
|
|
33
|
+
<Box flexDirection="row">
|
|
34
|
+
<Text color={tuiColors.textTertiary}>{indent}{prefix} </Text>
|
|
35
|
+
<Box flexDirection="row">
|
|
36
|
+
<Text color={tuiColors.textSecondary}>[</Text>
|
|
37
|
+
<AgentStateIcon state={node.state} tick={tick} />
|
|
38
|
+
<Text color={tuiColors.textSecondary}>]</Text>
|
|
39
|
+
</Box>
|
|
40
|
+
<Text color={tuiColors.textPrimary}> {paddedName}</Text>
|
|
41
|
+
{timeStr && (
|
|
42
|
+
<Text color={tuiColors.textTertiary}> ● {timeStr}</Text>
|
|
43
|
+
)}
|
|
44
|
+
</Box>
|
|
45
|
+
{showDetail && node.detail && (
|
|
46
|
+
<Box flexDirection="row">
|
|
47
|
+
<Text color={tuiColors.textTertiary}>{indent} └── </Text>
|
|
48
|
+
<Text color={tuiColors.textSecondary}>{node.detail}</Text>
|
|
49
|
+
</Box>
|
|
50
|
+
)}
|
|
51
|
+
{showDetail && node.subtasks && node.subtasks.length > 0 && (
|
|
52
|
+
<Box flexDirection="column">
|
|
53
|
+
{node.subtasks.map((subtask, idx) => (
|
|
54
|
+
<Box key={idx} flexDirection="row">
|
|
55
|
+
<Text color={tuiColors.textTertiary}>{indent} {idx === node.subtasks!.length - 1 ? '└──' : '├──'} </Text>
|
|
56
|
+
<Text color={tuiColors.textTertiary}>{subtask}</Text>
|
|
57
|
+
</Box>
|
|
58
|
+
))}
|
|
59
|
+
</Box>
|
|
60
|
+
)}
|
|
61
|
+
</Box>
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export interface TaskTreeProps {
|
|
66
|
+
rootTask: string;
|
|
67
|
+
tasks: TaskNode[];
|
|
68
|
+
tick: number;
|
|
69
|
+
isActive?: boolean;
|
|
70
|
+
maxDisplay?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const TaskTree = memo(function TaskTree({ rootTask, tasks, tick, isActive = false, maxDisplay = 15 }: TaskTreeProps) {
|
|
74
|
+
const borderColor = isActive ? tuiColors.primary : tuiColors.border;
|
|
75
|
+
const displayTasks = useMemo(() => tasks.slice(0, maxDisplay), [tasks, maxDisplay]);
|
|
76
|
+
const hiddenCount = tasks.length - maxDisplay;
|
|
77
|
+
|
|
78
|
+
const taskElements = useMemo(() =>
|
|
79
|
+
displayTasks.map((task, idx) => (
|
|
80
|
+
<TaskNodeItem
|
|
81
|
+
key={task.id}
|
|
82
|
+
node={task}
|
|
83
|
+
tick={tick}
|
|
84
|
+
isLast={idx === displayTasks.length - 1 && hiddenCount === 0}
|
|
85
|
+
/>
|
|
86
|
+
)),
|
|
87
|
+
[displayTasks, tick, hiddenCount]
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<Box flexDirection="column" borderStyle="single" borderColor={borderColor} paddingX={1}>
|
|
92
|
+
<Box marginBottom={1}>
|
|
93
|
+
<Text color={tuiColors.primary} bold>┌─</Text>
|
|
94
|
+
<Text color={tuiColors.primary} bold> TASK_TREE </Text>
|
|
95
|
+
<Text color={tuiColors.textTertiary}>────────────────────</Text>
|
|
96
|
+
</Box>
|
|
97
|
+
|
|
98
|
+
<Box flexDirection="row">
|
|
99
|
+
<Text color={tuiColors.textPrimary} bold>■ </Text>
|
|
100
|
+
<Text color={tuiColors.textSecondary}>root: {rootTask}</Text>
|
|
101
|
+
</Box>
|
|
102
|
+
|
|
103
|
+
<Box flexDirection="column" marginTop={1}>
|
|
104
|
+
<AnimatedBranch type="vertical" tick={tick} animated={isActive} />
|
|
105
|
+
</Box>
|
|
106
|
+
|
|
107
|
+
<Box flexDirection="column">
|
|
108
|
+
{taskElements}
|
|
109
|
+
{hiddenCount > 0 && (
|
|
110
|
+
<Box flexDirection="row">
|
|
111
|
+
<Text color={tuiColors.textTertiary}> └── +{hiddenCount} more tasks...</Text>
|
|
112
|
+
</Box>
|
|
113
|
+
)}
|
|
114
|
+
</Box>
|
|
115
|
+
</Box>
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
interface TaskHierarchyProps {
|
|
120
|
+
tasks: TaskNode[];
|
|
121
|
+
tick: number;
|
|
122
|
+
expandedIds?: Set<string>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const TaskHierarchy = memo(function TaskHierarchy({ tasks, tick, expandedIds = new Set() }: TaskHierarchyProps) {
|
|
126
|
+
const renderNode = (node: TaskNode, isLast: boolean): React.ReactNode => {
|
|
127
|
+
const hasChildren = (node.children?.length ?? 0) > 0;
|
|
128
|
+
const isExpanded = expandedIds.has(node.id);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<Box key={node.id} flexDirection="column">
|
|
132
|
+
<TaskNodeItem
|
|
133
|
+
node={node}
|
|
134
|
+
tick={tick}
|
|
135
|
+
isLast={isLast}
|
|
136
|
+
showDetail={isExpanded}
|
|
137
|
+
/>
|
|
138
|
+
{hasChildren && isExpanded && (
|
|
139
|
+
<Box flexDirection="column" marginLeft={2}>
|
|
140
|
+
{node.children!.map((child, idx) => (
|
|
141
|
+
<Box key={child.id} flexDirection="column">
|
|
142
|
+
<Box flexDirection="row">
|
|
143
|
+
<AnimatedBranch type="vertical" tick={tick} />
|
|
144
|
+
</Box>
|
|
145
|
+
{renderNode(child, idx === node.children!.length - 1)}
|
|
146
|
+
</Box>
|
|
147
|
+
))}
|
|
148
|
+
</Box>
|
|
149
|
+
)}
|
|
150
|
+
</Box>
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<Box flexDirection="column">
|
|
156
|
+
{tasks.map((task, idx) => renderNode(task, idx === tasks.length - 1))}
|
|
157
|
+
</Box>
|
|
158
|
+
);
|
|
159
|
+
});
|