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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All notable changes to vouch are documented here. Format follows
## [Unreleased]

### Added
- `vouch pending --json` emits pending proposals as structured JSON for shell
scripts, CI checks, and multi-agent review dashboards.
- `vouch diff <id-old> <id-new>` shows what changed between two claim revisions or two page revisions — field-level changes plus a line-diff of the long text/body. Auto-detects the artifact kind and hides always-churning metadata. Read-only; supports `--json`.
- Seed a cited starter source and claim during `vouch init`, print first-run
next steps, and document a 30-second onboarding tour (#54).
Expand Down
6 changes: 5 additions & 1 deletion src/vouch/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,14 @@ def doctor() -> None:


@cli.command()
def pending() -> None:
@click.option("--json", "as_json", is_flag=True, help="Emit JSON instead of text.")
def pending(as_json: bool) -> None:
"""List proposals awaiting review."""
store = _load_store()
pending = store.list_proposals(ProposalStatus.PENDING)
if as_json:
_emit_json([pr.model_dump(mode="json") for pr in pending])
return
if not pending:
click.echo("no pending proposals")
return
Expand Down
36 changes: 36 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import patch

Expand Down Expand Up @@ -83,6 +84,41 @@ def test_show_missing_proposal_shows_clean_error(store: KBStore) -> None:
_assert_clean_error(result, "proposal no-such-proposal")


def test_pending_json_empty_queue(store: KBStore) -> None:
result = CliRunner().invoke(cli, ["pending", "--json"])

assert result.exit_code == 0, result.output
assert json.loads(result.output) == []


def test_pending_json_lists_pending_proposals(store: KBStore) -> None:
src = store.put_source(b"e")
pr = propose_claim(store, text="pending json claim", evidence=[src.id], proposed_by="agent")

result = CliRunner().invoke(cli, ["pending", "--json"])

assert result.exit_code == 0, result.output
rows = json.loads(result.output)
assert len(rows) == 1
assert rows[0]["id"] == pr.id
assert rows[0]["kind"] == "claim"
assert rows[0]["proposed_by"] == "agent"
assert rows[0]["status"] == "pending"
assert rows[0]["payload"]["text"] == "pending json claim"


def test_pending_human_output_remains_text(store: KBStore) -> None:
src = store.put_source(b"e")
pr = propose_claim(store, text="pending text claim", evidence=[src.id], proposed_by="agent")

result = CliRunner().invoke(cli, ["pending"])

assert result.exit_code == 0, result.output
assert pr.id in result.output
assert "[claim] by agent" in result.output
assert "pending text claim" in result.output


def test_review_approves_pending_proposal(
store: KBStore, monkeypatch: pytest.MonkeyPatch
) -> None:
Expand Down
Loading