-
Notifications
You must be signed in to change notification settings - Fork 226
Add neo-tui console UI with plugin load and live show state #1099
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
cschuchardt88
wants to merge
12
commits into
neo-project:master-n3
Choose a base branch
from
cschuchardt88:feature/console-ui
base: master-n3
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
fc69dab
Add neo-tui cross-platform console UI for neo-cli
cschuchardt88 3bb794f
Allow neo-tui to start without a subcommand
cschuchardt88 f4212c4
Load plugins into neo-tui and show live node status
cschuchardt88 f253264
Add neo-tui screenshots for the PR description
cschuchardt88 4d26ceb
Move neo-tui README to docs and add current screenshots
cschuchardt88 4444a54
Add current neo-tui clear-command screenshot
cschuchardt88 f7e8e0a
Caption command-line screenshot as neo-cli neo> prompt
cschuchardt88 1d0c29f
Merge branch 'master-n3' into feature/console-ui
shargon 50a16f0
Merge branch 'master-n3' into feature/console-ui
superboyiii 3eb1f7e
Update src/Neo.CLI/CLI/MainService.cs
shargon 3a6b97c
Merge branch 'master-n3' into feature/console-ui
ajara87 c887ca5
Merge branch 'master-n3' into feature/console-ui
ajara87 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # neo-tui | ||
|
|
||
| Cross-platform console UI for **neo-cli** (Windows, Linux, macOS). | ||
|
|
||
| It starts the same `MainService` node as `neo-cli`, loads plugins from `Plugins/` the same way, then shows the live **show state** dashboard. | ||
|
|
||
| - Live **node status** (block height, mempool, peers, sync) — same data as `show state` | ||
| - **CONNECTED PEERS** from `LocalNode` (Up/Down to scroll when there are more than five) | ||
| - Command **output popup** on this console with **Please wait** until the command finishes, then **Rerun command** or **Close** | ||
| - Category **menus** (`M` / Enter from the status screen) | ||
| - **Command palette** of every `[ConsoleCommand]`, including plugin commands | ||
| - **Line editor** with history, Tab complete, Ctrl+A/E/U | ||
| - Direct `System.CommandLine` subcommands (`neo-tui help`, `neo-tui show block 1`, …) | ||
|
|
||
| ## Run (from repo) | ||
|
|
||
| ```bash | ||
| dotnet run --project src/Neo.ConsoleUI | ||
| ``` | ||
|
|
||
| Or after build: | ||
|
|
||
| ```bash | ||
| dotnet build src/Neo.ConsoleUI/Neo.ConsoleUI.csproj | ||
| # output: src/Neo.ConsoleUI/bin/Debug/net10.0/neo-tui.dll | ||
| dotnet src/Neo.ConsoleUI/bin/Debug/net10.0/neo-tui.dll | ||
| ``` | ||
|
|
||
| Startup flags match neo-cli: `--config`/`-c`, `--wallet`/`-w`, `--password`/`-p`, `--db-engine`, `--db-path`, `--plugins`, `--noverify`. | ||
|
|
||
| The working directory is the exe folder so `Plugins/`, `config.json`, and auto-install zips resolve the same way as neo-cli. On build, each plugin is copied next to the binary: `bin/$(Configuration)/$(TargetFramework)/Plugins/<Name>/` (the folder is created if it is missing). Extra plugins can still be installed at runtime (`--plugins RpcServer` or the `install` command). | ||
|
|
||
| ## Screenshots | ||
|
|
||
| Wide status dashboard — 2×2 metrics, sync bar, **CONNECTED PEERS** on the right (title on the time row, table aligned with BLOCKCHAIN STATUS): | ||
|
|
||
|  | ||
|
|
||
| Peer list scrolled (`6-10/10`): | ||
|
|
||
|  | ||
|
|
||
| Narrow window — peers drop below the 2×2: | ||
|
|
||
|  | ||
|
|
||
| Command menu (`M` / Enter): | ||
|
|
||
|  | ||
|
|
||
| Plugin commands: | ||
|
|
||
|  | ||
|
|
||
| Please wait while a command runs: | ||
|
|
||
|  | ||
|
|
||
| Command output popup — **Rerun command** / **Close**: | ||
|
|
||
|  | ||
|
|
||
|  | ||
|
|
||
| Menu command parameters: | ||
|
|
||
|  | ||
|
|
||
| Command line (`C`) — same `neo>` prompt as neo-cli: | ||
|
|
||
|  |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| <Project> | ||
| <Target Name="CopyNodePlugins" AfterTargets="Build"> | ||
| <PropertyGroup> | ||
| <_PluginRoot>$(MSBuildThisFileDirectory)..\plugins</_PluginRoot> | ||
| <_PluginOut>$(TargetDir)Plugins</_PluginOut> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <_PluginAllDll Include="$(_PluginRoot)\%(NodePlugin.Identity)\bin\$(Configuration)\$(TargetFramework)\*.dll"> | ||
| <PluginName>%(NodePlugin.Identity)</PluginName> | ||
| </_PluginAllDll> | ||
| <_PluginJson Include="$(_PluginRoot)\%(NodePlugin.Identity)\bin\$(Configuration)\$(TargetFramework)\%(NodePlugin.Identity).json"> | ||
| <PluginName>%(NodePlugin.Identity)</PluginName> | ||
| </_PluginJson> | ||
| <_PluginRuntime Include="$(_PluginRoot)\%(NodePlugin.Identity)\bin\$(Configuration)\$(TargetFramework)\runtimes\**\*"> | ||
| <PluginName>%(NodePlugin.Identity)</PluginName> | ||
| </_PluginRuntime> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <!-- Plugin assembly itself. --> | ||
| <_PluginOwnDll Include="@(_PluginAllDll)" Condition="Exists('%(FullPath)') AND '%(Filename)' == '%(PluginName)'" /> | ||
| <!-- Extra dependency dlls: not already next to the exe, and not another plugin project. --> | ||
| <_PluginDepDll Include="@(_PluginAllDll)" Condition="Exists('%(FullPath)') AND '%(Filename)' != '%(PluginName)' AND !Exists('$(TargetDir)%(Filename)%(Extension)') AND !Exists('$(_PluginRoot)\%(Filename)\%(Filename).csproj')" /> | ||
| <_PluginJsonExisting Include="@(_PluginJson)" Condition="Exists('%(FullPath)')" /> | ||
| <_PluginRuntimeExisting Include="@(_PluginRuntime)" Condition="Exists('%(FullPath)')" /> | ||
| </ItemGroup> | ||
| <MakeDir Directories="$(_PluginOut);@(_PluginOwnDll->'$(_PluginOut)\%(PluginName)')" /> | ||
| <Copy SourceFiles="@(_PluginOwnDll)" DestinationFolder="$(_PluginOut)\%(PluginName)\" SkipUnchangedFiles="true" /> | ||
| <Copy SourceFiles="@(_PluginDepDll)" DestinationFolder="$(_PluginOut)\%(PluginName)\" SkipUnchangedFiles="true" /> | ||
| <!-- Plugin.Load(byte[]) resolves managed deps from the exe directory, not only Plugins/<Name>/. --> | ||
| <Copy SourceFiles="@(_PluginDepDll)" DestinationFolder="$(TargetDir)" SkipUnchangedFiles="true" /> | ||
| <Copy SourceFiles="@(_PluginJsonExisting)" DestinationFolder="$(_PluginOut)\%(PluginName)\" SkipUnchangedFiles="true" /> | ||
| <Copy SourceFiles="@(_PluginRuntimeExisting)" DestinationFiles="$(_PluginOut)\%(PluginName)\runtimes\%(RecursiveDir)%(Filename)%(Extension)" SkipUnchangedFiles="true" /> | ||
| <Copy SourceFiles="$(_PluginRoot)\MPTTrie\bin\$(Configuration)\$(TargetFramework)\MPTTrie.dll" DestinationFolder="$(_PluginOut)\StateService\" SkipUnchangedFiles="true" Condition="Exists('$(_PluginRoot)\MPTTrie\bin\$(Configuration)\$(TargetFramework)\MPTTrie.dll')" /> | ||
| <PropertyGroup> | ||
| <_HostRid>$([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier)</_HostRid> | ||
| <_CopyRid>$(_HostRid)</_CopyRid> | ||
| <_CopyRid Condition="!Exists('$(_PluginRoot)\LevelDBStore\bin\$(Configuration)\$(TargetFramework)\runtimes\$(_CopyRid)\native')">win-x64</_CopyRid> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <_HostNative Include="$(_PluginRoot)\LevelDBStore\bin\$(Configuration)\$(TargetFramework)\runtimes\$(_CopyRid)\native\*.*" /> | ||
| <_HostNative Include="$(_PluginRoot)\RocksDBStore\bin\$(Configuration)\$(TargetFramework)\runtimes\$(_CopyRid)\native\*.*" /> | ||
| <_HostNative Include="$(_PluginRoot)\SQLiteWallet\bin\$(Configuration)\$(TargetFramework)\runtimes\$(_CopyRid)\native\*.*" /> | ||
| <_HostNativeExisting Include="@(_HostNative)" Condition="Exists('%(FullPath)')" /> | ||
| <_LevelDbNative Include="$(_PluginRoot)\LevelDBStore\bin\$(Configuration)\$(TargetFramework)\runtimes\**\*" Condition="Exists('$(_PluginRoot)\LevelDBStore\bin\$(Configuration)\$(TargetFramework)\runtimes')" /> | ||
| </ItemGroup> | ||
| <!-- P/Invoke looks next to the exe, not in runtimes/, when LevelDBStore is loaded as a plugin. --> | ||
| <Copy SourceFiles="@(_HostNativeExisting)" DestinationFolder="$(TargetDir)" SkipUnchangedFiles="true" /> | ||
| <Copy SourceFiles="@(_LevelDbNative)" DestinationFiles="$(TargetDir)runtimes\%(_LevelDbNative.RecursiveDir)%(_LevelDbNative.Filename)%(_LevelDbNative.Extension)" SkipUnchangedFiles="true" Condition="'@(_LevelDbNative)' != ''" /> | ||
| </Target> | ||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| // Copyright (C) 2015-2026 The Neo Project. | ||
| // | ||
| // CommandCatalog.cs file belongs to the neo project and is free | ||
| // software distributed under the MIT software license, see the | ||
| // accompanying file LICENSE in the main directory of the | ||
| // repository or http://www.opensource.org/licenses/mit-license.php | ||
| // for more details. | ||
| // | ||
| // Redistribution and use in source and binary forms with or without | ||
| // modifications are permitted. | ||
|
|
||
| using Neo.CLI; | ||
| using Neo.ConsoleService; | ||
| using Neo.Plugins; | ||
| using System.Reflection; | ||
|
|
||
| namespace Neo.ConsoleUI; | ||
|
|
||
| internal sealed record CommandInfo( | ||
| string Key, | ||
| string Category, | ||
| string Description, | ||
| MethodInfo Method, | ||
| object Instance); | ||
|
|
||
| internal static class CommandCatalog | ||
| { | ||
| public static IReadOnlyList<CommandInfo> Load(MainService service) | ||
| { | ||
| var list = new List<CommandInfo>(); | ||
| AddCommands(list, service, service); | ||
| AddCommands(list, service, service, typeof(ConsoleServiceBase)); | ||
| foreach (var plugin in Plugin.Plugins) | ||
| AddCommands(list, plugin, plugin); | ||
|
|
||
| return list | ||
| .OrderBy(c => c.Category, StringComparer.Ordinal) | ||
| .ThenBy(c => c.Key, StringComparer.Ordinal) | ||
| .ToArray(); | ||
| } | ||
|
|
||
| private static void AddCommands(List<CommandInfo> list, object instance, object owner, Type? type = null) | ||
| { | ||
| type ??= instance.GetType(); | ||
| foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) | ||
| { | ||
| foreach (var attribute in method.GetCustomAttributes<ConsoleCommandAttribute>(inherit: true)) | ||
| { | ||
| var key = string.Join(' ', attribute.Verbs); | ||
| if (list.Any(c => c.Key == key && c.Method == method)) | ||
| continue; | ||
| list.Add(new CommandInfo( | ||
| key, | ||
| string.IsNullOrWhiteSpace(attribute.Category) ? "Commands" : attribute.Category, | ||
| attribute.Description, | ||
| method, | ||
| owner)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static IEnumerable<string> Categories(IReadOnlyList<CommandInfo> commands) | ||
| => commands.Select(c => c.Category).Distinct(StringComparer.Ordinal); | ||
|
|
||
| public static IReadOnlyList<string> Completions(IReadOnlyList<CommandInfo> commands) | ||
| => commands.Select(c => c.Key).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.