tuicr 0.21.0

Review AI-generated diffs like a GitHub pull request, right from your terminal.
Documentation
# Review Session CLI

`tuicr review` exposes persisted review sessions without opening the TUI. It is
intended for scripts and coding agents that need to inspect or update tuicr's
saved review state.

Interactive TUI sessions create a persisted session file as soon as a review
target becomes active, so agents can resolve the announced slug immediately.
If that auto-created file still has no comments and no reviewed files when the
TUI exits, tuicr removes it.

While a TUI is open, tuicr records the active session in
`active_sessions.json` beside the storage manifest with the process id, slug,
session path, and last-seen timestamp. `tuicr review list` also includes an
`active` boolean so agents can select the live session without guessing from
timestamps.

Session arguments accept any of:

- a local slug from `tuicr review list`
- a PR slug, e.g. `gh:slatedb/slatedb/pr/1745` (PR slugs resolve without `--repo`)
- an absolute or relative path to a session JSON file (anything ending in
  `.json` or that exists on disk is treated as a direct path)

## Commands

```bash
tuicr review list --repo .                            # checkout + its repo's PR sessions
tuicr review list --repo slatedb/slatedb              # all sessions for a forge repo
tuicr review list --all                               # every session across all repos
tuicr review comments --session agavra/tuicr@main/worktree
tuicr review comments --session gh:slatedb/slatedb/pr/1745
```

All `tuicr review` commands emit JSON by default. Timestamps are RFC3339 strings
so callers can parse them without locale-specific handling.

## The `--repo` selector

`--repo` is a repo selector, not just a path. It accepts:

- a checkout path (default `.`) — matches that checkout's local sessions and,
  via its `origin` remote, any PR sessions for the same repo
- a forge coordinate: `owner/repo`, `host/owner/repo`, `forge:host/owner/repo`,
  or a repo / PR URL — matches local and PR sessions by `owner/repo`

This is how PR sessions become discoverable. PR review sessions are keyed by
forge coordinates rather than a local checkout, so naming the repo — either by
standing in its checkout or passing `--repo slatedb/slatedb` — surfaces them.
`list` emits a usable slug for each; pass a PR slug to `--session` to read or
annotate it (no `--repo` needed, since PR slugs are self-contained).

```bash
# from anywhere:
tuicr review list --repo slatedb/slatedb
#   -> [ ..., { "slug": "gh:slatedb/slatedb/pr/1745", "kind": "pr", ... } ]
tuicr review comments --session gh:slatedb/slatedb/pr/1745
```

`--repo` for `add` / `comments` is only consulted when resolving a *local*
slug; PR slugs and JSON paths ignore it.

## Add Comments

Use flags for quick manual comments:

```bash
tuicr review add --session agavra/tuicr@main/worktree \
  --target-file src/main.rs \
  --line 42 \
  --side new \
  --type issue \
  "Handle the empty case here."
```

Target flags:

- omit `--target-file` for a review-level comment
- pass `--target-file <path>` for a file-level comment
- add `--line <n>` for a line comment
- add `--end-line <n>` for a range comment
- use `--side old|new` for inline comments

## JSON Input

For machine input, pass a JSON payload with `--input`. The value can be literal
JSON, `@path/to/payload.json`, or `-` to read stdin.

```bash
tuicr review add --session agavra/tuicr@main/worktree --input - <<'JSON'
{
  "type": "issue",
  "content": "Handle the empty case here.",
  "file": "src/main.rs",
  "line": 42,
  "side": "new"
}
JSON
```

Flat JSON fields:

- `content`: required comment text
- `type` or `comment_type`: comment classification, defaults to `none` (untyped, no `[TYPE]` tag)
- `file`: file path; omit for a review-level comment
- `line`: line number for a line comment
- `start_line` and `end_line`: range bounds
- `side`: `old` or `new`, defaults to `new`

Nested targets are also accepted:

```json
{
  "comment_type": "suggestion",
  "content": "This range can be simplified.",
  "target": {
    "type": "line_range",
    "file": "src/main.rs",
    "start_line": 10,
    "end_line": 14,
    "side": "old"
  }
}
```

Target types:

- `review`
- `file`
- `line`
- `line_range` or `range`

## Output

`list` returns a JSON array:

```json
[
  {
    "slug": "agavra/tuicr@main/worktree",
    "kind": "local",
    "path": "/Users/alice/Library/Application Support/tuicr/reviews/sessions/9f6c1b3e09a54e2a.json",
    "updated_at": "2026-05-22T17:20:00Z",
    "comment_count": 1,
    "reviewed_count": 0,
    "file_count": 3,
    "anchor": "main",
    "active": true
  }
]
```

With `--all`, PR sessions appear alongside local ones with `"kind": "pr"` and a
PR slug:

```json
[
  {
    "slug": "gh:slatedb/slatedb/pr/1745",
    "kind": "pr",
    "path": "/Users/alice/Library/Application Support/tuicr/reviews/sessions/172e168db0d525e5.json",
    "updated_at": "2026-05-22T17:20:00Z",
    "comment_count": 0,
    "reviewed_count": 0,
    "file_count": 12,
    "anchor": "pr/1745",
    "active": false
  }
]
```

`comments` returns a JSON array:

```json
[
  {
    "id": "79c9b3e1-0a7a-4efe-9d43-f7085d7c1a82",
    "location": "src/main.rs:42",
    "path": "src/main.rs",
    "start_line": 42,
    "end_line": 42,
    "side": "new",
    "comment_type": "issue",
    "lifecycle_state": "local_draft",
    "created_at": "2026-05-22T17:20:00Z",
    "content": "Handle the empty case here."
  }
]
```