Add Phase 4 m2pack CLI + MCP wrapping. New top-level 'metin-release
m2pack' command group with build, verify, diff, and export-runtime-key
subcommands that shell out to the real m2pack-secure binary (resolved
via M2PACK_BINARY env or PATH). Each wrapper translates m2pack's own
JSON envelope into the canonical Result shape, keeping the raw m2pack
output under data.m2pack for callers that need the untranslated version.
The MCP server exposes the same four as m2pack_* tools via the existing
ToolSpec catalogue; all 12 tools (8 release_* + 4 m2pack_*) appear in
--list-tools and pass the parametrised schema mirror test.
93 tests green (71 -> 93), no new dependencies.
Add a Phase 4 'm2pack commands' section to docs/cli.md with each
subcommand's flags and a pointer at the m2pack-secure repo for
installation. Update README.md with a short m2pack paragraph and
append the Phase 4 entry to the Unreleased CHANGELOG section.
Add discovery-helper tests (env var override, PATH fallback, missing
binary) and command tests that point M2PACK_BINARY at a Python stub
script echoing canned JSON per subcommand. Cover success paths,
non-zero exit, non-JSON output, JSON-array output, and missing binary.
Extend the MCP schema mirror test to cover all 12 tools and add
dispatch tests for the new m2pack_* argv translation.
diff promotes m2pack's added/removed/changed/unchanged counts into
data.stats when m2pack reports them as lists or ints. export-runtime-key
follows the real binary's --key/--public-key/--output/--key-id/--format
surface (not the original plan's --pack/--master-key).
Shell out to m2pack-secure with --json, parse its envelope, and
translate into the standard metin-release Result envelope under
data.m2pack. Non-zero exit and non-JSON output map to SubprocessError
with m2pack_failed / m2pack_invalid_json / m2pack_empty_output codes.
Add Phase 3 metin-release-mcp — a thin MCP stdio server wrapping the
Phase 1 CLI as 8 release_* tools. Zero business logic: every tool
spawns metin-release --json, parses stdout, returns the envelope
verbatim. Tool schemas mirror the argparse signatures and are covered
by a parametrised test so drift fails loudly. Keeps existing Phase 1
code untouched.
Seed CHANGELOG.md in Keep a Changelog format, document every Phase 1
subcommand plus the --json flag placement fix as the initial 0.1.0
entry. Future minors and patches add sections above this one.
Before this change, only the top-level parser defined --json, -v and -q.
Argparse processes arguments left-to-right and hands off to the subparser
after seeing the subcommand name, so the idiomatic
metin-release release inspect --source X --json
failed with 'unrecognized arguments: --json'. Users had to write
metin-release --json release inspect --source X
which is the opposite of what every modern CLI does. Attach a shared
--json/-v/-q flag set to every subparser via a small helper. Same dest
means the last occurrence on the command line wins, which is the intuitive
behaviour. Both placements are now accepted; tests unchanged.
Pytest suite with a tiny_client fixture, an ephemeral Ed25519 keypair
fixture, and a threaded HTTPServer helper. Exercises cli dispatch,
inspect (including excluded-path handling), build-manifest and sign
against the real m2dev-client scripts, diff-remote via a local server,
and the full release publish composite against a local rsync target.