aboutsummaryrefslogtreecommitdiffstats
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* The wizard waits out a signer login; a picked recipient shows its work, and ↵Adam Soltys2026-08-084-30/+108
| | | | | | search answers from memory before the network Co-Authored-By: Claude Fable 5 <[email protected]>
* Profiles wear their latest notes, each one zappable; a zap with no ark ↵Adam Soltys2026-08-0810-45/+383
| | | | | | address to land on becomes a gift only their key can open Co-Authored-By: Claude Fable 5 <[email protected]>
* Boards show the server their funding tx, as mainnet now insistsAdam Soltys2026-08-052-1/+8
| | | | | Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M5kFodm9azZJVTQxnkDdKe
* hal speaks pver 5: preimages prove their size, and fees round up as oneAdam Soltys2026-08-057-54/+84
| | | | | | | | | | 0.6.0 servers require the new hashlock clauses (OP_SIZE 32 guard) for Lightning and rounds. New policies/transitions carry the v1 scripts and type bytes; _v0 variants keep old vtxos reconstructing and exiting. The retired third-party HTLC policy is dropped (upstream took 0x08). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M5kFodm9azZJVTQxnkDdKe
* Spending trusts its own ledger: gifts read persisted ark state, and Savings ↵Adam Soltys2026-08-054-5/+21
| | | | | | | keeps its pending line to itself Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M5kFodm9azZJVTQxnkDdKe
* The Nostr card owns its built-in account; the exported key opens this wallet ↵Adam Soltys2026-08-044-6/+84
| | | | | | | anywhere Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M5kFodm9azZJVTQxnkDdKe
* A wallet too small to renew warns before its coins expire; dust never diesAdam Soltys2026-08-044-2/+54
| | | | | | | | | | | | | | | | | | The warning: when the Spending balance minus round fee is under the 330-sat round minimum AND a vtxo enters the renewal window, auto-refresh can't save the coins — a wallet-screen notice (and a daily local notification, when permitted) says to receive any amount or spend before the deadline. New walletNotices feature hook renders under the balance card. The amnesty: sub-dust vtxos have no unilateral exit to protect, and regtest proves captaind keeps cosigning their spends past expiryHeight — even after the watchman claims the backing on-chain (tools/ark/expired-dust-test.js). Only hal's own receive validation stood in the way; it now exempts sub-330 vtxos from the expiry check. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
* Ark gifts go down to 1 sat; negative amounts can't OOM the encoderAdam Soltys2026-08-043-1/+14
| | | | | | | | | | | | | | | | | | Regtest-proven (tools/ark/dust-gift-test.js): the ASP cosigns all-dust arkoor sends, so a sub-dust bearer vtxo sweeps to its claimer fine, and dust folds into rounds alongside bigger siblings. The 330-sat gift floor guarded a failure that can't happen — dropped to 1 sat. The experiment also caught a live bug: refresh() of a balance smaller than the round fee computed a negative output amount, and pbWriter's varint sign-extends negatives into an infinite loop — auto-refresh would OOM the tab of any wallet too small to renew. varint now throws on negatives and refresh() refuses cleanly, before marking coins pending, when balance minus fee is under the server's 330-sat output minimum. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
* More options also points at Savings for a plain on-chain addressAdam Soltys2026-08-043-2/+10
| | | | | | | | | Not a pane of its own: a regular Bitcoin address means receiving to Savings, so the entry switches the account selector over and lets the savings receive view show its fresh address. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
* The chat log follows its bottom edge through viewport resizesAdam Soltys2026-08-041-0/+16
| | | | | | | | | | | The keyboard shrinks the viewport-sized chat card: the composer stayed on screen but the log kept its old scroll offset, hiding the newest messages. Re-stick on every viewport resize and on composer focus — unless the reader has deliberately scrolled up, which msgStick already remembers. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
* One More-options link replaces the BOLT 12 link on ReceiveAdam Soltys2026-08-042-16/+137
| | | | | | | | | Behind it: a one-time BOLT 11 invoice (minted by the ASP), the reusable BOLT 12 offer flow, the wallet's raw ark address, and the CLINK offer code — each on its own pane so only one scannable code shows at a time. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
* Seeing the message list clears the badge; rows keep their own dotsAdam Soltys2026-08-042-9/+49
| | | | | | | | | | The header dot cleared only per-conversation, so a channel or thread you never clicked into kept it lit forever. Now the list screen has its own watermark: visiting it answers the header dot, while each DM and community row shows an unread dot of its own until actually opened. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
* The npub default never displaces a custom nameAdam Soltys2026-08-041-1/+9
| | | | | | | | | | | adoptIdentity claimed the identity npub whenever the local name differed — and claim() releases the previous name, so a nostr login could delete the user's custom address from the registrar (it did). It now asks the registrar first and yields to any custom name. The registrar's /pubkey lookup also matches manager keys now and prefers real names over npub defaults, so restored wallets find their name again. Co-Authored-By: Claude Fable 5 <[email protected]>
* The wizard offers a profile, it doesn't overwrite oneAdam Soltys2026-08-042-4/+15
| | | | | | | | | Finishing the avatar step published name = the payment-address name and the default punk under the user's real nostr identity — renaming (and re-facing) profiles that already existed. Wizard-suggested fields are fill-only now: they land only where the profile has nothing. Co-Authored-By: Claude Fable 5 <[email protected]>
* No logo in the wizard; every step has a way back insteadAdam Soltys2026-08-041-5/+8
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* The logo rides along on every wizard stepAdam Soltys2026-08-041-1/+5
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* The wizard can no longer trap anyoneAdam Soltys2026-08-042-2/+11
| | | | | | | | | Publishing the profile on the avatar step is best-effort now — a signer that can't sign (a sleeping phone bunker) skips it with a toast instead of erroring the Continue button forever. And once a wallet exists, the logo leads home even out of a resumed wizard. Co-Authored-By: Claude Fable 5 <[email protected]>
* Five conversations, then 'show all' — communities stay in reachAdam Soltys2026-08-042-1/+14
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Your own npub stays out of the profile editorAdam Soltys2026-08-041-1/+3
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Avatars stop flashing everywhere: backgrounds, not <img>Adam Soltys2026-08-043-2/+7
| | | | | | | | A recreated <img> decodes async — one blank frame per render, and boot renders in bursts. A CSS background paints synchronously from cache, so the profile page, chat rows, and send candidates all hold steady now. Co-Authored-By: Claude Fable 5 <[email protected]>
* The bio edits in a textarea, and only appears once on your own profileAdam Soltys2026-08-041-5/+7
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* The logo leads home from the name page tooAdam Soltys2026-08-041-0/+1
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Copy joins the pencil inside the address boxAdam Soltys2026-08-043-16/+24
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Choosing a name gets a page of its ownAdam Soltys2026-08-042-7/+19
| | | | | | | The pencil opens a dedicated screen — no balances, no tabs — wired into the history stack like the other sub-pages. Co-Authored-By: Claude Fable 5 <[email protected]>
* Pencil in a boxAdam Soltys2026-08-041-1/+1
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* A proper pencilAdam Soltys2026-08-041-1/+1
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* A quieter pen inside the address box; the header avatar stops flashingAdam Soltys2026-08-043-6/+27
| | | | | | | | The avatar img was recreated on every render — boot's render bursts made it flash; there is exactly one header avatar, so the node is reused until the profile actually changes. Co-Authored-By: Claude Fable 5 <[email protected]>
* The name is edited where the name is — a pencil by the addressAdam Soltys2026-08-041-7/+12
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Offer the custom-name form right on the Receive paneAdam Soltys2026-08-041-0/+6
| | | | | | | Anyone still on the npub-shaped default sees their address here, not in the collapsed corner of Settings where the claim form lived. Co-Authored-By: Claude Fable 5 <[email protected]>
* Claim with the login identity, so a migrated name can come homeAdam Soltys2026-08-041-1/+5
| | | | | | | | | | The registrar now lets a migrated coinos user's nostr identity (re)take its own name — migration could land the claim in whatever wallet ran it, stranding the name there. The claim form signs with the (re)attached login identity when there is one; the wallet key alone could never prove the takeover. Co-Authored-By: Claude Fable 5 <[email protected]>
* A restored login ends the wizard instead of stalling in itAdam Soltys2026-08-042-0/+10
| | | | | | | | | | Signing in mid-wizard with a key whose wallet was restored left you on the sign-in step: the back-button hold matched the restored account and blocked the auto-advance. A login now clears the hold explicitly — and a restored wallet skips the rest of onboarding entirely; it was already onboarded wherever it came from. Co-Authored-By: Claude Fable 5 <[email protected]>
* Never mistake a failed backup lookup for 'no wallet yet'Adam Soltys2026-08-042-11/+29
| | | | | | | | | | | | Signing in with a key whose wallet backup exists on relays could still land in 'create a new wallet' when the lookup failed (relays unreachable, signer decrypt denied) — and confirming would have replaced the real backup on any relay the new one reached. Absence is now only believed when a relay actually answered; decrypt failures surface as errors; and the create path takes one last look and adopts a backup that surfaces rather than clobbering it. Co-Authored-By: Claude Fable 5 <[email protected]>
* Reword the migrate linkAdam Soltys2026-08-041-1/+1
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Back and Skip become a button row; the coinos link says what it doesAdam Soltys2026-08-042-3/+4
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* A way back from the username stepAdam Soltys2026-08-041-3/+9
| | | | | | | | | Back from username (and sign-in) holds the auto-advance for the wallet you backed away from, so welcome doesn't bounce you straight forward; Get started then continues with the already-minted wallet instead of minting another. Co-Authored-By: Claude Fable 5 <[email protected]>
* Park the send field above the phone keyboard; wizard whenever walletlessAdam Soltys2026-08-042-6/+27
| | | | | | | | | | | | The recipient candidate list was hiding under the on-screen keyboard: scroll the field to the top on focus and when fresh candidates land, give the list scroll room to get there, and let the keyboard resize the viewport (interactive-widget) so the scroll has somewhere to go. The wizard now shows whenever the device has no wallet — the one-time onboarded flag is gone; deleting every wallet brings the wizard back. Co-Authored-By: Claude Fable 5 <[email protected]>
* Drop the BOLT 12 explainer blurbAdam Soltys2026-08-042-2/+0
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* A refresh mid-wizard resumes the step it was onAdam Soltys2026-08-042-5/+19
| | | | | | | | | | The wizard mints the wallet on its first step, so 'an account exists' stopped meaning 'wizard done' — reloading dropped you into the half-set-up wallet. Persist the current step until the wizard finishes. Also trims the balance coach-mark copy. Co-Authored-By: Claude Fable 5 <[email protected]>
* Keep the punks carousel where you left it, and on the pageAdam Soltys2026-08-042-2/+17
| | | | | | | | | A background repaint rebuilt the strip at scrollLeft 0 mid-swipe; render() now carries scroll positions across the swap the same way it carries focus. The onboarding column also sized itself to the strip's intrinsic width (auto margins defeat flex stretch), overflowing phones below ~450px. Co-Authored-By: Claude Fable 5 <[email protected]>
* Sign avatar uploads — nostr.build stopped taking them bareAdam Soltys2026-08-041-1/+11
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Paste lives in the field; the footer fits; claiming a name comes firstAdam Soltys2026-08-043-24/+57
| | | | | | | | | | | | | | | | | | | | | | | | | | Paste, on the import and load-seed screens, was a bordered box floating beside a small label — heavier than the label, detached from the field it fills. It now sits inside the textarea, and only while that textarea is empty: the only time it's wanted, and the only time it can't cover what you typed. It's toggled on the node rather than through render(), since re-rendering a textarea per keystroke rebuilds it under the caret. Beside a one-line input (Send) the old placement was right and is untouched. The footer measured 100dvh, which on a phone can resolve to the tall viewport at first paint and leave the language picker just below the fold. svh is the one that fits with the address bar showing. Short screens also tighten their padding, which buys back the ~50px the create/import screen was overflowing at 375x553. And the wizard no longer asks every new user whether they have an old coinos.io account before letting them have a name. Claiming the name is the step; the people who do have an old account know it, and say so with a link. That screen is a statement now, not a question they just answered. The npub-shaped default address is no longer offered as a button — a plain skip goes past without showing anyone that. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Put the ostrich on the sign-in buttonAdam Soltys2026-08-041-1/+5
| | | | | | | | | Same construction as the sign-in button on the unlock screen — .btn-block forces display:block, so the flex centering lives on an inner wrapper rather than the button. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* One question fewer on the way in, and an 'or' that means itAdam Soltys2026-08-044-28/+27
| | | | | | | | | | | | | | | | | | | | | The sign-in screen stacked 'Connect a signer app' directly above a bunker/nsec field, which reads as two steps rather than two ways in. A divider says which it is. The wizard's second step asked whether you have a nostr account, then sent you to a screen that asks the same thing. Step one now offers both paths directly — Get started, or sign in with Nostr — and the middle step is gone, along with its strings. The welcome blurb goes too: the screen is one decision, and prose above it is something to read before you can make it. The footer sinks to the bottom of the window rather than trailing the content up the page. #app is a full-height column now; the chat card sizes itself against the viewport, so the layout test covers it at three sizes. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Offer a password the first time you lockAdam Soltys2026-08-042-9/+41
| | | | | | | | | | | | | | | | | | | | | Locking with no password locks nothing — the wallets sit on the device under an empty one and reopen with a tap. So the first deliberate lock now asks whether to set one, explaining plainly what happens if you don't. 'Not now' is a real answer, recorded, and never asked again: a wallet that nags is a wallet people stop reading. The offer rides the deliberate lock only. lock() is also where the idle timer, the last-wallet-removed path and boot-after-expiry land, and a password form appearing because you went to lunch is a different app than the one you left. Two subtleties worth naming: the offer is set after lock()'s ui reset block, which clears ui.pw and had been swallowing it; and taking the offer re-enters lock(), which now finds a password and lands on the unlock screen instead of the wallet list. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Call it 'Lock wallet', because that is what it doesAdam Soltys2026-08-0321-40/+21
| | | | | | | | | | | | | | | | 'Logout' promises a return to a fresh app with nothing of yours left on it. This closes the open wallet and keeps everything saved, which is why it read as interchangeable with 'Clear all' — the one that really does send you back to the beginning. Renamed via a new key rather than rewording the old one: nineteen locale tables carry their own word for 'Logout' and t() prefers the locale's value, so reusing the key would have kept the wrong meaning in every language but English. The dead key is dropped from those files; they fall back to English until translated. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Logout shouldn't ask for a password nobody setAdam Soltys2026-08-031-4/+16
| | | | | | | | | | | | | | | | | | | | | | | Wallets save themselves to this device as soon as you open one, encrypted under an empty password unless you choose one. Logging out still sent you to 'Unlock saved wallets — enter your password', which asks for something that doesn't exist and makes logout look like it did something drastic. It didn't: logout only drops the keys from memory, and 'Clear all' is the one that deletes. With no password, logout now returns to the wallet list — honest, since nothing is protecting those wallets and a blank prompt protects nothing. With a password set it prompts exactly as before. Fixed underneath: mergeVaultList derived the comparison xpub with accountXpubFor's mainnet default, so on any other network it never matched the stored one and every unlock re-added the same wallet as a fresh entry — visible as the same wallet listed twice, once watch-only. The seed-mismatch checks in 'load recovery phrase' had the same default and would have rejected the correct seed on testnet. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* The unread dot holds stillAdam Soltys2026-08-031-2/+4
| | | | | | | | | | | | | | | It looked like the dot was flickering on and off after a refresh. It wasn't: measured over the first twelve seconds it appeared once and never went away, while its entrance animation started seven separate times. render() rebuilds the whole DOM, so the pop replayed on every repaint. A dot that means 'someone is waiting' has nothing to animate about, so the animation is gone rather than gated. tools/unread-dot-test.js counts animation starts against real appear/disappear transitions, so a future entrance effect here fails instead of shipping as a flicker. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* The chat window fits the screen, and the header stops asking questionsAdam Soltys2026-08-033-22/+48
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The message log had a fixed 62vh height, so the card was head + panels + log + composer tall and the input fell off the bottom of the screen. The card is now sized to the viewport and the log is the only part that flexes: opening the invite or member panel shrinks the scroll area instead of pushing the composer out of reach. Three header changes, all the same idea — don't show a control for a choice nobody is making: '+' becomes 'Add person', because a plus sign doesn't say what it adds. A lone channel isn't named at all. '#general' next to a composer that says 'Message #general' points at a choice of one; several channels become a select, which is what a choice looks like. The new-channel field hides behind a 'New channel' button. Sitting open right after you create a community, it reads as something you're supposed to fill in. tools/chat-layout-test.js holds the line at three viewport sizes with both panels open, and covers the header behaviour through actually adding a second channel. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Drop the 'signer reconnected' toastAdam Soltys2026-08-033-5/+4
| | | | | | | | | | A dark pill floating at the bottom of the screen reads as a stray button under the footer, and it was saying something the page already showed: the badge flips to connected and the reconnect controls disappear. Failures still surface — those go in the card, where the problem is. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Give the nostr settings page a way to reconnectAdam Soltys2026-08-033-19/+44
| | | | | | | | | | | | | | | | | | | | | The app could tell you your signer wasn't connected and then send you somewhere with nothing to click: once an account was linked, the nostr card showed only an npub. It now shows connected/not connected, says what's missing, and offers the same signer options as signing in — refusing a different account rather than quietly swapping identities, since this is a reconnect and not a login. Pasted keys go back to not being persisted at all. Storing one would have survived a reload, but the UI promises a pasted key is used once and never kept, and that promise is worth more than saving a paste; those logins reconnect from this card like any other. The chat banner now tracks the live signer alone. The flag that suppressed it after a reconnect would also have hidden a later genuine disconnect. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi