Metadata-Version: 2.4
Name: skillnav
Version: 0.4.18
Summary: CLI client for the Skill management platform (SkillNavigator)
License: Apache-2.0
Keywords: skill,cli,agent,registry
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: typer>=0.16
Requires-Dist: click>=8.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.9; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"

# skillnav

Official CLI client for the Skill management platform (SkillNavigator).

Specification: `docs/cli-design.md` in the platform repository.

## Install

```bash
pip install skillnav -i https://mirrors.aliyun.com/pypi/simple/
# or from this repo:
pip install -e "cli-py[dev]"
```

## Usage

```bash
skillnav --version
skillnav config test                  # tests the active profile
# Create an API key in the Web UI (Account → API Keys), then:
skillnav login --api-key sk_...
skillnav search demo                  # anonymous
skillnav info demo-skill
skillnav install demo-skill --dir ~/skills/demo-skill   # --dir is required
skillnav publish examples/demo-skill --dry-run
skillnav download demo-skill -o /tmp/demo.zip
skillnav update              # upgrade to the latest release
skillnav update --check      # check only, do not install
```

Global flags: `--registry`, `--profile`, `--json`, `--no-input`.

`search` / `top` / `info` (and `status` / `report`) work without a key;
`install`, `download`, `publish`, `rate`, `issue`, `unpublish` and `republish`
need one.

`install` requires an explicit `--dir` — point it at the directory your agent
actually loads skills from. There is no implicit default, because agent clients
often run in temporary or sandboxed working directories.

Configuration: `~/.config/skillnav/config.json` (multi-profile; stores `apiKey` per profile). Adding a profile whose name already exists is refused — reuse it with `skillnav config use <name>` instead.

Environment: `SKILLNAV_REGISTRY`, `SKILLNAV_PROFILE`, `SKILLNAV_API_KEY` (legacy alias: `SKILLNAV_TOKEN`).

## Long-running publishes

`publish` returns as soon as the package is stored — inspection runs in the
background unless you ask otherwise. `publish --wait` (and
`retry-publish --wait`) keep the request open until the whole pipeline is
done; that pipeline waits on SkillSpector, VirusTotal and HaluCatch, and
VirusTotal queues newly uploaded files for minutes. Those calls therefore use
a **600s** request budget instead of the default 120s:

```bash
skillnav publish ./my-skill --wait
SKILLNAV_PUBLISH_WAIT_TIMEOUT=900 skillnav publish ./my-skill --wait
```

A timed-out request is reported as a **timeout**, never as "cannot reach the
API", and the hint points at `skillnav status <slug>` and
`skillnav retry-publish <slug>` — the server keeps working after the client
gives up, so re-uploading the same version is never the right fix.

VirusTotal defers by default: the upload ends that stage, the report is
collected by a background sweep (every 5 minutes, 45-minute fallback) and the
verdict is decided again once it lands. A version waiting for it shows
`inspectionStatus: inspecting` and stage `virustotal: processing` — that is
**normal waiting, not a failure**: do not `retry-publish` (it returns 409
`skill_inspection_in_progress`) and do not re-upload the version. The skill is
owner-only until the report lands.

## Skill lifecycle (unpublish / delete / republish)

Taking a skill out of public search is **not** a deletion — the package, its
inspection data and its version history all stay:

```bash
skillnav unpublish my-skill                   # remove from public search (y/N prompt)
skillnav --no-input unpublish my-skill        # agents / CI: skip the prompt
skillnav unpublish my-skill --version 1.0.0   # one version (never the latest)
skillnav unpublish my-skill --delete          # move to the recycle bin (3 days, then purged)
skillnav republish my-skill                   # put it back (visibility only)
```

`--delete` is the Web "delete" button: the skill is hidden and publishing under
that slug is blocked until it is restored from the recycle bin (or the 3-day
window expires). `republish` is the counterpart of `unpublish` and **cannot
bypass review** — the server refuses while an inspection is running, interrupted
or rejected, pointing at `retry-publish` or at shipping a new version.

An unpublished skill reports `Published: no (private)` in `skillnav status`.

## Upgrade and version check

Release lookups try **PyPI first** (`pypi.org/pypi/skillnav/json`) and fall
back to the **Aliyun simple index** when PyPI times out or fails. Explicit
`skillnav update` / `update --check` wait up to 10s per source; if both
fail, the error lists each source's failure.

On top of that, an interactive command performs a **daily best-effort check**
and prints a one-line hint to stderr when a newer release exists:

```
Update available: 0.4.12 -> 0.4.13 (run: skillnav update)
```

- The hint is **interactive-only** and plain ASCII (same wording as
  `update --check`): it is skipped for `--json` and whenever stderr is not a
  TTY — pipes, CI jobs and agent harnesses stay silent, so machine-read
  output is never polluted.

- The result is cached in `~/.config/skillnav/update-check.json`; the
  network is touched at most once per 24h (a failed lookup also backs off
  for 24h, so offline/air-gapped hosts wait at most once a day).
- **A given release is announced at most once, ever.** The hint is driven by
  a new release appearing, not by time: staying on an older version goes
  permanently silent for that version, and only a newer `latest`
  (0.4.13 → 0.5.0) announces again. So you are never nagged about the same
  version day after day.
- A missed hint is never fatal: `skillnav --version` prints the same hint to
  stderr (its stdout stays a single parseable version line), and
  `skillnav update` / `update --check` always perform a real lookup and show
  the result.
- The daily lookup uses a short timeout (default 3s,
  `SKILLNAV_UPDATE_CHECK_TIMEOUT` seconds to change).
- The hint goes to **stderr only** — `--json` output on stdout stays clean.
- Disable entirely with `SKILLNAV_UPDATE_CHECK=off`; editable installs
  (development checkouts) skip the check automatically.
- The check only notifies; upgrades stay explicit (`skillnav update`),
  which handles pip / pipx installs and refuses editable installs.
- The package version has a single source of truth:
  `skillnav/__init__.py` `__version__` (read by `pyproject.toml` via a
  dynamic attr), so the wheel and the CLI can never disagree.

## Test

Requires a running API at `http://127.0.0.1:3000` (`npm run dev:api`):

```bash
pip install -e "cli-py[dev]"
npm run skillnav:test
```

Unit tests only (no API):

```bash
pytest tests/skillnav -v --ignore=tests/skillnav/test_integration.py
```

## License

Apache-2.0
