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
11 changes: 6 additions & 5 deletions src/Nitro/CommandLine/test/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ layer: a handful of representative flows, not exhaustive.
| `board-maximize` | the Tasks tab's maximize toggle (`z`) | the single-column maximized layout |
| `search` | search mode (`/`) in the Tasks tab (bare `nitro agent`) | live query filtering and opening a result's detail pane |
| `detail` | the Tasks tab's detail pane and dependency tree (`t`, `d`, `u`) | the detail body and tree explorer navigation |
| `mail-send` | `nitro agent init` then `agent register/mail send/inbox/reply/read --thread` | the mail send/inbox/reply/read round trip in a live workspace, one actor registered with a role |
| `mail-send` | `agent register/mail send/inbox/reply/read --thread` over a copy of the fixture | the mail send/inbox/reply/read round trip, one actor registered with a role |
| `mail-error` | `nitro agent mail send` to an invalid recipient name | the agent-name-normalization rejection and non-zero exit rendering |
| `mail-board` | the Mail tab (bare `nitro agent`, `]` to switch) | unread styling, the detail pane, and the thread toggle |
| `mail-board` | the Mail tab's actor-less Workspace mailbox (bare `nitro agent`, `]` to switch) | read-only navigation, fold/list/thread toggles, and per-agent filtering |
| `agents` | the Agents tab (bare `nitro agent`, `A` to switch) | the fixture's remote agent session and detail pane |

`help` is a trivial smoke flow that proves the pipeline itself,
independently of the fixture-backed flows below it. It asks for help on
Expand All @@ -54,8 +55,8 @@ direction, together covering the round trip.

The `mail-*` flows are a handful of representative mail flows, not
exhaustive per-command coverage (that is the unit tier's job): `mail-send`
runs live against a fresh workspace (init via the unified `nitro agent
init`, register two actors via the root `nitro agent register` command
runs live against a copy of the shared fixture (register two actors via the
root `nitro agent register` command
(one with `--role`), send with `--cc`, inbox as the recipient, read with
`--thread` after a reply), so its ids and dates need the `mail-send`
SCRUBS entry in [`run.sh`](run.sh); `mail-board` runs against the shared
Expand Down Expand Up @@ -107,7 +108,7 @@ diffs under `out/report/` for CI. Exit codes: `0` all PASS, `1` any FAIL/NEW
(or, under `--update`, any recording failure), `2` usage error, `3` docker
missing.

Requirements: `docker` + the .NET SDK. Nothing else, `ttyd`, `ffmpeg`, and the
Requirements: `docker`, `sqlite3`, and the .NET SDK. `ttyd`, `ffmpeg`, and the
fonts are baked into the pinned container.

## What makes it deterministic
Expand Down
Binary file modified src/Nitro/CommandLine/test/e2e/agents-flow.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions src/Nitro/CommandLine/test/e2e/agents-flow.golden.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[T]asks [M]ail (2) [A]gents M[e]mory
╭─Agents (2)──────────────────────────────────╮╭─bob──────────────────────────────────────────╮
│ > bob ◇ claude-code started ││ Session │
│ 2026-01-01 heard 2026-01-01 ││ │
│ e2e-agent ● nitro-board started AGE ││ Actor: bob │
│ heard AGE ││ Role: - │
[T]asks [M]ail [A]gents M[e]mory
╭─Agents (1)──────────────────────────────────╮╭─bob──────────────────────────────────────────╮
│ > bob ◇ claude-code started 2026-01-01 ││ Session │
│ heard 2026-01-01 ││ │
│ ││ Actor: bob │
│ ││ Role: - │
│ ││ State: remote │
│ ││ Harness: claude-code │
│ ││ Session id: e2e-remote-session │
Expand Down Expand Up @@ -32,4 +32,4 @@
│ ││ │
│ ││ │
╰─────────────────────────────────────────────╯╰──────────────────────────────────────────────╯
hjkl move enter open r refresh y copy id z zoom e edit esc back q quit … e2e-agent
hjkl move enter open r refresh y copy id z zoom esc back q quit [ ] shift+letter tab
40 changes: 6 additions & 34 deletions src/Nitro/CommandLine/test/e2e/agents-flow.tape
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,12 @@
# header explains the remote-vs-live distinction that made bob the one state
# a static SQL fixture can pin byte-stably).
#
# perles-net-nhs (feat(nitro-agent): register both board entry points as
# live operator sessions) starts a live nitro-board session for bare
# `nitro agent` itself, before the shell even opens, so the tab can show a
# second row for the board alongside the seeded one. ListParticipantsAsync
# orders by harness then session id, and "claude-code" sorts ahead of
# "nitro-board", so bob stays row 0 and selected by default; the board's own
# row lands second.
# That row's fields are all deterministic except its two ages: actor
# e2e-agent (the resolved mail actor), harness nitro-board, state online
# (its host always matches the current instance, and the process is,
# definitionally, alive). Started/Last heard are MailAges.Format's relative
# ages, computed against wall-clock time; the board session starts moments
# before this frame is captured, so they read "now" in a fast run but can
# drift to "{n}m" if recording is slow, so run.sh's SCRUBS[agents] entry
# normalizes both to AGE before diffing. Its role (operator,
# BoardSessionLifecycle.OperatorRole) is set the same way, but
# AgentRowBadge.Render truncates the role column to
# nothing at this tape's fixed 1100-wide geometry once a second, wider
# ("nitro-board") harness value is on screen - the same truncation bob's
# own row already carries in the pre-existing golden, role "-" included.
# Confirmed against a live run of the published binary, not guessed from
# source.
#
# Drives: land on Agents, two rows, the fixture's bob (remote) selected by
# Drives: land on Agents, one row, the fixture's bob (remote) selected by
# default; its detail pane shows the new Session section (session id, host,
# started/last-heard) ahead of Identity, then Sent mail (m-fix006, shared
# with the mail board tape's own fixture data); no Tasks section, since bob
# is nobody's task assignee. The board's own row is asserted from the list
# line alone (actor, presence glyph, harness) - its detail pane is never
# opened, so the real session id/host/pid a live process carries never
# needs to be pinned.
# is nobody's task assignee. Bare `nitro agent` is an actor-less observer and
# does not register its own board session.
#
# Produces agents-flow.gif + agents-flow.txt.

Expand Down Expand Up @@ -83,15 +58,12 @@ Type `nitro agent` Enter
Wait+Screen@30s /> ○ \[B\] P0 acme-a1b Checkout crashes on Safari/

# Shift+A: TabSwitchKeys.ResolveMnemonic jumps straight to the Agents tab.
# Two live agent_sessions rows now exist (fixture-seeded bob, plus this
# launch's own live board session), sorted harness-then-session-id: bob
# (claude-code) stays row 0 and selected by default, the board session
# (nitro-board, actor e2e-agent, role operator, state online) is row 1.
# The fixture-seeded bob session is the only participant and is selected by
# default. Bare `nitro agent` does not add a session row.
Type "A"
Wait+Screen@30s /Agents \(2\)/
Wait+Screen@30s /Agents \(1\)/
Wait+Screen@30s /─bob─/
Wait+Screen@30s /bob\s+◇/
Wait+Screen@30s /e2e-agent\s+●\s+nitro-board/
Wait+Screen@30s /Session/
Wait+Screen@30s /Host: e2e-remote-host-fixture/

Expand Down
Binary file modified src/Nitro/CommandLine/test/e2e/board-flow.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/Nitro/CommandLine/test/e2e/board-flow.golden.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[T]asks [M]ail (2) [A]gents M[e]mory
[T]asks [M]ail [A]gents M[e]mory
╭─Blocked (3)─────────────────────────────────────────────────────────────────────────────────╮
│ ○ [B] P0 acme-a1b Checkout crashes on Safari │
│ ○ [E] P1 acme-epic1 Launch v2 pricing page │
Expand Down Expand Up @@ -32,4 +32,4 @@
│ │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────╯
hjkl move enter open r refresh y copy id z zoom e edit esc back q quit … e2e-agent
hjkl move enter open r refresh y copy id z zoom esc back q quit [ ] shift+letter tab
Binary file modified src/Nitro/CommandLine/test/e2e/board-maximize-flow.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/Nitro/CommandLine/test/e2e/board-maximize-flow.golden.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[T]asks [M]ail (2) [A]gents M[e]mory
[T]asks [M]ail [A]gents M[e]mory
╭─Blocked (3)─────────────────────────────────────────────────────────────────────────────────╮
│ ○ [B] P0 acme-a1b Checkout crashes on Safari │
│ ○ [E] P1 acme-epic1 Launch v2 pricing page │
Expand Down Expand Up @@ -32,4 +32,4 @@
│ │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────╯
hjkl move enter open r refresh y copy id z zoom e edit esc back q quit … e2e-agent
hjkl move enter open r refresh y copy id z zoom esc back q quit [ ] shift+letter tab
Binary file modified src/Nitro/CommandLine/test/e2e/close-reopen-flow.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/Nitro/CommandLine/test/e2e/close-reopen-flow.golden.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
$ nitro agent tasks close acme-a1b --reason "Won't fix, unreproducible"
$ nitro agent tasks close acme-a1b --reason "Won't fix, unreproducible" --actor e2e-agent
✓ Closed task 'acme-a1b'.
$ nitro agent tasks reopen acme-a1b
$ nitro agent tasks reopen acme-a1b --actor e2e-agent
✓ Reopened task 'acme-a1b'.
$
Binary file modified src/Nitro/CommandLine/test/e2e/create-flow.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/Nitro/CommandLine/test/e2e/create-flow.golden.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
$ nitro agent tasks create "Write onboarding docs"
$ nitro agent tasks create "Write onboarding docs" --actor e2e-agent
✓ Created task 'acme-XXX': Write onboarding docs.
$
Binary file modified src/Nitro/CommandLine/test/e2e/detail-flow.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/Nitro/CommandLine/test/e2e/detail-flow.golden.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[T]asks [M]ail (2) [A]gents M[e]mory
[T]asks [M]ail [A]gents M[e]mory
╭─acme-epic1 · blocking · depended on by────────────────────╮
│ ○ [E] P1 acme-epic1 Launch v2 pricing page │
│ ├─ > ● [T] P2 acme-epic1.1 Draft new pricing copy │
Expand Down Expand Up @@ -32,4 +32,4 @@



f follow m edge mode d direction u back hjkl move enter open r refresh y copy id … e2…
f follow m edge mode d direction u back hjkl move enter open r refresh y copy id …
5 changes: 2 additions & 3 deletions src/Nitro/CommandLine/test/e2e/fixtures/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ Before recording any flow, `run.sh` prepares `out/fixture/acme/` on the host
(not inside the VHS container):

1. `rm -rf` + `mkdir -p out/fixture/acme` for a clean slate.
2. Run the freshly published `bin/nitro agent init` inside it, with
`NITRO_TASK_ACTOR=e2e-agent` set. This creates the real
`.nitro/agents/agents.db` unified schema (via `AgentDatabase.InitializeAsync`,
2. Run the freshly published `bin/nitro agent init` inside it. This creates
the real `.nitro/agents/agents.db` unified schema (via `AgentDatabase.InitializeAsync`,
composing `TaskStoreSchema` and `MailStoreSchema`) and sets the `acme`
task ID prefix (via `AgentWorkspace.NormalizePrefix`, derived from the
`acme` directory name, matching `TasksCommandTestBase`).
Expand Down
2 changes: 1 addition & 1 deletion src/Nitro/CommandLine/test/e2e/fixtures/mail-seed.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
BEGIN TRANSACTION;

-- agents -----------------------------------------------------------------
-- e2e-agent is the actor the tape opens the board as (NITRO_MAIL_ACTOR).
-- e2e-agent backs the identity-dependent mail command fixtures.
INSERT INTO agents (name, registered_at, last_seen_at) VALUES
('e2e-agent', '2026-01-01 07:00:00.0000000+00:00', '2026-01-01 07:00:00.0000000+00:00'),
('alice', '2026-01-01 07:00:00.0000000+00:00', '2026-01-01 07:00:00.0000000+00:00'),
Expand Down
Binary file modified src/Nitro/CommandLine/test/e2e/mail-board-flow.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions src/Nitro/CommandLine/test/e2e/mail-board-flow.golden.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[T]asks [M]ail (2) [A]gents M[e]mory
╭─Inbox (3)─────────────────────────────────────────────╮╭─m-fix002 Billing review────────────╮
[T]asks [M]ail [A]gents M[e]mory
╭─Workspace: bob (3)────────────────────────────────────╮╭─m-fix002 Billing review────────────╮
│ From To Su… Age ││ From: bob │
│ > T bob e2e-agent+1 Bi… 2026-01-01 ││ To: e2e-agent │
│ ● + alice e2e-agent Pr… 2026-01-01 ││ Cc: alice │
│ ● + alice e2e-agent Re… 2026-01-01 ││ Date: 2026-01-01 10:00 │
│ > bob e2e-agent+1 Bi… 2026-01-01 ││ To: e2e-agent │
│ e2e-agent bob St… 2026-01-01 ││ Cc: alice │
│ alice bob De… 2026-01-01 ││ Date: 2026-01-01 10:00 │
│ ││ e2e-agent: read 2026-01-02 08:00 │
│ ││ alice: unread │
│ ││ │
Expand Down Expand Up @@ -32,4 +32,4 @@
│ ││ │
│ ││ │
╰───────────────────────────────────────────────────────╯╰────────────────────────────────────╯
hjkl move tab switch pane enter focus detail u read/unread a archive r reply c compose …
hjkl move tab switch pane enter focus detail y copy id f filter t thread …
Loading
Loading