Skip to content

Commit f5d3069

Browse files
committed
add pagination key mode
1 parent 3d213a3 commit f5d3069

3 files changed

Lines changed: 93 additions & 36 deletions

File tree

README.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -222,30 +222,32 @@ bt eval foo.eval.ts -- --description "Prod" --shard=1/4
222222
- Detail view: `t` span/thread, `Left/Right` switch panes, `Backspace`/`Esc` back
223223
- Global: `q` quit
224224

225-
## `bt util xact`
225+
## `bt util version`
226226

227-
Local transaction-id conversion helpers:
227+
Local version and pagination-key conversion helpers:
228228

229229
- Convert transaction id to pretty version id:
230-
- `bt util xact to-pretty 1000192656880881099`
230+
- `bt util version to-pretty 1000192656880881099`
231231
- Convert pretty version id to transaction id:
232-
- `bt util xact from-pretty 81cd05ee665fdfb3`
232+
- `bt util version from-pretty 81cd05ee665fdfb3`
233233
- Convert transaction id, pretty version id, or pagination key to timestamp (local timezone by default):
234-
- `bt util xact to-time 1000192656880881099`
235-
- `bt util xact to-time 81cd05ee665fdfb3`
236-
- `bt util xact to-time p07639577379371417602`
237-
- `bt util xact to-time p07639577379371417602 --utc`
238-
- `bt util xact to-time 1000192656880881099 --format unix`
234+
- `bt util version to-time 1000192656880881099`
235+
- `bt util version to-time 81cd05ee665fdfb3`
236+
- `bt util version to-time p07639577379371417602`
237+
- `bt util version to-time p07639577379371417602 --utc`
238+
- `bt util version to-time 1000192656880881099 --format unix`
239239
- Convert timestamp to transaction id:
240-
- `bt util xact from-time` (defaults to current time)
241-
- `bt util xact from-time 2025-01-01` (date-only ISO at UTC midnight)
242-
- `bt util xact from-time 2024-03-14T18:00:00Z`
243-
- `bt util xact from-time 1710439200 --input unix --counter 42`
244-
- Inspect any xact value:
245-
- `bt util xact inspect 1000192656880881099`
246-
- `bt util xact inspect 81cd05ee665fdfb3`
247-
- `bt util xact inspect p07639577379371417602`
248-
- `bt util xact inspect p07639577379371417602 --utc`
240+
- `bt util version from-time` (defaults to current time)
241+
- `bt util version from-time 2025-01-01` (date-only ISO at UTC midnight)
242+
- `bt util version from-time 2024-03-14T18:00:00Z`
243+
- `bt util version from-time 1710439200 --input unix --counter 42`
244+
- Convert timestamp to pagination key:
245+
- `bt util version from-time 2026-05-14T08:00:09-07:00 --pagination-key`
246+
- Inspect any version-like value:
247+
- `bt util version inspect 1000192656880881099`
248+
- `bt util version inspect 81cd05ee665fdfb3`
249+
- `bt util version inspect p07639577379371417602`
250+
- `bt util version inspect p07639577379371417602 --utc`
249251

250252
## `bt auth`
251253

src/util_cmd.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ pub struct UtilArgs {
1818

1919
#[derive(Debug, Clone, Subcommand)]
2020
enum UtilCommands {
21-
/// Transaction-id conversion utilities
21+
/// Version and pagination-key conversion utilities
22+
#[command(name = "version")]
2223
Xact(XactArgs),
2324
}
2425

@@ -36,7 +37,7 @@ enum XactCommands {
3637
FromPretty(FromPrettyArgs),
3738
/// Convert a transaction id to a timestamp
3839
ToTime(ToTimeArgs),
39-
/// Convert a timestamp to a transaction id
40+
/// Convert a timestamp to a transaction id or pagination key
4041
FromTime(FromTimeArgs),
4142
/// Decode and display transaction id details
4243
Inspect(InspectArgs),
@@ -91,6 +92,10 @@ struct FromTimeArgs {
9192
/// Low 16-bit transaction counter value
9293
#[arg(long, default_value_t = 0)]
9394
counter: u16,
95+
96+
/// Output a pagination key instead of a transaction id
97+
#[arg(long)]
98+
pagination_key: bool,
9499
}
95100

96101
#[derive(Debug, Clone, Copy, ValueEnum, Eq, PartialEq)]
@@ -212,21 +217,32 @@ fn run_from_time(json: bool, args: FromTimeArgs) -> Result<()> {
212217
let unix_seconds = parse_timestamp_or_now(args.timestamp.as_deref(), args.input)?;
213218
let xact = build_xact_id(unix_seconds, args.counter);
214219
let pretty = prettify_xact(xact);
220+
let pagination_key = build_pagination_key(unix_seconds, args.counter, 0);
221+
let output_kind = if args.pagination_key {
222+
"pagination_key"
223+
} else {
224+
"xact_id"
225+
};
215226
if json {
216-
println!(
217-
"{}",
218-
serde_json::to_string(&serde_json::json!({
219-
"input_timestamp": args.timestamp,
220-
"input_format": match args.input {
221-
TimeInputFormat::Iso => "iso",
222-
TimeInputFormat::Unix => "unix",
223-
},
224-
"unix_seconds": unix_seconds,
225-
"counter": args.counter,
226-
"xact_id": xact.to_string(),
227-
"pretty_version": pretty,
228-
}))?
229-
);
227+
let mut payload = serde_json::json!({
228+
"output_kind": output_kind,
229+
"input_timestamp": args.timestamp,
230+
"input_format": match args.input {
231+
TimeInputFormat::Iso => "iso",
232+
TimeInputFormat::Unix => "unix",
233+
},
234+
"unix_seconds": unix_seconds,
235+
"counter": args.counter,
236+
"xact_id": xact.to_string(),
237+
"pretty_version": pretty,
238+
});
239+
if args.pagination_key {
240+
payload["pagination_key"] = serde_json::json!(format_pagination_key(pagination_key));
241+
payload["pagination_row_num"] = serde_json::json!(0);
242+
}
243+
println!("{}", serde_json::to_string(&payload)?);
244+
} else if args.pagination_key {
245+
println!("{}", format_pagination_key(pagination_key));
230246
} else {
231247
println!("{xact}");
232248
}
@@ -401,6 +417,10 @@ fn build_xact_id(unix_seconds: u64, counter: u16) -> u64 {
401417
TOP_BITS | ((unix_seconds & 0xffff_ffff_ffff) << 16) | u64::from(counter)
402418
}
403419

420+
fn build_pagination_key(unix_seconds: u64, counter: u16, row_num: u16) -> u64 {
421+
((unix_seconds & 0xffff_ffff) << 32) | (u64::from(counter) << 16) | u64::from(row_num)
422+
}
423+
404424
fn format_pagination_key(pagination_key: u64) -> String {
405425
format!("p{pagination_key:020}")
406426
}
@@ -507,6 +527,20 @@ mod tests {
507527
assert_eq!(xact_counter(xact), counter);
508528
}
509529

530+
#[test]
531+
fn from_time_to_pagination_key_uses_xact_counter() {
532+
let unix_seconds = 1_778_727_718u64;
533+
let counter = 31_627u16;
534+
let pagination_key = build_pagination_key(unix_seconds, counter, 0);
535+
assert_eq!(
536+
format_pagination_key(pagination_key),
537+
"p07639577379371417600"
538+
);
539+
assert_eq!(pagination_key_to_unix_seconds(pagination_key), unix_seconds);
540+
assert_eq!(pagination_key_xact_counter(pagination_key), counter);
541+
assert_eq!(pagination_key_row_num(pagination_key), 0);
542+
}
543+
510544
#[test]
511545
fn load_pretty_passthrough_for_non_pretty_input() {
512546
assert_eq!(load_pretty_xact("123").unwrap(), "123");

tests/cli.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,35 @@ fn setup_instrument_accepts_deprecated_agents_alias() {
122122
}
123123

124124
#[test]
125-
fn util_xact_to_time_accepts_pagination_key_with_utc() {
125+
fn util_version_to_time_accepts_pagination_key_with_utc() {
126126
bt_command()
127-
.args(["util", "xact", "to-time", "p07639577379371417602", "--utc"])
127+
.args([
128+
"util",
129+
"version",
130+
"to-time",
131+
"p07639577379371417602",
132+
"--utc",
133+
])
128134
.assert()
129135
.success()
130136
.stdout(predicate::str::contains("2026-05-14T03:01:58Z"));
131137
}
132138

139+
#[test]
140+
fn util_version_from_time_can_output_pagination_key() {
141+
bt_command()
142+
.args([
143+
"util",
144+
"version",
145+
"from-time",
146+
"2026-05-14T08:00:09-07:00",
147+
"--pagination-key",
148+
])
149+
.assert()
150+
.success()
151+
.stdout(predicate::str::contains("p07639762451734462464"));
152+
}
153+
133154
#[test]
134155
fn setup_uses_codex_detected_on_path_without_explicit_agent() {
135156
let repo = make_git_repo();

0 commit comments

Comments
 (0)