Metadata-Version: 2.4
Name: agent-publish
Version: 0.1.0
Summary: One-shot multi-registry release publisher for OSS packages (Python port of @p-vbordei/agent-publish)
Project-URL: Homepage, https://github.com/p-vbordei/agent-publish-py
Project-URL: Reference, https://github.com/p-vbordei/agent-publish
Author-email: Vlad Bordei <bordeivlad@gmail.com>
License: Apache-2.0
License-File: LICENSE
Keywords: agent,github-release,jcs,npm,publish,release
Classifier: License :: OSI Approved :: Apache Software License
Requires-Python: >=3.10
Requires-Dist: jcs>=0.2.1
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# agent-publish (Python)

[![CI](https://github.com/p-vbordei/agent-publish-py/actions/workflows/ci.yml/badge.svg)](https://github.com/p-vbordei/agent-publish-py/actions/workflows/ci.yml)
[![Spec](https://img.shields.io/badge/spec-v0.1-blue)](./SPEC.md)
[![License](https://img.shields.io/badge/license-Apache%202.0-green)](./LICENSE)

> **Idiomatic Python port of [`@p-vbordei/agent-publish`](https://github.com/p-vbordei/agent-publish) (npm v0.1.2).** One-shot multi-registry release publisher for OSS packages. Reads a strict `publish.yaml`, runs prechecks (clean tree, tag exists, version match), invokes `npm publish` and `gh release create`, and emits a canonical (RFC 8785 JCS) JSON release manifest.

## What's in the box

- `load_publish_config(path)` — strict YAML schema for `publish.yaml`
- `precheck(cwd, version, *, from_tag=None)` — clean tree, tag exists, version match
- `build_manifest(...)` + `canonical_manifest_bytes(...)` — JCS-canonical release manifest
- `npm_publish(...)` / `github_release(...)` — registry adapters
- CLI: `agent-publish manifest | publish [--dry-run] [--from-tag vX.Y.Z]`
- `SpawnFn` callable injection — tests stub `npm` / `gh` without real network

## Install

```bash
pip install agent-publish
```

(Python 3.10+.)

## Quickstart

```bash
# In a tagged repo with package.json + CHANGELOG.md + publish.yaml:
agent-publish manifest               # preview the JSON release manifest
agent-publish publish --dry-run      # full flow, no network writes
agent-publish publish                # real: npm + GH release + manifest
```

### Library example

The runnable version is [`examples/quickstart.py`](./examples/quickstart.py). It
builds a manifest in memory, stubs `npm` via `SpawnFn` so nothing hits the
network, and prints the canonical JCS bytes:

```bash
$ python examples/quickstart.py
{"registries":[{"name":"npm","package":"agent-id","provenance":true,"sha256":"sha512-Ki1ScEwgQ8K0bV2W9k7CWnHFq2x8K3T8sZ3X7K0Ld5g=","url":"https://www.npmjs.com/package/agent-id/v/0.1.0","version":"0.1.0"}],"repo":"p-vbordei/agent-id","schema":"agent-publish/release-manifest/v1","tagged_at":"2025-01-01T00:00:00.000Z","version":"0.1.0"}
```

Keys are RFC 8785-sorted, no whitespace — byte-identical to the TS and Rust
ports on the same input.

## How it relates

| Repo | Language | Status |
|---|---|---|
| [`agent-publish`](https://github.com/p-vbordei/agent-publish) | TypeScript / Bun (reference) | `@p-vbordei/agent-publish` v0.1.2 |
| [`agent-publish-py`](https://github.com/p-vbordei/agent-publish-py) | Python (this repo) | v0.1.0 |
| [`agent-publish-rs`](https://github.com/p-vbordei/agent-publish-rs) | Rust | v0.1.0 |

All three pass the same C1–C5 conformance clauses on the same fixtures.

## Conformance

```bash
uv sync --extra dev
uv run pytest -v
```

- **C1** — manifest JCS bytes are deterministic and byte-identical across ports.
- **C2** — `publish --dry-run` performs zero network writes (verified via stubbed `SpawnFn`).
- **C3** — partial registry failure still emits a manifest with successful results recorded; exit code 3.
- **C4** — manifest matches the v1 schema (`schema`, `version`, `repo`, `tagged_at`, `registries[]`).
- **C5** — `publish.yaml` rejects unknown keys, missing required fields, and invalid types.

Plus S1–S5 security checks (token leakage, command injection, `.npmrc` permissions, env scrubbing, dirty-tree guard) embedded in `tests/security/`.

## Architecture

See [`docs/architecture.md`](docs/architecture.md) for the module map, dependency choices, and the `SpawnFn` injection pattern.

## Development

```bash
git clone https://github.com/p-vbordei/agent-publish-py
cd agent-publish-py
uv sync --extra dev
uv run pytest
uv run python examples/quickstart.py
```

See [`CONTRIBUTING.md`](CONTRIBUTING.md) and [`CHANGELOG.md`](CHANGELOG.md).

## License

Apache-2.0 — see [LICENSE](LICENSE).
