- Crate/binary: nostr-manager-backend -> keynectr
- Data directory: nost-feed-manager -> keynectr, migrated automatically
on first data_dir() call (existing vaults, settings and backups move)
- Electron extraResources/spawn path, executableName, productName,
window title and CLI usage strings updated to match
- Deliberately unchanged: crypto.rs KDF verifier string, so previously
encrypted vault backups remain decryptable
Verified live: existing vault with two profiles migrated to
~/.local/share/keynectr and loads correctly.
set_profile_picture and publish_profile_metadata were rejected by the
renderer-method gate added in the 2026-08-21 hardening ('rejected renderer
method' in the log), so the GUI buttons could never reach the backend.
Also allow delete_profile / undo_delete from the deletion feature, which
were missing from the list as well.
Profiles created in the app never published a kind 0 metadata event, so
clients like Iris and Yakihonne showed generated petnames ("evil iguana")
or a truncated npub instead of the user's chosen name.
- Publish kind 0 metadata (name/display_name) automatically on creation
- Add "Publish name" action (GUI button + publish-name CLI) for existing
profiles, with a per-relay success/failure report
- Add profile pictures: optional picture URL persisted in the vault,
set via GUI modal (URL paste or nostr.build upload), set-picture CLI,
and included in the published metadata; avatars render it in-app
- Run metadata publishing on its own thread so sync and async callers
never nest tokio runtimes
- Expose undo_history in the state view and fix typecheck errors left by
the unfinished delete/undo work (variants, icon, null-safety)
- Use offline relay settings in tests: Settings::default() points at real
relays, which tests were silently publishing to (suite: 126s -> ~3s)
Verification: cargo test 96 passed; clippy/fmt/build clean. Frontend:
78 tests, typecheck, lint, format, vite and electron builds all pass.
- src/feed.rs: contact_feed + contact_pubkeys fetch the active profile's
kind 3 contact list and aggregate notes only from those authors;
aggregate_for + FeedBuilder accept an optional author whitelist
- IPC: FeedGet accepts contacts_only, resolves the active profile npub
- CLI: feed --contacts [limit] filters to the active profile's contacts
- Frontend: Feed screen Everyone/My contacts toggle, scope-aware empty
states, feedGet(limit, contactsOnly) threading
- Tests for author filtering and the contacts scope in feed.rs and
FeedScreen.test.tsx
- src/feed.rs: aggregate recent kind 1 notes from enabled relays into a
newest-first, de-duplicated feed using a throwaway identity
- IPC: FeedGet; CLI: feed [limit]; frontend: Feed screen + nav + tests
- README: mark feed aggregation as shipped
Add a remote-signer (bunker) role so other Nostr apps can delegate
signing to this app's active profile keys via nostrconnect:// links.
Backend: new src/signer.rs implementing the NIP-46 protocol (kind 24133
events encrypted with NIP-44 v2 conversation keys). It parses
nostrconnect:// connect URIs, spawns an async task in the serve process
that reads relay requests, auto-approves once the handshake completes,
signs delegate events, and publishes responses. Exposes status, connect,
and disconnect via IPC and CLI (signer status / signer connect).
Other: ipc.rs serve/handle now share Arc<Mutex<App>>; main.rs adds the
signer CLI commands; Cargo.toml enables nostr nip46 feature.
Frontend: new Signer screen (nav item + sidebar entry with key icon)
to paste a nostrconnect:// link, connect/disconnect, and show the
connected peer and relays; wires signer_connect/_disconnect/_status
through api.ts and AppProvider; adds tests and test mocks.
- profiles::reveal_secret_key returns a key in hex and nsec1... forms, gated on
an unlocked vault (VaultLocked when encrypted + locked)
- IPC: reveal_secret_key method; error replies now carry a machine-readable
code field (ErrorKind as snake_case, e.g. vault_locked)
- CLI: show-secret <npub> prompts for the vault password when locked
- GUI: 'Secret key' button per profile card opens a modal showing hex + nsec
with copy buttons; locked vaults ask for the password inline before revealing
- Tests: Rust (reveal plaintext/encrypted/locked) and Vitest (reveal flow,
lock-then-unlock), all green