Phase 2 of docs/npub-sign-in.md: the library half is lightning-kmp-app 01962f3 (claude/nostr-credentials), bumped in here; this is the app half. nostr-keys.dat becomes nostr-credentials.dat, one typed entry per public key -- a secret, or only the public key -- so that a profile signed in to read-only and the same profile with its nsec pasted later are one entry in one file. StoredIdentity gains NostrPublic, whose id is the one its secret would have (hash160 of the x-only key), and merge reads the typed map. It keeps the one precedence it needs: a public entry for a key a seed already derives lists the wallet only, which is the state the seed writer's two-file upgrade can leave behind if it dies between its writes. A secret for a seed's key is still listed twice, as before -- that is a duplicate the writers refuse, not a state the listing hides. IdentityWriter: writeNostrPublicKey beside writeNostrKey, both refusing a duplicate by public key against the seeds and the credentials, with the one exception that is the point of the file -- the nsec of a key held read-only is not a duplicate, since the device does not have that secret. writeNostrKey replaces the public entry with a secret one in a single write, under the id it already had, so the read-only identity's preferences are the ones the signing identity keeps. writeMnemonic has to span two files for the same upgrade and removes the credential first, then writes the seed: a crash between the two loses the read-only identity, which the npub pasted again restores, rather than listing one npub twice under two ids. forgetNostrKey becomes forgetNostrCredential and removes an entry of either kind; NotABareKey becomes NotACredential and still means a mnemonic. The startup screen's third branch is here rather than in Phase 3 because StoredIdentity is sealed and the compiler asked for it: a read-only identity is active the moment it is read, as the nsec one is. NostrSecretViewModel reads the secret entry and answers a public one with "no key for this identity", which the screen it belongs to will never show once Phase 5 hides the row. Tests: the writer's upgrade in both directions -- the nsec of a read-only key accepted under the same id, the npub of a secret refused -- and forget of either kind; merge listing all three kinds, the shared id of a public key and its secret, and the seed-over-public precedence. Replayed onto Mantra by docs/curated-to-mantra.md: gitlink -> 84cc44c: upstream pinned 01962f3, a branch commit since rebased onto the library's master as 84cc44c with an identical tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Pulled-From: curated/curated@5efeae769f
This is a Kotlin Multiplatform project targeting Android, iOS, Desktop (JVM).
-
/composeApp is for code that will be shared across your Compose Multiplatform applications. It contains several subfolders:
- commonMain is for code that’s common for all targets.
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name. For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app, the iosMain folder would be the right place for such calls. Similarly, if you want to edit the Desktop (JVM) specific part, the jvmMain folder is the appropriate location.
-
/iosApp contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform, you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
Build and Run Android Application
To build and run the development version of the Android app, use the run configuration from the run widget in your IDE’s toolbar or build it directly from the terminal:
- on macOS/Linux
./gradlew :composeApp:assembleDebug - on Windows
.\gradlew.bat :composeApp:assembleDebug
Build and Run Desktop (JVM) Application
To build and run the development version of the desktop app, use the run configuration from the run widget in your IDE’s toolbar or run it directly from the terminal:
- on macOS/Linux
./gradlew :composeApp:run - on Windows
.\gradlew.bat :composeApp:run
Build and Run iOS Application
To build and run the development version of the iOS app, use the run configuration from the run widget in your IDE’s toolbar or open the /iosApp directory in Xcode and run it from there.
Learn more about Kotlin Multiplatform…