diff --git a/README.md b/README.md index a2d50de..d3dcf4e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## Highlights - **Stateful, VISA-native CLI** - - **Stateful UX.** Register an alias once with `ivicli visa add psu1 ...`; subsequent commands operate on `psu1` without retyping the VISA resource. + - **A current device, like a shell's working directory.** `ivicli visa add psu1 ` registers an alias once; `ivicli visa use psu1` makes it *the current device*, so every later `visa query` / `write` / `script` needs no target at all — no VISA resource, not even the alias. - **VISA-compatible.** Parses standard `TCPIP::`, `USB::`, `GPIB::` resource strings without proprietary syntax. - **Automation-friendly.** Stdout carries data (including `--json`); stderr carries logs. Exit codes are POSIX-conventional. Shell completion ships for bash / zsh / PowerShell. - **Discover & inspect** @@ -19,9 +19,9 @@ - **Multiple backends.** Local NI-VISA, HiSLIP, VXI-11, raw TCP SOCKET, Fake (programmable + scenario playback), Replay (strict deterministic playback) — all behind a single `IIviBackend` port. - **Gateway servers.** Expose a local instrument over HiSLIP (`TCPIP::host::hislip0::INSTR`) or raw socket so remote PyVISA / NI-VISA clients can drive it without redeploying the test. - **Test without hardware** - - **Recordable scenarios.** `mock scenario record --from-script` captures the SCPI traffic of a script run; `IVICLI_REPLAY=` re-runs the same scripts deterministically without hardware. - - **Record once, replay forever.** Capture a real session with `IVICLI_CAPTURE`, convert it via `mock scenario import`, then drive any verb with `IVICLI_REPLAY=` — no more hardware time burned on regression checks. - - **Lint your scripts.** `visa lint foo.scpi` catches unknown SCPI roots (IEEE 488.2 + SCPI core) before you run them, without touching the instrument. + - **Run a mock instrument.** The `Fake` backend answers SCPI from a *scenario* — a scripted set of `query → response` rules — so `ivicli` (or your own VISA app) can talk to a stand-in with zero bench time. + - **Capture, then replay.** Record a live session (`IVICLI_CAPTURE=`) or a SCPI script run (`mock scenario record --from-script foo.scpi`) into a scenario, then re-run it deterministically with `IVICLI_REPLAY=` — no hardware burned on regression checks. + - **Run & lint SCPI scripts.** `visa script foo.scpi` runs a `.scpi` file — [SCPI](https://www.ivifoundation.org/downloads/SCPI/scpi-99.pdf) commands plus ivi-cli's inline assertions ([ADR 0027](docs/adr/0027-phase3-operator-automation.md)) — against the current device; `visa lint foo.scpi` flags unknown SCPI roots (IEEE 488.2 + SCPI core) before you run it. - **Audit-friendly.** Set `IVICLI_CAPTURE=` and every backend operation streams to an NDJSON log for post-hoc inspection — `tail -f path | jq` or hand it to support. - **Control plane (HTTP / WebSocket API)** - **JSON HTTP API.** `ivicli api start` exposes a JSON HTTP API at `http://127.0.0.1:8080/v1` (with `/openapi/v1.json`) so AI agents, dashboards, and CI scripts can list devices / fire SCPI queries / read status without speaking VISA. @@ -135,32 +135,48 @@ ivicli completion powershell | Out-String | Invoke-Expression Once installed, `` expands subcommands, options, and runtime identifiers (device aliases, server names, scenario names). -## Architecture +## How it connects + +`ivicli` sits between a caller and an instrument. The four ways you use it: + +**1 · Drive real hardware** + +```mermaid +flowchart LR + u["you / CI"] -->|"VISA — NI-VISA / HiSLIP / VXI-11 / SOCKET"| c["ivicli"] --> i["instrument (LAN, USB/GPIB)"] +``` + +**2 · Test without hardware** + +```mermaid +flowchart LR + u["you / CI"] --> c["ivicli"] -->|"Fake / Replay / mock container"| n["no hardware"] +``` + +**3 · Expose a local instrument** + +```mermaid +flowchart LR + r["remote PyVISA / NI-VISA client"] -->|"HiSLIP / SOCKET gateway"| c["ivicli"] --> i["local instrument"] +``` + +**4 · Control plane** ```mermaid flowchart LR - Cli["IviCli.Cli
(composition root)"] --> App["IviCli.Application
(handlers, ports)"] - Cli --> Server["IviCli.Server
(HiSLIP / SOCKET gateways)"] - Server --> App - Cli --> Infra["IviCli.Infrastructure
(TomlConfigStore, FilePidRegistry)"] - Infra --> App - Cli --> Backends["IviCli.Backends.*
(Fake / Local / HiSlip / Vxi11 / Socket / Replay)"] - Backends --> App - App --> Domain["IviCli.Domain
(value objects, entities, errors)"] - Server --> Domain - Backends --> Domain + a["AI agent / dashboard / CI"] -->|"HTTP / WebSocket API"| c["ivicli"] --> i["instrument"] ``` -Dependency direction is one-way (Domain ← Application ← {Infrastructure, Backends, Server} ← Cli). The architecture-test suite (`tests/IviCli.Cli.Tests/Architecture/`) enforces it on every PR. +The internal layering (Clean Architecture + one-way dependency direction, enforced by an architecture-test suite) is documented for contributors in [ADR 0003](docs/adr/0003-architecture-style.md) and [ADR 0021](docs/adr/0021-repository-layout.md). ## Documentation -- [PRD](docs/PRD.md) — full product requirements ([日本語](docs/PRD.jp.md)) +- [PRD](docs/PRD.md) — full product requirements - [Architecture Decision Records](docs/adr/) — every Accepted decision behind the implementation. Start with [ADR 0003](docs/adr/0003-architecture-style.md) (architecture style), [ADR 0021](docs/adr/0021-repository-layout.md) (layer assemblies), [ADR 0007](docs/adr/0007-network-transport.md) (HiSLIP / SOCKET). - [Domain glossary](docs/domain-glossary.md) — the ubiquitous-language catalog - [Guides](docs/guides/) — task-oriented how-tos, starting with [Mock a VISA instrument](docs/guides/mock-a-visa-instrument.md) -- [Samples](docs/samples/) — drop-in scenarios + setup scripts (e.g. [PSU mock VISA device](docs/samples/psu/)) -- [Contributing](docs/CONTRIBUTING.md) — local dev loop, branching, hooks ([日本語](docs/CONTRIBUTING.jp.md)) +- [Samples](docs/samples/) — ready-made **mock instruments** for testing without hardware: drop-in scenarios + setup scripts (e.g. the [PSU mock](docs/samples/psu/)) +- [Contributing](docs/CONTRIBUTING.md) — local dev loop, branching, hooks ## Building from source diff --git a/docs/README.jp.md b/docs/README.jp.md index e647def..1b5a3ea 100644 --- a/docs/README.jp.md +++ b/docs/README.jp.md @@ -9,7 +9,7 @@ ## ハイライト - **状態保持型・VISA ネイティブな CLI** - - **状態保持型 UX.** `ivicli visa add psu1 ...` で alias を一度登録すれば、以降は `psu1` だけで操作できます。 + - **シェルのカレントディレクトリのような「現在の機器」.** `ivicli visa add psu1 ` で alias を一度登録し、`ivicli visa use psu1` で *現在の機器* に設定すれば、以降の `visa query` / `write` / `script` は対象指定が一切不要です(VISA リソースはもちろん alias すら書かなくてよい)。 - **VISA 互換.** 標準的な `TCPIP::` / `USB::` / `GPIB::` のリソース文字列を独自構文なしで扱います。 - **自動化指向.** stdout はデータ (`--json` 含む)、stderr はログ専用。終了コードは POSIX 慣習に従い、bash / zsh / PowerShell の補完をサポートします。 - **発見と可視化** @@ -19,9 +19,9 @@ - **複数バックエンド.** Local NI-VISA / HiSLIP / VXI-11 / raw TCP SOCKET / Fake (プログラム可能 + scenario 再生) / Replay (厳密な決定論的再生) を単一の `IIviBackend` port 越しに提供します。 - **ゲートウェイサーバ.** ローカル計測器を HiSLIP (`TCPIP::host::hislip0::INSTR`) または raw socket で公開し、リモートの PyVISA / NI-VISA クライアントから駆動できます。 - **ハードウェアなしでテスト** - - **シナリオ録画.** `mock scenario record --from-script` でスクリプト実行中の SCPI トラフィックを取得、`IVICLI_REPLAY=` で同じスクリプトをハードウェアなしに決定論的に再実行できます。 - - **一度録って何度でも再生.** `IVICLI_CAPTURE` で実機セッションを取り、`mock scenario import` で scenario に変換、以後 `IVICLI_REPLAY=` で同じ動作をハードウェア占有なしに再現できます。 - - **スクリプト Lint.** `visa lint foo.scpi` で IEEE 488.2 / SCPI core の語彙に対する未知のルートを計測器に触らずに検出します。 + - **モック計測器を動かす.** `Fake` backend は *scenario*(`query → response` ルールの集合)に従って SCPI に応答するので、`ivicli`(または自作の VISA アプリ)を実機なしのスタンドインと対話させられます。 + - **録って再生.** 実機セッション(`IVICLI_CAPTURE=`)または SCPI スクリプト実行(`mock scenario record --from-script foo.scpi`)を scenario に録り、`IVICLI_REPLAY=` で決定論的に再実行できます — 回帰チェックに実機を消費しません。 + - **SCPI スクリプトの実行と Lint.** `visa script foo.scpi` は `.scpi` ファイル([SCPI](https://www.ivifoundation.org/downloads/SCPI/scpi-99.pdf) コマンド + ivi-cli 独自のインラインアサーション、[ADR 0027](adr/0027-phase3-operator-automation.md))を現在の機器に対して実行、`visa lint foo.scpi` は実行前に未知の SCPI ルート(IEEE 488.2 + SCPI core)を検出します。 - **監査向け.** `IVICLI_CAPTURE=` を設定するとすべての backend 操作が NDJSON ログにストリームされ、`tail -f path | jq` で後追い確認やサポート提出に利用できます。 - **コントロールプレーン (HTTP / WebSocket API)** - **JSON HTTP API.** `ivicli api start` で HTTP JSON API を `http://127.0.0.1:8080/v1` に公開(`/openapi/v1.json` 付き)。AI agent / ダッシュボード / CI スクリプトが VISA を喋らずに device 列挙・SCPI クエリ・status 取得できます。 @@ -135,32 +135,48 @@ ivicli completion powershell | Out-String | Invoke-Expression 導入後、`` でサブコマンド・オプション・実行時識別子(device alias、server 名、scenario 名)が展開されます。 -## アーキテクチャ +## どう繋がるか + +`ivicli` は呼び出し側と計測器の間に立ちます。使い方は次の 4 通りです: + +**1 · 実機を操作** + +```mermaid +flowchart LR + u["you / CI"] -->|"VISA — NI-VISA / HiSLIP / VXI-11 / SOCKET"| c["ivicli"] --> i["計測器 (LAN, USB/GPIB)"] +``` + +**2 · ハードウェアなしでテスト** + +```mermaid +flowchart LR + u["you / CI"] --> c["ivicli"] -->|"Fake / Replay / mock container"| n["ハードウェアなし"] +``` + +**3 · ローカル計測器を公開** + +```mermaid +flowchart LR + r["remote PyVISA / NI-VISA client"] -->|"HiSLIP / SOCKET gateway"| c["ivicli"] --> i["ローカル計測器"] +``` + +**4 · コントロールプレーン** ```mermaid flowchart LR - Cli["IviCli.Cli
(composition root)"] --> App["IviCli.Application
(handlers, ports)"] - Cli --> Server["IviCli.Server
(HiSLIP / SOCKET gateways)"] - Server --> App - Cli --> Infra["IviCli.Infrastructure
(TomlConfigStore, FilePidRegistry)"] - Infra --> App - Cli --> Backends["IviCli.Backends.*
(Fake / Local / HiSlip / Vxi11 / Socket / Replay)"] - Backends --> App - App --> Domain["IviCli.Domain
(value objects, entities, errors)"] - Server --> Domain - Backends --> Domain + a["AI agent / dashboard / CI"] -->|"HTTP / WebSocket API"| c["ivicli"] --> i["計測器"] ``` -依存方向は一方向 (Domain ← Application ← {Infrastructure, Backends, Server} ← Cli)。アーキテクチャテスト (`tests/IviCli.Cli.Tests/Architecture/`) が PR ごとに違反を検知します。 +内部の層構成(Clean Architecture と一方向の依存方向、アーキテクチャテストで強制)は、コントリビュータ向けに [ADR 0003](adr/0003-architecture-style.md) と [ADR 0021](adr/0021-repository-layout.md) に記載しています。 ## ドキュメント -- [PRD](PRD.jp.md) — プロダクト要件 ([English](PRD.md)) +- [PRD](PRD.jp.md) — プロダクト要件 - [Architecture Decision Records](adr/) — Accepted な意思決定。読み始めの推奨: [ADR 0003](adr/0003-architecture-style.md) (アーキテクチャスタイル)、[ADR 0021](adr/0021-repository-layout.md) (層アセンブリ)、[ADR 0007](adr/0007-network-transport.md) (HiSLIP / SOCKET) - [Domain glossary](domain-glossary.md) — ユビキタス言語カタログ - [Guides](guides/) — タスク指向の how-to。まずは [Mock a VISA instrument](guides/mock-a-visa-instrument.md) -- [Samples](samples/) — そのまま投入できる scenario + セットアップスクリプト (例: [PSU mock VISA device](samples/psu/)) -- [Contributing](CONTRIBUTING.jp.md) — ローカル開発・ブランチ運用・hooks ([English](CONTRIBUTING.md)) +- [Samples](samples/) — ハードウェアなしでテストするための **モック計測器** 一式: そのまま投入できる scenario + セットアップスクリプト (例: [PSU モック](samples/psu/)) +- [Contributing](CONTRIBUTING.jp.md) — ローカル開発・ブランチ運用・hooks ## ソースからビルド diff --git a/docs/adr/0024-documentation-policy.md b/docs/adr/0024-documentation-policy.md index 3448891..6dd4543 100644 --- a/docs/adr/0024-documentation-policy.md +++ b/docs/adr/0024-documentation-policy.md @@ -75,6 +75,8 @@ and on the JP side: Both files share the same heading structure and section order so cross-reference is trivial. +**Navigation links point to the English canonical only.** When one document links to another (e.g. the README's documentation index linking to the PRD or CONTRIBUTING), it links the English file and does *not* append inline per-language variants such as `([日本語](...))`. Readers switch language via the target document's own top-of-file switcher. This keeps index lines from growing one entry longer per added language; the whole-document switcher header is the single place a language choice is offered. + ### 5. Domain glossary `docs/domain-glossary.md` is a living document: