Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 35 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <resource>` 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**
Expand All @@ -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=<scenario>` 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=<name>` — 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=<path>`) or a SCPI script run (`mock scenario record --from-script foo.scpi`) into a scenario, then re-run it deterministically with `IVICLI_REPLAY=<scenario>` — 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=<path>` 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.
Expand Down Expand Up @@ -135,32 +135,48 @@ ivicli completion powershell | Out-String | Invoke-Expression

Once installed, `<Tab>` 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<br/>(composition root)"] --> App["IviCli.Application<br/>(handlers, ports)"]
Cli --> Server["IviCli.Server<br/>(HiSLIP / SOCKET gateways)"]
Server --> App
Cli --> Infra["IviCli.Infrastructure<br/>(TomlConfigStore, FilePidRegistry)"]
Infra --> App
Cli --> Backends["IviCli.Backends.*<br/>(Fake / Local / HiSlip / Vxi11 / Socket / Replay)"]
Backends --> App
App --> Domain["IviCli.Domain<br/>(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

Expand Down
54 changes: 35 additions & 19 deletions docs/README.jp.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
## ハイライト

- **状態保持型・VISA ネイティブな CLI**
- **状態保持型 UX.** `ivicli visa add psu1 ...` で alias を一度登録すれば、以降は `psu1` だけで操作できます
- **シェルのカレントディレクトリのような「現在の機器」.** `ivicli visa add psu1 <resource>` で alias を一度登録し、`ivicli visa use psu1` で *現在の機器* に設定すれば、以降の `visa query` / `write` / `script` は対象指定が一切不要です(VISA リソースはもちろん alias すら書かなくてよい)
- **VISA 互換.** 標準的な `TCPIP::` / `USB::` / `GPIB::` のリソース文字列を独自構文なしで扱います。
- **自動化指向.** stdout はデータ (`--json` 含む)、stderr はログ専用。終了コードは POSIX 慣習に従い、bash / zsh / PowerShell の補完をサポートします。
- **発見と可視化**
Expand All @@ -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=<scenario>` で同じスクリプトをハードウェアなしに決定論的に再実行できます
- **一度録って何度でも再生.** `IVICLI_CAPTURE` で実機セッションを取り、`mock scenario import` で scenario に変換、以後 `IVICLI_REPLAY=<name>` で同じ動作をハードウェア占有なしに再現できます
- **スクリプト Lint.** `visa lint foo.scpi` IEEE 488.2 / SCPI core の語彙に対する未知のルートを計測器に触らずに検出します
- **モック計測器を動かす.** `Fake` backend は *scenario*(`query → response` ルールの集合)に従って SCPI に応答するので、`ivicli`(または自作の VISA アプリ)を実機なしのスタンドインと対話させられます
- **録って再生.** 実機セッション(`IVICLI_CAPTURE=<path>`)または SCPI スクリプト実行(`mock scenario record --from-script foo.scpi`)を scenario に録り、`IVICLI_REPLAY=<scenario>` で決定論的に再実行できます — 回帰チェックに実機を消費しません
- **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=<path>` を設定するとすべての 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 取得できます。
Expand Down Expand Up @@ -135,32 +135,48 @@ ivicli completion powershell | Out-String | Invoke-Expression

導入後、`<Tab>` でサブコマンド・オプション・実行時識別子(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<br/>(composition root)"] --> App["IviCli.Application<br/>(handlers, ports)"]
Cli --> Server["IviCli.Server<br/>(HiSLIP / SOCKET gateways)"]
Server --> App
Cli --> Infra["IviCli.Infrastructure<br/>(TomlConfigStore, FilePidRegistry)"]
Infra --> App
Cli --> Backends["IviCli.Backends.*<br/>(Fake / Local / HiSlip / Vxi11 / Socket / Replay)"]
Backends --> App
App --> Domain["IviCli.Domain<br/>(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

## ソースからビルド

Expand Down
2 changes: 2 additions & 0 deletions docs/adr/0024-documentation-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down