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
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ Cross-package release notes for relayburn. Package changelogs contain package-le

## [Unreleased]

- `relayburn-cli` (Rust): wire `burn summary` and `burn hotspots` as thin presenters over `relayburn-sdk`, matching the TS CLI's flag set and stdout byte-for-byte (default + `--json`). Un-ignores the four matching golden invocations. (#248 D1)
- `relayburn-cli` (Rust): port `burn overhead` and `burn overhead trim` as thin presenters over `relayburn_sdk::overhead` / `::overhead_trim`. Output (human + `--json`) is byte-equivalent with the TS CLI. (#248 D2)
- `relayburn-cli` (Rust): wire `burn compare` as a presenter over `relayburn_sdk::analyze::compare` building blocks (`build_compare_table` + the per-turn fidelity gate), matching the TS CLI flag set (positional comma-separated model list, `--include-partial` / `--fidelity` / `--since` / `--project` / `--session` / `--min-sample` / `--csv` / `--no-archive`) and producing byte-equivalent stdout for the cli-golden `compare` / `compare-json` invocations. (#248 D3)
- `relayburn-cli` (Rust): port `burn overhead` and `burn overhead trim` as thin presenters over `relayburn_sdk::overhead` / `::overhead_trim`. Output (human + `--json`) is byte-equivalent with the TS CLI. (#248 D2)
- `relayburn-cli` (Rust): wire `burn state` as a typed clap subcommand with `status` (default), `rebuild`, `prune`, and `reset` verbs over `relayburn-sdk`. `state status` reports per-table row counts in `burn.sqlite`, the row count in `content.sqlite`, the `archive_state` schema/last-built/last-rebuild fields, and the resolved retention config; `--json` emits the structured `StateStatus` payload. `state rebuild {index,content,archive,all}` drives `Ledger::rebuild_derivable`; `state prune` drives `Ledger::prune_content_older_than`. `state reset` and standalone `state rebuild classify` are stubbed pending a follow-up. (#248 D4)
- `relayburn-cli` (Rust): wire `burn summary` and `burn hotspots` as thin presenters over `relayburn-sdk`, matching the TS CLI's flag set and stdout byte-for-byte (default + `--json`). Un-ignores the four matching golden invocations. (#248 D1)
- `relayburn-sdk-node` (Rust): napi-rs bindings skeleton — `#[napi]` shims for every public verb in `relayburn-sdk` (`summary`, `sessionCost`, `overhead`, `overheadTrim`, `hotspots`, `search`, `exportLedger`, `exportStamps`, async `ingest`, plus `ledgerOpen`), with u64 token counts surfaced as JS `BigInt`, ISO-8601 timestamps as `String`, async verbs returning `Promise<T>`, and a typed `BurnError` mapping for SDK failures. (#247)
- `relayburn-cli` (Rust): introduce the harness substrate — `HarnessAdapter` trait, lazy compile-time `phf` registry (`lookup` / `list_harness_names`), and the shared `pending_stamp::adapter` factory codex + opencode will reuse. Adapter slots in the registry are reserved but empty pending the Wave 2 PRs (#248-d/e/f). `relayburn-sdk` re-exports `start_watch_loop`, `WatchController`, `write_pending_stamp`, `PendingStampHarness`, and friends so the CLI doesn't have to reach into private SDK modules. (#248)
- `relayburn-cli` (Rust): scaffold the clap v4 derive root with global `--json` / `--ledger-path` / `--no-color` flags, eight stub subcommands (`summary`, `hotspots`, `overhead`, `compare`, `run`, `state`, `ingest`, `mcp-server`), and shared `render::{table,json,error}` helpers. Stubs exit `1` with a `not yet implemented` message (or a `{"error": …}` envelope under `--json`); Wave 2 fan-out PRs replace each stub with a thin presenter over `relayburn-sdk`. (#248 part a)
Expand Down
141 changes: 140 additions & 1 deletion crates/relayburn-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub enum Command {
Run,

/// Inspect or rebuild derived state under `~/.relayburn`.
State,
State(StateArgs),

/// Scan harness session stores and append new turns to the ledger.
Ingest,
Expand Down Expand Up @@ -250,3 +250,142 @@ pub struct OverheadTrimArgs {
#[arg(long, value_name = "N")]
pub top: Option<u64>,
}

// ---------------------------------------------------------------------------
// `burn state` — typed args + nested subcommand
// ---------------------------------------------------------------------------

/// `burn state [...]` — derived-state inspection / maintenance verbs.
/// Mirrors the TS surface in `packages/cli/src/commands/state.ts`:
///
/// - `burn state status` (default when no subcommand): print the row /
/// file / archive_state report.
/// - `burn state rebuild <target>`: rebuild derivable tables from
/// upstream session files.
/// - `burn state prune`: TTL-based content sidecar prune.
/// - `burn state reset`: wipe derived state and (optionally) re-ingest.
#[derive(Debug, Clone, ClapArgs)]
pub struct StateArgs {
#[command(subcommand)]
pub command: Option<StateSubcommand>,
}

/// Nested subcommand for `burn state`. `None` (no positional) is treated
/// as `Status` to match the TS default.
#[derive(Debug, Clone, Subcommand)]
pub enum StateSubcommand {
/// Print derived-artifact status: file paths, sizes, row counts,
/// archive-state metadata, resolved retention config.
Status(StateStatusArgs),

/// Rebuild derived ledger artifacts from upstream session files.
Rebuild(StateRebuildArgs),

/// Prune expired content sidecars below the TTL window.
Prune(StatePruneArgs),

/// Wipe derived state under `$RELAYBURN_HOME` (and optionally
/// re-ingest from upstream session logs).
Reset(StateResetArgs),
}

/// `burn state status` — flags. `--json` is global and lives on
/// [`Args::json`]; nothing local today, but keep an args struct so
/// future flags (`--minimal`, `--quiet`) land without churning the
/// dispatch sig.
#[derive(Debug, Clone, ClapArgs, Default)]
pub struct StateStatusArgs {}

/// `burn state rebuild` — target + flags. Mirrors the TS surface:
/// `index | classify | content | archive [--full|--vacuum] | all`.
#[derive(Debug, Clone, ClapArgs)]
pub struct StateRebuildArgs {
#[command(subcommand)]
pub target: StateRebuildTarget,
}

#[derive(Debug, Clone, Subcommand)]
pub enum StateRebuildTarget {
/// Rebuild the derivable tables from upstream session logs.
/// In the 2.0 SQLite layout there is one rebuild path
/// (`rebuild_derivable`) which drops + replays every derivable
/// table. The TS subtargets (index / classify / content / archive)
/// existed because each artifact lived in a separate file; in 2.0
/// they collapse onto the same SQL transaction.
Index,
/// Re-run activity classification on existing turns. Today this
/// is a no-op stub — the Rust ingest classifier writes the
/// `activity` field at append time (#274). A standalone reclassify
/// pass is filed for follow-up.
Classify(StateRebuildClassifyArgs),
/// Re-derive content rows from source session files.
Content,
/// Apply / rebuild the archive_state metadata.
Archive(StateRebuildArchiveArgs),
/// Run content + index + classify + archive in one pass.
All(StateRebuildAllArgs),
}

#[derive(Debug, Clone, ClapArgs, Default)]
pub struct StateRebuildClassifyArgs {
/// Force reclassification of every turn even when `activity` is
/// already populated.
#[arg(long)]
pub force: bool,
}

#[derive(Debug, Clone, ClapArgs, Default)]
pub struct StateRebuildArchiveArgs {
/// Legacy positional from the TS CLI: `burn state rebuild archive
/// vacuum`. Equivalent to `--vacuum`; kept so existing scripts that
/// target the 1.x surface keep parsing.
#[arg(value_name = "ACTION")]
pub action: Option<ArchiveAction>,
/// Drop archive state and rebuild from zero.
#[arg(long)]
pub full: bool,
/// Reclaim unused SQLite pages after the apply.
#[arg(long)]
pub vacuum: bool,
Comment on lines +345 to +349
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve archive vacuum positional compatibility

The typed clap shape for state rebuild archive only accepts --vacuum/--full flags, so burn state rebuild archive vacuum is now rejected as an extra argument. The TypeScript command still accepts archive vacuum as a positional action (runArchiveTarget), so this breaks existing scripts/automation that use that invocation style.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 99ecb8f. Added a typed ArchiveAction ValueEnum and an Option<ArchiveAction> positional on StateRebuildArchiveArgs, so burn state rebuild archive vacuum now parses cleanly. Verified burn state rebuild archive bogus still rejects with [possible values: vacuum]. The dispatch is unchanged: both the positional and --vacuum flag route through rebuild_derivable because 2.0 collapses archive.sqlite into burn.sqlite — kept the surface so 1.x automation doesn't break, with a doc comment explaining the no-op equivalence.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

/// Legacy positional action for `burn state rebuild archive`. Today
/// `vacuum` is the only accepted value; both the positional and
/// `--vacuum` flag route through the same `rebuild_derivable` path
/// in 2.0 (there's no separate `archive.sqlite` to vacuum), but the
/// surface stays so 1.x automation doesn't error out.
#[derive(Debug, Clone, Copy, ValueEnum)]
#[value(rename_all = "lower")]
pub enum ArchiveAction {
Vacuum,
}

#[derive(Debug, Clone, ClapArgs, Default)]
pub struct StateRebuildAllArgs {
/// Forwarded to `rebuild classify --force` when bundling.
#[arg(long)]
pub force: bool,
}

#[derive(Debug, Clone, ClapArgs, Default)]
pub struct StatePruneArgs {
/// Override the configured retention window. Accepts a number
/// (days) or the literal `forever`.
#[arg(long)]
pub days: Option<String>,
/// Delete sidecars even when the source session file still exists.
#[arg(long)]
pub force: bool,
}

#[derive(Debug, Clone, ClapArgs, Default)]
pub struct StateResetArgs {
/// Actually delete. Without this flag, reset is a dry-run.
#[arg(long)]
pub force: bool,
/// After a successful `--force` wipe, re-parse all source harness
/// logs from offset 0. Only meaningful with `--force`; clap rejects
/// `--reingest` on its own so a typo can't silently no-op.
#[arg(long, requires = "force")]
pub reingest: bool,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Loading
Loading