diff --git a/README.md b/README.md index d3dcf4e..f220215 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Building an app that drives a VISA instrument and want to test it without the ha | `mock scenario` | `list` `create` `remove` `show` `activate` `deactivate` `record` `import` + `scene add` / `scene remove` | Author and capture mock-device scenarios | | `server` | `add` `remove` `list` `route add` / `route remove` / `route list` `start` `stop` `status` `log` | Gateway-server lifecycle | | `api` | `start` `stop` `token create` `token list` `token revoke` | Management HTTP JSON API (ADR 0034) + WebSocket subprotocol (ADR 0035) + PAT auth (ADR 0036) | -| top-level | `diagnose` `completion ` | Environment health + shell autocomplete | +| top-level | `doctor` `completion ` | Environment health + shell autocomplete | ## Verbosity & format flags diff --git a/docs/PRD.jp.md b/docs/PRD.jp.md index e781093..a5a1b1b 100644 --- a/docs/PRD.jp.md +++ b/docs/PRD.jp.md @@ -134,7 +134,7 @@ ivicli ├─ server # gateway / remote instrument publishing ├─ logical # logical name management ├─ config # configuration management - ├─ diagnose # environment diagnostics + ├─ doctor # environment diagnostics └─ driver # IVI driver management ``` @@ -360,12 +360,14 @@ route を削除する。 ## 6.4 Diagnostics -### diagnose +### doctor ```bash -ivicli diagnose +ivicli doctor ``` +後方互換のため `diagnose` を非推奨エイリアスとして残します(0.3.0 で削除予定)。 + 以下を診断: * IVI Shared Components @@ -648,7 +650,7 @@ CI / AI Agent 向け。 ```text Control Plane ┌─────────────────────────────────────────────────┐ -│ config / logical / diagnose / server route │ +│ config / logical / doctor / server route │ └─────────────────────────────────────────────────┘ ↓ Management API @@ -823,7 +825,7 @@ Phase 1: * visa use/current * visa query/write/read * visa status -* diagnose +* doctor * driver list — ローカルの IVI Configuration Store からインストール 済み IVI ドライバを列挙 (ADR 0045)。機器は通信できているのにドライ バ DLL が無い / バージョン不一致、といったデバッグで必須。 diff --git a/docs/PRD.md b/docs/PRD.md index 5c65bc5..c09208e 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -129,7 +129,7 @@ ivicli ├─ server # gateway / remote instrument publishing ├─ logical # logical name management ├─ config # configuration management - ├─ diagnose # environment diagnostics + ├─ doctor # environment diagnostics └─ driver # IVI driver management ``` @@ -356,12 +356,14 @@ Removes a route. ## 6.4 Diagnostics -### diagnose +### doctor ```bash -ivicli diagnose +ivicli doctor ``` +`diagnose` is kept as a deprecated alias for backward compatibility; it will be removed at 0.3.0. + Diagnoses the following: * IVI Shared Components @@ -643,7 +645,7 @@ Intended for CI / AI Agents. ```text Control Plane ┌─────────────────────────────────────────────────┐ -│ config / logical / diagnose / server route │ +│ config / logical / doctor / server route │ └─────────────────────────────────────────────────┘ ↓ Management API @@ -818,7 +820,7 @@ Phase 1: * visa use/current * visa query/write/read * visa status -* diagnose +* doctor * driver list — enumerate installed IVI drivers from the local IVI Configuration Store (ADR 0045). Essential for debugging when an instrument is online but the driver assembly is missing or mis- diff --git a/docs/README.jp.md b/docs/README.jp.md index 1b5a3ea..b78ffd1 100644 --- a/docs/README.jp.md +++ b/docs/README.jp.md @@ -107,7 +107,7 @@ VISA 計測器を操作するアプリを開発していて、実機を用意せ | `mock scenario` | `list` `create` `remove` `show` `activate` `deactivate` `record` `import` + `scene add` / `scene remove` | モックデバイス用シナリオの編集と記録 | | `server` | `add` `remove` `list` `route add` / `route remove` / `route list` `start` `stop` `status` `log` | ゲートウェイサーバのライフサイクル | | `api` | `start` `stop` `token create` `token list` `token revoke` | Management HTTP JSON API (ADR 0034) + WebSocket サブプロトコル (ADR 0035) + PAT 認証 (ADR 0036) | -| top-level | `diagnose` `completion ` | 環境ヘルスチェック + シェル補完 | +| top-level | `doctor` `completion ` | 環境ヘルスチェック + シェル補完 | ## 詳細度 / フォーマットのフラグ diff --git a/docs/adr/0003-architecture-style.md b/docs/adr/0003-architecture-style.md index eafb214..2b278ec 100644 --- a/docs/adr/0003-architecture-style.md +++ b/docs/adr/0003-architecture-style.md @@ -10,7 +10,7 @@ Assembly layout and dependency direction are established in 0021. This ADR build Constraints derived from the PRD and 0021: - Polymorphism over `IIviBackend` as a transport abstraction (HiSLIP / VXI-11 / Socket / Fake / Replay) -- Separation of the Data Plane (visa query/write/read) and the Control Plane (config / server route / diagnose) +- Separation of the Data Plane (visa query/write/read) and the Control Plane (config / server route / doctor) - Separation of static config (`config.toml`) and dynamic session state (`session.json`) - SCPI itself distinguishes write (`OUTP ON`) from query (`*IDN?`) by syntax diff --git a/src/IviCli.Application/ApplicationServiceCollectionExtensions.cs b/src/IviCli.Application/ApplicationServiceCollectionExtensions.cs index 868444f..c1daf04 100644 --- a/src/IviCli.Application/ApplicationServiceCollectionExtensions.cs +++ b/src/IviCli.Application/ApplicationServiceCollectionExtensions.cs @@ -38,7 +38,7 @@ public static IServiceCollection AddIviCliApplication(this IServiceCollection se services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/IviCli.Application/Diagnostics/DiagnoseQuery.cs b/src/IviCli.Application/Diagnostics/DoctorQuery.cs similarity index 82% rename from src/IviCli.Application/Diagnostics/DiagnoseQuery.cs rename to src/IviCli.Application/Diagnostics/DoctorQuery.cs index 1ff76d0..5df812d 100644 --- a/src/IviCli.Application/Diagnostics/DiagnoseQuery.cs +++ b/src/IviCli.Application/Diagnostics/DoctorQuery.cs @@ -3,8 +3,8 @@ namespace IviCli.Application.Diagnostics; -/// Query DTO for ivicli diagnose (PRD §6.4). -public sealed record DiagnoseQuery; +/// Query DTO for ivicli doctor (PRD §6.4). +public sealed record DoctorQuery; /// The overall diagnostics report. /// The individual checks performed, in stable order. @@ -29,8 +29,8 @@ public enum DiagnosticStatus Error, } -/// Errors that the diagnose query itself can fail with (rare — most issues are reported as DiagnosticCheck entries). -public abstract record DiagnoseError : IviError +/// Errors that the doctor query itself can fail with (rare — most issues are reported as DiagnosticCheck entries). +public abstract record DoctorError : IviError { /// public abstract LogSeverity Severity { get; } diff --git a/src/IviCli.Application/Diagnostics/DiagnoseQueryHandler.cs b/src/IviCli.Application/Diagnostics/DoctorQueryHandler.cs similarity index 91% rename from src/IviCli.Application/Diagnostics/DiagnoseQueryHandler.cs rename to src/IviCli.Application/Diagnostics/DoctorQueryHandler.cs index f6089ce..5225677 100644 --- a/src/IviCli.Application/Diagnostics/DiagnoseQueryHandler.cs +++ b/src/IviCli.Application/Diagnostics/DoctorQueryHandler.cs @@ -6,13 +6,13 @@ namespace IviCli.Application.Diagnostics; /// -/// Application-layer handler for ivicli diagnose (PRD §6.4). Reports +/// Application-layer handler for ivicli doctor (PRD §6.4). Reports /// runtime, config, and backend-registration health. Since each check is /// reported independently, the handler does not fail at the command level; /// even when every check is in Error state the caller still receives a /// populated . /// -public sealed class DiagnoseQueryHandler +public sealed class DoctorQueryHandler { private readonly IFileSystem _fs; private readonly IEnumerable _backends; @@ -21,7 +21,7 @@ public sealed class DiagnoseQueryHandler private readonly string _logDirectory; /// Creates a new handler. - public DiagnoseQueryHandler( + public DoctorQueryHandler( IFileSystem fs, IEnumerable backends, IEnumerable scanners, @@ -36,8 +36,8 @@ DiagnoseHandlerOptions options } /// Runs every diagnostic check and aggregates them. - public Task> HandleAsync( - DiagnoseQuery query, + public Task> HandleAsync( + DoctorQuery query, CancellationToken ct ) { @@ -53,7 +53,7 @@ CancellationToken ct checks.Add(CheckScanners()); return Task.FromResult( - Result.Success( + Result.Success( new DiagnosticsReport(checks.ToImmutable()) ) ); @@ -134,7 +134,7 @@ private DiagnosticCheck CheckScanners() } } -/// Composition-time options for . +/// Composition-time options for . /// Absolute path to the config.toml file. /// Absolute path to the log output directory. public sealed record DiagnoseHandlerOptions(string ConfigPath, string LogDirectory); diff --git a/src/IviCli.Cli/Commands/DiagnoseCommand.cs b/src/IviCli.Cli/Commands/DoctorCommand.cs similarity index 82% rename from src/IviCli.Cli/Commands/DiagnoseCommand.cs rename to src/IviCli.Cli/Commands/DoctorCommand.cs index bbe91b7..d98e916 100644 --- a/src/IviCli.Cli/Commands/DiagnoseCommand.cs +++ b/src/IviCli.Cli/Commands/DoctorCommand.cs @@ -8,9 +8,9 @@ namespace IviCli.Cli.Commands; /// -/// Wires the ivicli diagnose top-level subcommand. +/// Wires the ivicli doctor top-level subcommand. /// -public static class DiagnoseCommand +public static class DoctorCommand { /// Builds the configured . public static Command Build(IServiceProvider services) @@ -18,23 +18,24 @@ public static Command Build(IServiceProvider services) var jsonOpt = new Option("--json") { Description = "Emit machine-readable JSON." }; var command = new Command( - "diagnose", + "doctor", "Report runtime, configuration, and backend-registration health." ); + command.Aliases.Add("diagnose"); // deprecated pre-rename spelling; drop at 0.3.0 command.Options.Add(jsonOpt); command.SetAction( async (parseResult, ct) => { var json = parseResult.GetValue(jsonOpt); - var handler = services.GetRequiredService(); - var logger = services.GetRequiredService>(); + var handler = services.GetRequiredService(); + var logger = services.GetRequiredService>(); - var result = await handler.HandleAsync(new DiagnoseQuery(), ct); + var result = await handler.HandleAsync(new DoctorQuery(), ct); return result switch { - Result.Ok ok => Render(ok.Value, json), - Result.Error err => Fail(err.Err, logger), + Result.Ok ok => Render(ok.Value, json), + Result.Error err => Fail(err.Err, logger), _ => ExitCodeMapper.GenericFailure, }; } @@ -80,7 +81,7 @@ private static int Render(DiagnosticsReport report, bool emitJson) : ExitCodeMapper.Success; } - private static int Fail(DiagnoseError error, ILogger logger) + private static int Fail(DoctorError error, ILogger logger) { logger.Log( Logging.SerilogConfiguration.ToLogLevel(error.Severity), @@ -88,7 +89,7 @@ private static int Fail(DiagnoseError error, ILogger logger) error.Message, error.LogArgs.ToArray() ); - Console.Error.WriteLine("error: diagnose failed."); + Console.Error.WriteLine("error: doctor failed."); return ExitCodeMapper.GenericFailure; } diff --git a/src/IviCli.Cli/Program.cs b/src/IviCli.Cli/Program.cs index 5c8e4f7..a6bc79d 100644 --- a/src/IviCli.Cli/Program.cs +++ b/src/IviCli.Cli/Program.cs @@ -414,7 +414,7 @@ private static RootCommand BuildRoot(IServiceProvider services) root.Subcommands.Add(mock); root.Subcommands.Add(ServerCommand.Build(services)); root.Subcommands.Add(ApiCommand.Build(services)); - root.Subcommands.Add(DiagnoseCommand.Build(services)); + root.Subcommands.Add(DoctorCommand.Build(services)); root.Subcommands.Add(DriverCommand.Build(services)); root.Subcommands.Add(LogicalCommand.Build(services)); root.Subcommands.Add(CompletionCommand.Build()); diff --git a/tests/IviCli.Application.Tests/Diagnostics/DiagnoseQueryHandlerTests.cs b/tests/IviCli.Application.Tests/Diagnostics/DoctorQueryHandlerTests.cs similarity index 84% rename from tests/IviCli.Application.Tests/Diagnostics/DiagnoseQueryHandlerTests.cs rename to tests/IviCli.Application.Tests/Diagnostics/DoctorQueryHandlerTests.cs index b00491f..d3cb64b 100644 --- a/tests/IviCli.Application.Tests/Diagnostics/DiagnoseQueryHandlerTests.cs +++ b/tests/IviCli.Application.Tests/Diagnostics/DoctorQueryHandlerTests.cs @@ -6,9 +6,9 @@ namespace IviCli.Application.Tests.Diagnostics; -public class DiagnoseQueryHandlerTests +public class DoctorQueryHandlerTests { - private static DiagnoseQueryHandler MakeHandler( + private static DoctorQueryHandler MakeHandler( bool configExists, bool logDirExists, IEnumerable? backends = null, @@ -28,7 +28,7 @@ private static DiagnoseQueryHandler MakeHandler( fs.AddDirectory(logDir); } - return new DiagnoseQueryHandler( + return new DoctorQueryHandler( fs, backends ?? Array.Empty(), scanners ?? Array.Empty(), @@ -48,7 +48,7 @@ public async Task Handle_AllPresent_ReportsAllOk() ); // When - var result = await handler.HandleAsync(new DiagnoseQuery(), CancellationToken.None); + var result = await handler.HandleAsync(new DoctorQuery(), CancellationToken.None); // Then var report = result.ShouldBeOk(); @@ -63,7 +63,7 @@ public async Task Handle_NoBackends_ReportsError() var handler = MakeHandler(configExists: true, logDirExists: true); // When - var result = await handler.HandleAsync(new DiagnoseQuery(), CancellationToken.None); + var result = await handler.HandleAsync(new DoctorQuery(), CancellationToken.None); // Then var report = result.ShouldBeOk(); @@ -83,7 +83,7 @@ public async Task Handle_MissingConfig_ReportsWarning() ); // When - var result = await handler.HandleAsync(new DiagnoseQuery(), CancellationToken.None); + var result = await handler.HandleAsync(new DoctorQuery(), CancellationToken.None); // Then var report = result.ShouldBeOk(); diff --git a/tests/IviCli.Cli.Tests/Commands/DoctorCommandTests.cs b/tests/IviCli.Cli.Tests/Commands/DoctorCommandTests.cs new file mode 100644 index 0000000..9df5795 --- /dev/null +++ b/tests/IviCli.Cli.Tests/Commands/DoctorCommandTests.cs @@ -0,0 +1,37 @@ +using System.CommandLine; +using IviCli.Cli.Commands; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; + +namespace IviCli.Cli.Tests.Commands; + +public sealed class DoctorCommandTests +{ + private static Command BuildDoctor() => + DoctorCommand.Build(new ServiceCollection().BuildServiceProvider()); + + [Fact] + public void Command_is_named_doctor() + { + BuildDoctor().Name.ShouldBe("doctor"); + } + + [Fact] + public void Diagnose_remains_a_deprecated_alias() + { + BuildDoctor().Aliases.ShouldContain("diagnose"); + } + + [Fact] + public void Parsing_the_alias_resolves_to_the_doctor_command() + { + var root = new RootCommand("test root"); + var doctor = BuildDoctor(); + root.Subcommands.Add(doctor); + + var result = root.Parse("diagnose"); + + result.Errors.ShouldBeEmpty(); + result.CommandResult.Command.ShouldBeSameAs(doctor); + } +}