Commit 7565d45
feat: add TUI features and fix benchmark pagination total count (#230)
## Summary
- **Object create form**: New TUI screen accessible via `c` shortcut
from object list. Supports optional file path upload or displays
pre-signed S3 URL with clipboard copy. For tar/tgz content types, a
multi-item list manager allows adding multiple file paths; for other
types, a single text input is shown. Switching content type syncs
between the two inputs bidirectionally.
- **Benchmark tab toggle**: Changed public/custom toggle from `t` key to
`Tab` key with visual tab bar matching the agent list pattern.
- **Blueprint tab toggle**: Added public/custom toggle with `Tab` key
and visual tab bar matching the benchmark/agent list pattern.
- **Benchmark pagination fix**: All benchmark list screens (Benchmark
Definitions, Benchmark Runs, Scenario Runs, Benchmark Jobs) now
correctly display total count from the API instead of current page item
count.
- **Full Details viewport fix**: Fixed off-by-one in `DetailedInfoView`
overhead calculation that caused the top border to be clipped off screen
when content filled the viewport exactly.
- **CLI: `blueprint create --base`**: Duplicate a blueprint by passing
`--base <id|name>` to `blueprint create`. The source blueprint's
parameters are used as defaults; any other flag overrides. `--name`
defaults to `{base}-copy` when `--base` is used.
- **CLI: `axon events`**: New subcommand to list events for an axon.
**Fixed origin field to display enum names (SYSTEM_EVENT, AGENT_EVENT,
etc.) instead of numeric values.**
- **CLI: `scenario list`**: New subcommand to list scenario runs with
pagination and optional benchmark run ID filter.
- **Metadata support**: `--metadata key=value` added to `object upload`
and `benchmark-job run` CLI commands. TUI create screens for objects and
benchmark jobs include a metadata key-value editor matching the devbox
create pattern.
- **Tar archive: duplicate path rejection**: `createTarBuffer` now
rejects duplicate input paths (after `path.resolve`) instead of
producing an invalid tar archive.
- **Tar archive: symlink support**: Replaced `nanotar` with
`tar-stream`. Symlinks are now stored as proper tar symlink entries
(type `2`) with their target in `linkname`, instead of being rejected.
This applies to both CLI and TUI upload flows.
- **TUI tar single-file fix**: When content type is tar/tgz and a single
file (not directory) is specified, the TUI now uploads it as-is instead
of re-archiving it. Matches the CLI behavior.
- **TUI `[d]` keybind consistency**: Changed all `[d] Remove` hints in
devbox create (gateway configs, MCP configs, agent mounts, object
mounts) to `[d] Delete` to match the rest of the codebase.
- **Benchmark job metadata navigation**: Fixed up/down arrow keys moving
the main form cursor while editing metadata key-value pairs. Added
`isActive: !inMetadataSection` guard to the main form input handler.
- **Benchmark list `[c]` keybind fix**: Changed "Create Job" shortcut
from `c` to `s` to avoid conflicting with the `[c]` = "Copy ID"
convention used in detail screens. The popup already used `s` for this
action.
- **CLI output consistency**: Standardized all CLI list/get/info
commands to default to JSON output and removed chalk-colored text tables
from `axon events`, `axon list`, `scenario list`, `scenario info`,
`benchmark-job list`, `benchmark-job summary`, and `agent show`. Text
mode now uses the shared `output()` utility's uncolored key-value
format.
**Note**: TUI axon events and SQL workbench screens have been moved to
PR #233.
## Test plan
### Automated tests (155+ new tests)
| Test file | Tests | Coverage |
|-----------|-------|---------|
| `services/benchmarkJobService.test.ts` | 27 | `buildCloneParams` (all
source/secret variants), `createBenchmarkJob` (validation, config
mapping), `listBenchmarkJobs`, `getBenchmarkJob`, `getBenchmarkRun`,
`listBenchmarkRunScenarioRuns` |
| `services/axonService.test.ts` | 15 | `listActiveAxons` (smart search,
pagination), `getAxon`, `listAxonEvents` (hasMore detection, row
mapping, origin enum mapping), `executeAxonSql` |
| `services/benchmarkService.test.ts` | 16 | `listScenarioRuns` (both
code paths), `listPublicBenchmarks`, `createBenchmarkRun`,
`listBenchmarkRuns`, `getBenchmarkRun`, `getScenarioRun`,
`listBenchmarks`, `getBenchmark` |
| `services/objectServiceApi.test.ts` | 6 | `createObject`,
`completeObject`, `uploadToPresignedUrl` |
| `services/objectService.test.ts` | +5 | `buildObjectDetailFields` edge
cases (hours format, missing size, public field) |
| `commands/object/upload.test.ts` | +3 | Symlink entries stored with
correct type/linkname, symlinks inside directory trees, duplicate path
rejection |
| `commands/axon/events.test.ts` | 5 | Output format, limit defaults,
error handling |
| `commands/blueprint/create.test.ts` | 26 | Normal create
(name+options, missing name error), --base (ID/name lookup, exact match,
fallback, not found, default name, custom name, all source params
copied, override per flag, preserves non-overridden params), output
format, error handling |
| `commands/scenario/list.test.ts` | 8 | Pagination, sorting, output
formats, filter, error handling |
| `components/allocateSectionLines.test.ts` | 10 | Zero/partial/full
budget, single-field priority, null filtering, multi-section
distribution |
### Manual tests
- [x] TUI: Objects list → press `c` → verify create form renders with
Name, Content Type, File Path fields
- [x] TUI: Create object with non-tar content type → verify single text
input for file path
- [x] TUI: Create object → switch content type to tar/tgz → verify file
path field becomes multi-item list manager
- [x] TUI: Type a path in single input, switch to tar → verify path
appears as 1st entry in list
- [x] TUI: Add multiple paths in tar mode, switch to text → verify 1st
entry populates single input; switch back to tar → verify entries >=2
are preserved
- [x] TUI: Create object without file path → verify pre-signed URL
shown, `c` copies to clipboard
- [x] TUI: Create object with file path → verify upload + completion
flow
- [x] TUI: Create object with multiple paths and tar/tgz content type →
verify archive upload
- [x] TUI: Object create form → add metadata key-value pairs → verify
passed to API
- [x] TUI: Benchmark job create → add metadata key-value pairs → verify
passed to API
- [x] TUI: Benchmark Definitions → verify `Tab` key toggles between
Public/Custom with visual tab bar
- [x] TUI: Benchmark Definitions → verify old `t` key no longer toggles
- [x] TUI: Benchmark Definitions list → verify total count matches API
total, not page item count
- [x] TUI: Benchmark Runs list → verify total count displays correctly
- [x] TUI: Scenario Runs list → verify total count displays correctly
- [x] TUI: Benchmark Jobs list → verify total count displays correctly
- [x] TUI: Any detail screen → press `i` for Full Details → verify top
border is visible (not clipped)
- [x] TUI: Blueprint detail → verify "Duplicate Blueprint" operation is
NOT shown
- [x] TUI: Blueprint list → verify `Tab` key toggles between
Public/Custom with visual tab bar
- [x] TUI: Object create → select tar/tgz, specify a single .tar file →
uploads as-is (not re-archived)
- [x] TUI: Object create → select tar/tgz, specify a directory → creates
an archive
- [x] TUI: Devbox create → verify gateway/MCP/mount sections show `[d]
Delete` consistently
- [x] TUI: Benchmark job create → enter metadata section → verify
up/down arrows only navigate metadata items
- [x] TUI: Benchmark list → verify `s` creates a job, `c` no longer
triggers create
- [x] CLI: `rli blueprint create --base <id>` → verify creates copy with
{base}-copy name
- [x] CLI: `rli blueprint create --base <id> --name custom` → verify
custom name
- [x] CLI: `rli blueprint create --base <id> --resources LARGE` → verify
override applied
- [x] CLI: `rli blueprint create --base <id> --metadata env=prod` →
verify metadata override
- [x] CLI: `rli blueprint create --help` → verify --base flag listed,
--name not marked required
- [ ] CLI: `rli object upload <file> --metadata key=value` → verify
metadata on created object
- [ ] CLI: `rli benchmark-job run --agent ... --benchmark ... --metadata
key=value` → verify metadata
- [ ] CLI: `rli axon events <id>` → verify JSON output by default,
origin shows enum names
- [ ] CLI: `rli axon events <id> -o text` → verify key-value output
- [ ] CLI: `rli scenario list` → verify JSON output by default
- [ ] CLI: `rli scenario list -o text` → verify key-value output
- [ ] CLI: `rli benchmark-job list` → verify JSON output by default
- [ ] CLI: `rli benchmark-job summary <id>` → verify JSON output by
default
- [ ] CLI: `rli scenario info <id>` → verify JSON output by default
- [ ] CLI: `rli agent show <id>` → verify JSON output by default
- [ ] CLI: Upload with duplicate paths → verify error message instead of
invalid tar
- [ ] CLI: Upload with symlink path → verify symlink stored correctly in
tar archive
- [x] Type check: `npx tsc --noEmit` passes cleanly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>1 parent 419a961 commit 7565d45
48 files changed
Lines changed: 4134 additions & 1029 deletions
File tree
- src
- commands
- agent
- axon
- benchmark-job
- blueprint
- object
- scenario
- components
- router
- screens
- services
- store
- utils
- tests
- __tests__
- commands
- agent
- axon
- blueprint
- object
- scenario
- components
- services
- fixtures
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
202 | 202 | | |
203 | 203 | | |
204 | 204 | | |
| 205 | + | |
205 | 206 | | |
206 | 207 | | |
207 | 208 | | |
208 | 209 | | |
209 | 210 | | |
210 | 211 | | |
| 212 | + | |
211 | 213 | | |
212 | 214 | | |
213 | 215 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
92 | 91 | | |
| 92 | + | |
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
| |||
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
| 131 | + | |
131 | 132 | | |
132 | 133 | | |
133 | 134 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
19 | 18 | | |
20 | 19 | | |
21 | 20 | | |
| |||
105 | 104 | | |
106 | 105 | | |
107 | 106 | | |
108 | | - | |
109 | 107 | | |
110 | 108 | | |
111 | 109 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | 8 | | |
10 | 9 | | |
11 | 10 | | |
| |||
34 | 33 | | |
35 | 34 | | |
36 | 35 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | 36 | | |
77 | 37 | | |
78 | 38 | | |
| |||
87 | 47 | | |
88 | 48 | | |
89 | 49 | | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | 50 | | |
99 | 51 | | |
100 | 52 | | |
| |||
0 commit comments