Adds Agent Mail - #10276
Conversation
Adds the SQLite-backed mail store (workspace, schema, IMailStore/MailStore, MailActor, MailAgentName) mirroring the tasks foundation exactly: same connection handling, WAL/foreign_keys pragmas, transaction style, and PRAGMA user_version init/check. Wires IMailStore into DI next to ITaskStore. No commands yet (perles-net-mail-epic-90n.1); downstream beads build on this contract.
… agents) Implements perles-net-mail-epic-90n.2: the nitro agent mail CLI entry points that mirror the Commands/Tasks conventions, backed by the IMailStore foundation from 90n.1. Register the mail command group under `nitro agent mail` and wire the new result DTOs into the AOT JSON source-generation context.
…t-mail-epic-90n.3) Adds nitro agent mail send/reply/broadcast as thin wrappers over IMailStore.SendMessageAsync/ReplyMessageAsync, with --body/--body-file mutual exclusion enforced at parse time, first-occurrence recipient ordering, and a shared MailMessageResult JSON DTO. Registers the new subcommands under nitro agent mail and extends JsonSourceGenerationContext for their JSON output, following the pattern already used by init/register/ whoami/agents.
Builds the mail board's model/mode layer against the complete IMailStore contract with fakes, mirroring how the task board's model was built against ITaskStore before its commands existed (perles-net-mail-epic-90n.7, started early per the orchestrator's parallelization ruling). Adds MailState/MailDataLoader (inbox filter cycling: inbox/unread/archived, thread loading), MailMode (ITuiMode: list + detail panes, focus toggling, thread view toggle), MailMessageBadge/MailDetailView (rendering), and MailKeyMap (a standalone key table for the mail command's own dispatcher). Read-only: no gesture marks a message read or writes to the store. One additive ThemeTokens entry (mail.message.unread). Entry command registration, Commands/Mail/, and Services/Mail/ are out of scope here (commands lane is building those concurrently; entry wiring is deferred to .8 per the bead comment).
Implements perles-net-mail-epic-90n.4: list, read, acknowledge, and archive mail messages for the acting agent, mirroring the Commands/Tasks conventions established by the earlier mail identity and send beads.
Adds `nitro agent mail threads` (conversation-level rollup with participants, message count, unread count, last activity) and `nitro agent mail search <text>` (case-insensitive subject/body search, reusing the inbox row rendering and DTO). Both include archived messages and honor --limit/--actor per epic conventions.
Adds `nitro agent mail watch`, a poll loop that reconciles the acting agent's inbox against a baseline captured at start, once per second via the injected TimeProvider. Prints newly arrived unread messages, oldest first, using the same rendering as `read` in human mode and the read DTO in JSON mode. Never marks anything read. An optional --timeout exits with an error and a stderr-only message when it elapses with no new mail; without it, watch waits until cancelled.
SearchAsync only LIKE-matched subject and body, not the sender agent name, though the bead prose requires sender matching. Extend the LIKE predicate to also cover m.sender, reusing the existing escaped text and ESCAPE clause.
SearchMailCommand's description still said "subject and body" only, but the underlying query has matched sender since 4dd2e12.
…ply) + board entry command Wires read/unread toggle, archive (behind a confirmation), reply, and compose into the mail board (u/a/r/c), every write going through the same IMailStore members the CLI uses. Opening a message in the detail pane marks it read. Compose and reply build on the Form engine with a shared discard confirmation on Esc when dirty. MailMode owns its own overlays (archive confirmation, compose/reply forms, discard confirmation) rather than adding task-specific fields to TuiShell; TuiShell gets one small additive raw-key routing check mirroring the existing SearchMode precedent. Fixes the case-sensitive actor match in MailRecipientView.FindRecipient (OrdinalIgnoreCase) per .7's binding follow-up, and adds a real MailStore-backed test file for the recipient/reply semantics FakeMailStore cannot independently prove. Registers 'nitro agent mail board' in MailCommand. perles-net-mail-epic-90n.8
Adds three representative nitro agent mail flows to the e2e VHS tier (mail-send, mail-error, mail-board), the seeded mailbox fixture mail-board-flow runs against, and a Mail_Init_Register_Send_Inbox_Round_Trips smoke test, so the mail CLI gets the same real-binary/real-PTY coverage the task CLI already has.
…-agent-unify-814.1) Adds AgentWorkspace/AgentDatabase under Services/Workspace as the shared discovery, schema composition, and version-stamping layer for tasks and mail: one .nitro/agents/ directory, one agents.db, one PRAGMA user_version (2), one transaction for DDL + stamp. TaskStore and MailStore now resolve their workspace and connections through AgentDatabase instead of forking their own OpenAsync/version logic; TaskWorkspace.cs and MailWorkspace.cs are deleted. The old init commands (agent tasks init, agent mail init) still exist and now build the unified layout, matching this bead's boundary. "No task/mail workspace found" collapses into one "No agent workspace found. Run `nitro agent init` first." message.
Extends TuiShell with a tabbed-hosting constructor that owns an ordered list of TuiTab instances: each tab keeps its own navigation stack and KeyDispatcher, so switching tabs preserves nested mode state and routes keys only to the active tab's key table. A one-row tab strip renders above the content region whenever more than one tab is hosted, tab switching uses [ and ], and it stays inert while any shell-level or mode-level overlay is capturing input. The shell-level task overlay machinery (editor, lifecycle dialogs, pickers, create form) now gates on which tab owns it. A DataChangedEvent refreshes every hosted tab's active mode, not only the active one. Generalizes the mail-mode raw-key-capturing check from a concrete MailMode type check to a new IRawKeyCapturingMode interface, and wires its overlay hints into the footer (previously never shown while a mail overlay was open). Adds MailMode.UnreadCount, refreshed alongside its other state, for a hosting tab's unread badge. The existing single-mode constructor is preserved unchanged for BoardTaskCommand and BoardMailCommand: it wraps its one mode in a single TuiTab, so the tab strip never renders and behavior is identical. Scoped per the orchestrator's early-start narrowing on bd-agent-unify-814.3: tab mechanics only, hosted with fakes; no TaskDbWatcher rename, no entry- command wiring.
Console.ReadKey on Linux never populates ConsoleKey.Oem4/Oem6 for '[' and ']' (verified with a pty probe: KEY=None(0) CHAR='['/']'), so the exact-chord equality check in TabSwitchKeys.Resolve always failed and tab switching was dead outside chords that also set ConsoleKey. Resolve now matches on KeyChar with no modifiers, mirroring KeyMap's printable- char fallback, which still covers the Oem4/Oem6-carrying chords used in existing tests.
…t init (bd-agent-unify-814.2) Adds InitAgentCommand under agent init: builds the unified .nitro/agents workspace (agents.db, tasks.jsonl, selective .gitignore) directly, and migrates a legacy pre-unification workspace when found: a legacy .nitro/tasks/tasks.db is attach-copied table by table (tasks, dependencies, labels, comments, events, config, child_counters), a legacy or already-committed tasks.jsonl is imported through the existing sync-import merge semantics, and a legacy .nitro/mail/mail.db is reported obsolete and left untouched by ruling. Prefix precedence is explicit --prefix, then migrated config, then the directory name. --force reapplies schema and prefix in place without touching tasks.jsonl. A failed init parses any source jsonl before creating anything and deletes a freshly-created agents.db on any later failure, so the command is retryable and legacy files are never written to. agent tasks init and agent mail init are removed, not aliased, along with their now-unused options. The seven remaining "No task/mail workspace found" command-level messages (SyncTaskCommand x3, BoardTaskCommand, WhereTaskCommand, DoctorTaskCommand, BoardMailCommand) collapse to "No agent workspace found. Run `nitro agent init` first." DoctorTaskCommand also warns on leftover legacy .nitro/tasks and .nitro/mail directories. JsonSourceGenerationContext swaps TaskWorkspaceInitResult and MailWorkspaceInitResult for AgentWorkspaceInitResult, and CommandLine.Smoke.Tests retargets its init-based smoke tests to the new command.
Adds AlreadyInitialized_Force_PreservesSeededTaskAndMailRows, which was claimed as covered by bd-agent-unify-814.2's comment but did not exist.
AgentCommand now carries its own action alongside its subcommands: an interactive terminal with a resolved agent workspace opens the unified tabbed TUI (tasks + mail) via the new AgentTuiLauncher, starting on the tasks tab; a non-interactive terminal, or no workspace found, prints exactly the guidance a bare group with no action prints today (locked in, since it already lists init/tasks/mail). Also, from the .3 review notes now due: - TuiShell's tabbed ctor throws ArgumentOutOfRangeException for an out-of-range tasksTabIndex instead of silently clamping it. - HandleDataChanged no longer routes an inactive tab's own refresh follow-ups through the active tab's mode (a latent cross-tab leak). - TaskDbWatcher is renamed to SqliteDbWatcher, now shared by both the bare-agent launcher and the single-tab board commands. - TuiShellTabsTests gained a ConsoleKey.None shell-level tab-switch case (the Linux Console.ReadKey shape), matching TabSwitchKeysTests.
An invalid NITRO_MAIL_ACTOR (or its NITRO_TASK_ACTOR fallback) no longer prevents the tabbed agent shell from opening. AgentTuiLauncher catches the ExitException from MailActor.Resolve and hosts the Mail tab with a new MailUnavailableMode instead: a static "Mail" label, no unread polling, and the resolution failure rendered with a hint to set NITRO_MAIL_ACTOR. The Tasks tab and its actor resolution are unaffected. Deferred from bd-agent-unify-814.3 (fix item 2) to .4.
Sweeps the e2e VHS tier onto the unified .nitro/agents/agents.db workspace and the tabbed TUI (bd-agent-unify-814.5): init-flow now drives the unified `nitro agent init`, mail-send/mail-error init the same way, and one shared fixture (seed.sql + mail-seed.sql applied to the same agents.db, guarded by PRAGMA user_version 2 plus a task and a mail query) replaces the old two-fixture layout. board, board-maximize, detail, and mail-board launch via bare `nitro agent` so the tab strip renders; board and mail-board each demonstrate a `[`/`]` tab switch. Adds agent-root-flow, driving bare `nitro agent` into the tabbed TUI and quitting. search-flow stays on the single-tab `agent tasks board` entry point: typing a query while the Mail tab is hosted races a Mail-tab refresh loop that resets SearchMode's own debounced query and never lets it apply, filed as bd-agent-unify-814.7 (out of this bead's e2e-only scope; see the NEEDS-PASCAL comment on bd-agent-unify-814.5). Fixes the one remaining stale `agent tasks init` spelling in the AOT smoke job of nitro-cli-e2e.yml.
…unify-814.7) Every store connection opens without pooling and closes after a single query. In WAL mode that makes SQLite create, checkpoint, and delete the -wal and -shm siblings on close even for a plain read, which SqliteDbWatcher's FileSystemWatcher saw as a data change and re-fired on, 200ms later, forever. In the tabbed nitro agent TUI the Mail tab's own RefreshRequested read kept retriggering itself on every DataChangedEvent, racing out SearchMode's debounced query reset on the Tasks tab so a typed search query never applied. SqliteDbWatcher now watches only the main database file; its mtime moves only when a write actually lands, not on a read-triggered checkpoint-of-nothing. Added regression tests proving read-shaped -wal/-shm churn alone stays silent while a real write amid that same churn still fires. Re-recorded search-flow.tape via bare 'nitro agent' (tab strip on screen) now that the narrowing search demo passes; fixed two stale .5-era tape comments (detail-flow.tape's mis-attributed cross-reference, list-flow.tape's pre-unification db path).
RefreshRequested used to reset the pending debounced query to the last applied one, discarding a not-yet-applied edit and its timer whenever an external write (e.g. another agent creating a task while the user types) triggered a refresh. TickAsync now re-runs the last applied query for display on a refresh without touching a pending, not-yet-due edit, so the user's typed text and debounce timer survive. Bead: bd-n6k
…-g3b) The watcher previously fired only off the main db file's mtime, which moves via SQLite's PASSIVE close-time checkpoint. That checkpoint is silently skipped when another connection holds a read lock (a concurrent TUI reader or a second nitro process), so a real write can leave frames appended in -wal with no event, leaving the TUI stale until a later write checkpoints or the user presses r. Now also key on -wal size growth: a size increase past its last observed size fires a change, while a plain read's own create and delete of -wal (which never grows past that baseline) stays silent, same as before. The -shm sibling stays fully ignored. Adds deterministic tests for the growth case, including one shaped like a cross-process writer whose checkpoint is blocked by a concurrent reader (main db untouched, -wal grows and stays grown).
…t-unify-814.8) Moves the agents table and its CRUD out of mail into a shared IAgentRegistry in the Workspace layer, adds role and implicit columns with an idempotent v2-to-v3 upgrade path, and re-routes register/whoami/ list from `nitro agent mail` to `nitro agent` directly. IMailStore drops its agent CRUD and now consumes IAgentRegistry, including for the auto-register-on-send/reply path.
…-role (bd-agent-unify-814.9) Sending mail to an unknown recipient no longer hard-fails: SendMessageAsync implicit-creates the recipient's agent row via a new IAgentRegistry.EnsureImplicitAsync and reports every still-unregistered recipient back through MailMessage.Unregistered, so an orchestrator can mail a worker it is about to spawn. The send command prints a warning line per unregistered recipient and its JSON output (a new MailSendResult DTO, kept separate from the shared MailMessageResult so reply and broadcast are unaffected) carries the unregistered list. Broadcast now excludes implicit rows from "everyone" and gains --role to target only registered agents with that role.
…er + send policy (bd-agent-unify-814.10) .8 moved agent register/whoami/list to the nitro agent root (removing the old mail register/whoami/agents spellings) and .9 changed mail send/broadcast so an unregistered recipient now succeeds with a "note: has never registered." warning instead of a hard error. Re-record via run.sh --update to bring the mail-send-flow and mail-error-flow tapes, goldens, and gifs back in sync: mail-send-flow now registers both actors via the root command (one with --role, to demonstrate the read command's "From: name (role)" header) and mail-error-flow reshapes its hard-fail scene around an INVALID recipient name (agent-name normalization rejection), the one remaining error case on send. Also bumps run.sh's FIXTURE_SCHEMA_VERSION guard from 2 to 3 to match AgentDatabase.CurrentVersion after .8's role/implicit columns landed; without it the fixture-prep step fails before any flow can record. Full ./run.sh (all 16 flows) passes with exit 0 twice.
There was a problem hiding this comment.
Pull request overview
This PR introduces an agent mail feature to the Nitro CLI and unifies local workspace state under a single agent workspace (.nitro/agents/agents.db). It also adds a tabbed TUI launched by bare nitro agent, hosting both Tasks and Mail, and updates the e2e tapes/tests to cover the new behavior.
Changes:
- Add mail CLI + TUI (send/reply/inbox/threads/search/board) backed by a unified SQLite schema.
- Unify initialization/workspace plumbing (
nitro agent init) and add an agent registry (register/whoami/list) shared by tasks + mail. - Improve TUI refresh behavior (new SQLite watcher semantics + SearchMode refresh/debounce interaction) and expand test coverage + e2e tapes.
Reviewed changes
Copilot reviewed 189 out of 205 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Nitro/CommandLine/test/e2e/search-flow.tape | Update search tape to bare nitro agent |
| src/Nitro/CommandLine/test/e2e/search-flow.golden.txt | Golden updated for tab strip/footer |
| src/Nitro/CommandLine/test/e2e/README.md | Document expanded e2e flow set |
| src/Nitro/CommandLine/test/e2e/mail-send-flow.tape | New live mail send/reply tape |
| src/Nitro/CommandLine/test/e2e/mail-send-flow.golden.txt | Golden for mail send/reply flow |
| src/Nitro/CommandLine/test/e2e/mail-error-flow.tape | New invalid-recipient failure tape |
| src/Nitro/CommandLine/test/e2e/mail-error-flow.golden.txt | Golden for invalid-recipient error |
| src/Nitro/CommandLine/test/e2e/mail-board-flow.tape | New Mail tab TUI tape |
| src/Nitro/CommandLine/test/e2e/mail-board-flow.golden.txt | Golden for Mail tab board |
| src/Nitro/CommandLine/test/e2e/list-flow.tape | Update workspace path reference |
| src/Nitro/CommandLine/test/e2e/init-flow.tape | Switch to nitro agent init |
| src/Nitro/CommandLine/test/e2e/init-flow.golden.txt | Golden for unified init output |
| src/Nitro/CommandLine/test/e2e/fixtures/seed.sql | Seed tasks into unified agents.db |
| src/Nitro/CommandLine/test/e2e/fixtures/mail-seed.sql | New deterministic mail seed fixture |
| src/Nitro/CommandLine/test/e2e/detail-flow.tape | Detail tape updated for tabbed TUI |
| src/Nitro/CommandLine/test/e2e/detail-flow.golden.txt | Golden updated for tab strip |
| src/Nitro/CommandLine/test/e2e/board-maximize-flow.tape | Launch maximize flow via bare nitro agent |
| src/Nitro/CommandLine/test/e2e/board-maximize-flow.golden.txt | Golden updated for tab hints/strip |
| src/Nitro/CommandLine/test/e2e/board-flow.tape | Launch board via bare nitro agent + tab switch |
| src/Nitro/CommandLine/test/e2e/board-flow.golden.txt | Golden updated for tab strip/footer |
| src/Nitro/CommandLine/test/e2e/agent-root-flow.tape | New tape proving bare nitro agent mount/quit |
| src/Nitro/CommandLine/test/e2e/agent-root-flow.golden.txt | Golden for agent-root flow |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Shell/TuiTabTests.cs | New unit tests for tab mode stack |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Shell/TabSwitchKeysTests.cs | New tests for [/] tab switching |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Search/SearchModeTests.cs | Add tests for refresh vs debounce behavior |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Mail/MailRecipientViewTests.cs | New tests for per-recipient read/archive logic |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Mail/MailMessageBuilder.cs | New mail test helper builder |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Mail/MailMessageBadgeTests.cs | New tests for list-row rendering |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Mail/MailDetailViewTests.cs | New tests for detail/thread rendering |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Mail/MailDataLoaderTests.cs | New tests for inbox/thread loading |
| src/Nitro/CommandLine/test/CommandLine.Tests/Tui/Mail/MailAgesTests.cs | New tests for relative/absolute age labels |
| src/Nitro/CommandLine/test/CommandLine.Tests/Services/Workspace/TestFileSystem.cs | New test filesystem helper (agents) |
| src/Nitro/CommandLine/test/CommandLine.Tests/Services/Mail/TestFileSystem.cs | New test filesystem helper (mail) |
| src/Nitro/CommandLine/test/CommandLine.Tests/Services/Mail/MailAgentNameTests.cs | New tests for agent name normalization |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/WhereTaskCommandTests.cs | Update error message for unified init |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/TaskStoreTests.cs | TaskStore tests updated for AgentDatabase/workspace |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/TasksCommandTestBase.cs | Use AgentWorkspace + agent init |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/SyncTaskCommandTests.cs | Update paths + init behavior expectations |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/StatusTaskEpicCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/StatsTaskCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/SetTaskConfigCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/ReadyTaskCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/ListTaskConfigCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/InitTaskCommandTests.cs | Remove legacy agent tasks init tests |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/GetTaskConfigCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/DoctorTaskCommandTests.cs | Add warning coverage for legacy dirs |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/CloseEligibleTaskEpicCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/BoardTaskCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Tasks/BlockedTaskCommandTests.cs | Update unified init guidance |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Mail/MailCommandTestBase.cs | New base for mail command tests |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Mail/MailActorTests.cs | New tests for actor resolution precedence |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Mail/BoardMailCommandTests.cs | Tests for mail board command behavior |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Agent/WhoamiAgentCommandTests.cs | New whoami command tests |
| src/Nitro/CommandLine/test/CommandLine.Tests/Commands/Agent/AgentCommandTestBase.cs | New base for agent registry tests |
| src/Nitro/CommandLine/test/CommandLine.Tests/CommandExecutionResultExtensions.cs | Add assertion helper for bare group guidance |
| src/Nitro/CommandLine/test/CommandLine.Smoke.Tests/SmokeTests.cs | Smoke coverage for mail round-trip |
| src/Nitro/CommandLine/src/CommandLine/Tui/Theming/ThemeTokens.cs | Add theme token for unread mail styling |
| src/Nitro/CommandLine/src/CommandLine/Tui/Shell/TuiTab.cs | New tab abstraction for mode stacks |
| src/Nitro/CommandLine/src/CommandLine/Tui/Shell/TabSwitchKeys.cs | New [/] tab switching resolution |
| src/Nitro/CommandLine/src/CommandLine/Tui/Shell/IRawKeyCapturingMode.cs | New interface for raw-key overlays |
| src/Nitro/CommandLine/src/CommandLine/Tui/Search/SearchMode.cs | Refresh handling adjusted to preserve edits |
| src/Nitro/CommandLine/src/CommandLine/Tui/Runtime/TaskDbWatcher.cs | Remove legacy DB watcher |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailViewMode.cs | New enum for message vs thread view |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailUnavailableMode.cs | New mode for invalid actor resolution |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailReplyForm.cs | New reply form widget |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailRecipientView.cs | Recipient read/archive helpers |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailMessageBadge.cs | Render mail list rows (markup) |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailListFilter.cs | New inbox filter enum |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailFocus.cs | New focus enum (list/detail) |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailDataLoader.cs | Data loader translating UI filters to store |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailAges.cs | Shared age formatting for mail list |
| src/Nitro/CommandLine/src/CommandLine/Tui/Input/TuiMessage.cs | Add mail-related TUI messages |
| src/Nitro/CommandLine/src/CommandLine/Tui/Board/BoardDataLoader.cs | Adjust deferred/blocked column filtering |
| src/Nitro/CommandLine/src/CommandLine/Services/Workspace/IAgentRegistry.cs | New shared agent registry contract |
| src/Nitro/CommandLine/src/CommandLine/Services/Workspace/AgentWorkspace.cs | Define unified .nitro/agents layout |
| src/Nitro/CommandLine/src/CommandLine/Services/Workspace/AgentRole.cs | Normalize agent role values |
| src/Nitro/CommandLine/src/CommandLine/Services/Workspace/AgentRegistrySchema.cs | Schema for agents table |
| src/Nitro/CommandLine/src/CommandLine/Services/Workspace/AgentRecord.cs | Agent record model |
| src/Nitro/CommandLine/src/CommandLine/Services/Tasks/TaskStoreSchema.cs | Remove legacy version constant |
| src/Nitro/CommandLine/src/CommandLine/Services/Tasks/TaskStore.cs | Use AgentDatabase + AgentWorkspace |
| src/Nitro/CommandLine/src/CommandLine/Services/Results/JsonSourceGenerationContext.cs | Add JSON result types for agent/mail |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailThreadSummary.cs | Thread summary model |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailStoreSchema.cs | Mail tables schema |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailRecipientKinds.cs | Recipient kind constants |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailRecipient.cs | Recipient record model |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailMessageCreation.cs | Send parameters model |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailMessage.cs | Mail message model |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailInboxFilter.cs | Inbox query filter model |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailAgentName.cs | Normalize/validate mail agent names |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailActor.cs | Resolve actor identity for mail |
| src/Nitro/CommandLine/src/CommandLine/Extensions/ServiceCollectionExtensions.cs | Register AgentDatabase/registry/mail store |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/WhereTaskCommand.cs | Update unified init error guidance |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/TasksCommand.cs | Remove legacy tasks init subcommand |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/SetTaskConfigCommand.cs | Use AgentWorkspace prefix normalization |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/Options/TaskPrefixOption.cs | Remove legacy tasks init option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/Options/ForceReinitializeOption.cs | Remove legacy tasks init option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/InitTaskCommand.cs | Remove legacy agent tasks init command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/DoctorTaskCommand.cs | Warn on leftover legacy workspace dirs |
| src/Nitro/CommandLine/src/CommandLine/Commands/Tasks/BoardTaskCommand.cs | Use unified workspace + new DB watcher |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/ThreadsMailCommand.cs | New threads listing command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/SendMailCommand.cs | New send command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/SearchMailCommand.cs | New search command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/ReplyMailCommand.cs | New reply command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailUnreadOption.cs | Add --unread filter option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailTimeoutOption.cs | Add --timeout option validation |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailThreadOption.cs | Add --thread option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailSubjectOption.cs | Add required --subject option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailSinceOption.cs | Add RFC3339 --since parsing |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailSearchTextArgument.cs | Add search text argument |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailRecipientsArgument.cs | Add recipients argument |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailMessageIdsArgument.cs | Add message-ids argument |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailMessageIdArgument.cs | Add message-id argument |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailLimitOption.cs | Add --limit option validation |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailFromOption.cs | Add --from filter option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailCcOption.cs | Add repeatable --cc option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailBodyOption.cs | Add --body option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailBodyFileOption.cs | Add --body-file option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailAllOption.cs | Add --all (include archived) option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/Options/MailActorOption.cs | Add --actor option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailThreadRowResult.cs | JSON row type for threads |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailThreadRow.cs | Human-readable threads row formatting |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailSendResult.cs | JSON result for send (incl. unregistered) |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailMessageResult.cs | JSON result for message core fields |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailMessageDetailResult.cs | JSON result for read output |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailInboxRowResult.cs | JSON row type for inbox |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailInboxRow.cs | Human-readable inbox row formatting |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailIdsResult.cs | JSON result for batch mutations |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailCommand.cs | Add agent mail command group |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/MailBody.cs | Shared body resolution/validation |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/InboxMailCommand.cs | New inbox command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/BroadcastMailCommand.cs | New broadcast command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/BoardMailCommand.cs | New interactive mail board entry |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/ArchiveMailCommand.cs | New archive command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Mail/AckMailCommand.cs | New ack/mark-read command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/WhoamiAgentCommand.cs | New whoami command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/RegisterAgentCommand.cs | New register command |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/Options/StaleAgentOption.cs | Add --stale option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/Options/RoleAgentOption.cs | Add --role option |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/Options/ForceReinitializeAgentOption.cs | Add --force for agent init |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/Options/AgentPrefixOption.cs | Add --prefix for agent init |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/ListAgentCommand.cs | New list command for registry |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/AgentTuiLauncher.cs | Build/run tabbed Tasks+Mail TUI |
| src/Nitro/CommandLine/src/CommandLine/Commands/Agent/AgentCommand.cs | Make bare nitro agent launch tabbed TUI |
| .github/workflows/nitro-cli-e2e.yml | CI e2e workflow updated to agent init |
| src/Nitro/CommandLine/src/CommandLine/Tui/Runtime/SqliteDbWatcher.cs | New watcher avoiding -shm read churn |
| src/Nitro/CommandLine/src/CommandLine/Services/Mail/MailStore.cs | Mail store implementation over AgentDatabase |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailComposeForm.cs | Compose form + send outcome plumbing |
| src/Nitro/CommandLine/src/CommandLine/Tui/Mail/MailLifecycleActions.cs | Mark-read/unread/archive helpers |
Suppressed comments (2)
src/Nitro/CommandLine/test/e2e/README.md:59
- This paragraph says
searchis an exception that must be launched viaagent tasks boardand should be reverted later, but search-flow.tape already launches via barenitro agentand documents the bd-agent-unify-814.7 fix as proven. Please update/remove this “exception/revert” guidance to avoid misleading future updates.
src/Nitro/CommandLine/src/CommandLine/Services/Workspace/AgentWorkspace.cs:1 AgentWorkspaceusesIFileSystem, but this file has nousing ChilliCream.Nitro.CommandLine.Services;so it won’t compile (IFileSystem is in the Services namespace).
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| | `list` / `show` / `create` / `close-reopen` / `dep-tree` / `error` | `nitro agent tasks <cmd>` over the fixture | the non-interactive task commands | | ||
| | `board` | the Tasks tab (bare `nitro agent`) | column/row navigation, and a tab switch to Mail and back | | ||
| | `board-maximize` | the Tasks tab's maximize toggle (`z`) | the single-column maximized layout | | ||
| | `search` | search mode (`/`) via `agent tasks board`, no tab strip (see below) | live query filtering and opening a result's detail pane | |
| @@ -0,0 +1,35 @@ | |||
| Tasks Mail (1) | |||
| @@ -0,0 +1,29 @@ | |||
| namespace ChilliCream.Nitro.CommandLine.Services.Mail; | |||
| @@ -0,0 +1,35 @@ | |||
| namespace ChilliCream.Nitro.CommandLine.Services.Mail; | |||
| using ChilliCream.Nitro.CommandLine.Services.Mail; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Theming; | ||
|
|
||
| namespace ChilliCream.Nitro.CommandLine.Tui.Mail; |
| using ChilliCream.Nitro.CommandLine.Services.Mail; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Input; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Shell; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Theming; | ||
| using Spectre.Console.Rendering; | ||
|
|
||
| namespace ChilliCream.Nitro.CommandLine.Tui.Mail; |
| using ChilliCream.Nitro.CommandLine.Services.Mail; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Input; |
| using System.Data.Common; | ||
| using System.Globalization; | ||
| using System.Security.Cryptography; | ||
| using System.Text; | ||
| using ChilliCream.Nitro.CommandLine.Services.Workspace; | ||
| using Dapper; | ||
| using Microsoft.Data.Sqlite; | ||
|
|
||
| namespace ChilliCream.Nitro.CommandLine.Services.Mail; |
| using ChilliCream.Nitro.CommandLine.Services.Mail; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Input; |
| using ChilliCream.Nitro.CommandLine.Services.Mail; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Editing; | ||
| using ChilliCream.Nitro.CommandLine.Tui.Input; |
🎬 Nitro CLI E2E snapshots changedThese flow recordings differ from Run 32478167500 · full set in the nitro-e2e-snapshots artifact. |




























No description provided.