|
1 | 1 | # mostro-cli — Transport v2 (NIP-44 Direct) client support |
2 | 2 |
|
3 | | -**Status:** Phase 1 implemented · Phases 2–3 pending |
| 3 | +**Status:** Phases 1–2 implemented · Phase 3 pending |
4 | 4 | **Daemon spec:** `MostroP2P/mostro` → `docs/TRANSPORT_V2_SPEC.md` |
5 | 5 | **Issue:** [#626 — Messaging Transport Abstraction Layer](https://github.com/MostroP2P/mostro/issues/626) |
6 | 6 | **Core:** `transport` module shipped in **mostro-core 0.13.0** |
@@ -93,32 +93,50 @@ Acceptance: `cargo build`, `cargo test`, `cargo clippy --all-targets |
93 | 93 | --all-features`, `cargo fmt --check` all clean; behaviour identical to before |
94 | 94 | against a gift-wrap node. |
95 | 95 |
|
96 | | -### Phase 2 — Transport selection (v2 capability) — PENDING |
97 | | - |
98 | | -Teach the CLI to send and receive on either transport, selected explicitly. |
99 | | - |
100 | | -- **Config:** a `TRANSPORT` env var / `--transport <gift-wrap|nip44>` flag, |
101 | | - parsed into `Transport` (default `gift-wrap` — wire-identical to today). |
102 | | - Mirrors the daemon's `[mostro] transport` knob. Store it on `Context`. |
103 | | -- **Send:** route the Mostro-protocol path of `send_dm` through |
104 | | - `wrap_message_with(ctx.transport, …)` instead of the hard-wired |
105 | | - `wrap_message`. The NIP-17 peer-chat path (`to_user`) is untouched. |
106 | | -- **Receive:** replace the hard-coded `Kind::GiftWrap` filter in `wait_for_dm` |
107 | | - (and the notification-loop kind check) with `ctx.transport.event_kind()`. |
108 | | - For v2, additionally constrain the filter to `author = mostro_pubkey` so the |
109 | | - Mostro reply is not confused with NIP-17 peer chat on the same kind. |
110 | | -- **Unwrap:** `parse_dm_events` calls `unwrap_incoming` instead of |
111 | | - `unwrap_message`, so it transparently handles whichever kind arrived. |
112 | | -- **Blast radius:** the ~12 command call sites of `send_dm` thread |
113 | | - `ctx.transport` through; no per-command logic changes. |
114 | | - |
115 | | -Acceptance: against a `transport = "nip44"` daemon, a full |
116 | | -`new-order → take → add-invoice → fiat-sent → release` round-trips; against a |
117 | | -gift-wrap daemon, behaviour is unchanged. This is the phase that lets us test |
118 | | -the daemon's Phase 2 anti-spam gates. |
| 96 | +### Phase 2 — Transport selection (v2 capability) — IMPLEMENTED |
| 97 | + |
| 98 | +Teaches the CLI to send and receive on either transport, selected explicitly. |
| 99 | + |
| 100 | +- **Config:** a `--transport <gift-wrap|nip44>` flag (`-t`) that sets a |
| 101 | + `TRANSPORT` env var, resolved via `messaging::parse_transport_env()` into |
| 102 | + `Transport` (default `gift-wrap` — wire-identical to today). This mirrors how |
| 103 | + `POW` / `SECRET` are already read from the environment rather than threaded |
| 104 | + through every call site, so `send_dm`'s signature (and its ~14 callers) is |
| 105 | + untouched. Mirrors the daemon's `[mostro] transport` knob. |
| 106 | +- **Send:** the Mostro-protocol path of `send_dm` / `send_plain_text_dm` goes |
| 107 | + through a new `publish_wrapped` → `wrap_message_with(transport, …)`, |
| 108 | + replacing the hard-wired `wrap_message`. The NIP-17 peer-chat path |
| 109 | + (`to_user`) is untouched. |
| 110 | +- **Receive:** `wait_for_dm` subscribes on `transport.event_kind()` (and its |
| 111 | + notification loop matches that kind). For v2 it additionally pins |
| 112 | + `author = mostro_pubkey` so the Mostro reply is never confused with NIP-17 |
| 113 | + peer chat on the same kind 14. |
| 114 | +- **Unwrap:** `parse_dm_events` gains a `mostro_protocol: bool`; when `true` it |
| 115 | + decodes via `unwrap_incoming` (dispatches on kind: 1059 / 14), when `false` |
| 116 | + it keeps the NIP-17 peer-chat path. All Mostro-reply / Mostro→user-DM call |
| 117 | + sites pass `true`; the one peer-chat listing call passes `false`. |
| 118 | + |
| 119 | +Tests: `Transport::from_str` → `event_kind` mapping, and a |
| 120 | +`wrap_message_with(Nip44Direct) → unwrap_incoming` roundtrip (kind 14, author = |
| 121 | +trade key, message round-trips). Full suite green; clippy + fmt clean. |
| 122 | + |
| 123 | +Known gap (deferred to Phase 3): the `get-dm` **historical listing** filter |
| 124 | +(`create_filter` for the `DirectMessages*` kinds) still hard-codes gift wrap, |
| 125 | +so listing past Mostro DMs on a v2 node returns nothing. The interactive |
| 126 | +request/response path (the one that exercises the daemon's anti-spam gate) is |
| 127 | +fully v2. |
| 128 | + |
| 129 | +Acceptance: against a `transport = "nip44"` daemon, run the CLI with |
| 130 | +`--transport nip44` and a full `new-order → take → add-invoice → fiat-sent → |
| 131 | +release` round-trips; against a gift-wrap daemon (default), behaviour is |
| 132 | +unchanged. This is the phase that lets us test the daemon's Phase 2 anti-spam |
| 133 | +gates. |
119 | 134 |
|
120 | 135 | ### Phase 3 — Capability auto-detection + docs/UX — PENDING |
121 | 136 |
|
| 137 | +- Make the `get-dm` historical-listing filter transport-aware |
| 138 | + (`create_filter` for the `DirectMessages*` kinds: kind 14 + `author = |
| 139 | + mostro_pubkey` on v2), closing the Phase 2 known gap. |
122 | 140 | - Read the node's `protocol_versions` tag from its kind-`38385` info event |
123 | 141 | (same fetch path as the existing `pow` probe) and, when `--transport` is not |
124 | 142 | given, auto-select the matching transport — warning on a mismatch |
|
0 commit comments