chore: expand TODO into a roadmap
Rust / build (macos-latest, stable) (push) Canceled after 0s
Rust / build (ubuntu-latest, stable) (push) Canceled after 0s
Rust / build (windows-latest, stable) (push) Canceled after 0s

This commit is contained in:
2026-10-09 08:38:53 +07:00
parent 4d8aa97e24
commit 7878feb236
2 changed files with 49 additions and 95 deletions
+49 -2
View File
@@ -1,4 +1,51 @@
# TODO
- Profile panel: the sidebar user menu's "View profile" opens an empty placeholder panel; build the actual profile view.
- Relays panel: the sidebar user menu's "View relays" opens an empty placeholder panel; build the actual relays view.
## UI
- [ ] Add profile panel, replace the empty placeholder behind the sidebar user menu's "View profile".
- [ ] Show the user's profile (metadata, avatar).
- [ ] List their published repositories.
- [ ] List their relays.
- [ ] Show their recent activity (issues, PRs, patches, comments).
- [ ] Add relay panel, replace the empty placeholder behind the sidebar user menu's "View relays".
- [ ] Configure lookup relays.
- [ ] Configure outbox and inbox relays.
- [ ] Configure bootstrap relays.
- [ ] Configure grasp servers.
## Maintainer workflow
- [ ] Add close issue / close PR / mark applied-merged actions, `RepoStore::set_status` exists but is only called for drafts.
- [ ] Carry `applied-as-commits` / `merge-commit` tags on status events (nak publishes these).
- [ ] Wire up `Repo::apply_patch` (`git am`) so patches can be applied in-app.
## Repository management
- [ ] Set `maintainers` when announcing a new repo, multi-maintainer repos cannot be created today and maintainer support is read-only.
- [ ] Re-publish announcements to relays that missed the latest version (nak `git sync` reconciles this).
- [ ] Support creating fork announcements (upstream `u` tag), currently parse-only.
- [ ] Publish `web` urls and hashtags; currently parse-only.
## Push
- [ ] Add a fast-forward check and a force option (nak refuses non-FF without `--force`), today it relies entirely on grasp CAS.
- [ ] Allow NIP-34 maintainers to push, not just the owner.
## Contributor workflow
- [ ] Check PRs out into a worktree to build/test, diffs are view-only in the mirror (ngit `pr checkout`, `pr/` branches).
## Identity
- [ ] Support multiple identities with non-destructive switching (ngit: multi-account keyring, aliases, `--signer`); today sign-out deletes the single key.
## Ecosystem
- [ ] Private repository support (GRASP-08, encrypted private relay lists).
- [ ] Git remote helper so plain `git clone/push` with `nostr://` urls works outside the app.
## Minor
- [ ] Open a repo by address (naddr, `npub/identifier`, NIP-05), discovery is currently Explore/Sidebar only.
- [ ] Per-grasp-server announcement freshness view (nak `git status`).
- [ ] Publish PR labels, they are always empty today.
-93
View File
@@ -1,93 +0,0 @@
# Nostr sync detection plan
Detect when a local repository has diverged from its NIP-34 state on Nostr
(kind 30618) and suggest syncing when the app opens.
Scope: repositories already initialized on Nostr (NIP-34 binding present).
Purely local repositories without a binding do not get this feature.
Scenario: the repository is initialized on Nostr and also pushed to Gitea.
Work continues locally and is pushed to Gitea only, so the Nostr state falls
behind. Signed should notice the difference on startup and offer to sync.
## Prior art
- nak (`git.go`): `nak git sync` fetches the latest kind 30617/30618 events
from relays and writes them to local refs (`refs/nip34/state/*`); push and
pull then compare against those refs with ordinary git machinery
(e.g. `merge-base --is-ancestor` for fast-forward checks).
- ngit-cli: the same idea — the Nostr state is materialized as git refs in the
repository, then ahead/behind comparison applies.
## Current state of the codebase
| Piece | Location | Status |
|---|---|---|
| NIP-34 binding detection | `Repo::nip34_binding()` in `signed_git/src/repo.rs` | done |
| Full Nostr state (refs + HEAD) | `RepoState::parse` in `signed_core/src/state.rs` | parsed, but `RepoStore` keeps only `head` and drops the refs |
| Push-to-Nostr flow | `Backend::push_repo_from` / `RepoStore::push_checkout` / `push_repository` | done; stages the state event on grasp relays, pushes objects, broadcasts 30618 |
| "Ahead of origin" detection | `CheckoutsStore::checkout_push_status` — local branch vs `refs/remotes/origin/<branch>` | exists, but that is local vs Gitea, not local vs Nostr |
| UI suggestion surfaces | Sidebar unpushed badge (`SidebarPanel::refresh_unpushed`), push banner (`RepoDetailView::push_suggestion` / `render_push_banner`) | pattern exists for origin; nothing for Nostr |
Gap: nothing compares the local repository's refs against the Nostr
`RepoState` refs, and no "sync to Nostr" suggestion is based on that
comparison.
## Plan
### Phase 1 — Divergence computation in `signed_git`
Add a pure function in a new `sync.rs` module that takes local `ref_state()`
and the Nostr `RepoState.refs` and classifies each `refs/heads/*` ref:
```rust
pub enum RefSync {
InSync,
LocalAhead { ahead: usize }, // fast-forwardable push
RemoteAhead { behind: usize }, // Nostr has newer commits
Diverged { ahead: usize, behind: usize },
LocalOnly, // branch never published
RemoteOnly, // branch exists only on Nostr
}
pub struct RepoSyncStatus {
pub refs: Vec<(String, RefSync)>, // branch name -> classification
pub ahead_total: usize, // summary for badges
pub behind_total: usize,
}
```
Implemented with the existing `Repo::merge_base` and `commits_since` /
`commits_ahead` — no new dependencies.
### Phase 2 — Keep Nostr state refs and add a sync-status store in `signed_state`
1. `RepoStore`: store `state_refs: Vec<(String, String)>` (and the state event
timestamp) alongside `head` in `run_refresh` instead of discarding them.
2. New `SyncStatusStore` (following the `CheckoutsStore` pattern: global
entity, background compute, notify-on-change) that:
- watches own announcements (`RepoListStore` + `Backend::current_user`;
for repositories the user does not own, sync means PRs, which is out of
scope);
- reads the latest kind 30618 event per own repository from the Nostr LMDB
(`RepoListStore::sync_own_repo_states` already ensures those events are
synced);
- for each associated checkout (`CheckoutsStore::associations_of`)
computes `RepoSyncStatus` against the local refs on the background
executor;
- recomputes on app open, `BackendEvent::Synced` / `RepoUpdates` (state
kind), after a successful push, and on a slow poll (~60s, like
`PUSH_POLL`).
### Phase 3 — UI: suggest sync
- Sidebar: out-of-sync badge on own repository rows, reusing the `unpushed`
badge pattern, visually distinct (e.g. "N commits not on Nostr" tooltip).
- RepoDetailView: banner modeled on `render_push_banner`: "main is 3 commits
ahead of Nostr — Sync now", calling the existing `store.push_checkout(path)`.
## Open decisions
1. Badge placement: sidebar only, or sidebar plus repo-detail banner in the
first pass. Recommendation: both — the banner hosts the action button, the
badge drives the click.