Metadata-Version: 2.4
Name: salpa-cli
Version: 0.2.1
Summary: Salpa node authoring CLI — scaffold and validate node packages that match the shipped template contract.
Project-URL: Homepage, https://bocores.com/salpa-cli
Project-URL: Documentation, https://salpa.app/docs/custom-nodes
Author: Salpa
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: cli,computational-science,node-authoring,salpa,scaffold,workflow
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Code Generators
Requires-Python: >=3.10
Requires-Dist: rich>=13
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Description-Content-Type: text/markdown

# salpa-cli

The Salpa node authoring CLI. Scaffolds node packages that match the shipped
template contract — the deterministic path to a new node — and checks them
against that contract before you install them.

```bash
python3 -m pip install salpa-cli
salpa new my-analyzer          # interactive
salpa new my-suite -t multi-node-package --yes
salpa validate my_suite        # will it install and register?
```

Installing adds the `salpa` command. If your shell can't find `salpa` afterward,
your Python scripts directory isn't on your `PATH` —
installing into a virtual environment is the simplest fix (it puts `salpa` on `PATH`).

`salpa new` creates `./<under_scored_name>/` from a bundled template, with every
placeholder substituted and the directory underscored (the dir name becomes the
Python package name, so a hyphen would break `from .core import ...`; meta.toml's
`name` stays kebab-case).

## Templates

Templates ship inside the wheel and are the single source of truth for the node
contract, so there is no second copy to drift.

| Template | For |
|----------|-----|
| `individual-node` | one node with its own pixi env (default) |
| `multi-node-package` | several related nodes sharing one pixi env, chained via `predecessor_data` |

## Options

```
salpa new [NAME]
  -t, --template     individual-node | multi-node-package
  -d, --description  one-line description
      --author       author name
      --category     UI category (e.g. "Cheminformatics")
  -o, --output       directory to create the package in (default: .)
  -y, --yes          non-interactive: accept defaults, no prompts
      --install      run `pixi install` in the new package afterwards
```

## Validating

`salpa validate [PATH]` checks a package against the contract the app enforces at
install and registration time. Every check maps to a real failure — a node missing
from `[package.nodes]`, a shared-environment name that drifted between three files,
a stray per-node `pixi.toml` that silently opts a node out of the shared env. It is
not a linter: style is not checked.

```
salpa validate [PATH]           # default: the current directory
      --strict                  # warnings become errors (CI)
      --ignore CODE             # suppress one check by code, repeatable
      --json                    # machine-readable report
      --no-import               # skip the import checks
      --python PATH             # override the auto-detected import-check interpreter
```

Exit codes: `0` clean · `1` at least one error · `2` the path is not a package.

Findings are `ERROR` (will not install or will not register) or `WARN` (installs,
but is probably not what you meant). Each carries a stable code (`E3`, `S2`, …) so
it can be quoted, grepped, and suppressed.

**Import checks.** `I1`-`I3` import your `node.py` in a subprocess to confirm the
app can read its `OPTIONS`. They need the authoring SDK (`bocoflow_core`), and the
interpreter that has it is found for you — your package already declares the SDK in
its own `pixi.toml`, so its solved `test` environment is the right one to judge the
package against:

```bash
pixi install -e test    # solve the test env — the one your pixi.toml puts the SDK in
salpa validate          # the import checks now run, no flags
```

The search order, first hit wins: `.pixi/envs/test` → `.pixi/envs/default` → the
interpreter running `salpa`. A candidate that cannot import `bocoflow_core` is
passed over, and the report names the one that answered. `pip install
bocoflow-core-sdk` beside `salpa` works too, and `--python PATH` overrides the
search entirely (a `--python` that lacks the SDK skips rather than falling back —
naming an interpreter is an instruction, not a hint).

With no interpreter at all, the checks are **skipped**, and both the status line and
the summary say so — `No findings (import checks skipped)` is a smaller claim than
`No findings. This package should install and register.`, and reads as one.

**Suppressing a check.** Some warnings describe a shape that is occasionally
correct — `E3` (a per-node `pixi.toml`) is a deliberate opt-out when a node's
dependencies conflict with its package's shared environment. `--ignore` lets such a
package pass `--strict` without silencing everything:

```bash
salpa validate --strict --ignore E3
```

Suppressed findings are still reported (and appear under `suppressed` in `--json`)
— they are hidden from the exit code, not from you.

`salpa new` runs a validation pass over its own output and prints a one-line
summary. That pass covers structure, naming and environment only; the import
checks are left to `salpa validate`.

## Authoring guide

`salpa docs` prints the bundled node-authoring guide. Full documentation:
https://salpa.app/docs/custom-nodes

## Reserved

`salpa publish` / `install` / `run` are reserved for later and not implemented
yet. The current surface is `salpa new`, `salpa validate` and `salpa docs`.
