The filter JSON in SpellDetailRenderer was missing since/until
fields when they were in relative format (e.g., "7d", "now").
This happened because decodeSpell only adds these fields to
the filter object when they're unix timestamps.
Now we extract the raw since/until values from event tags and
include them in a displayFilter object for the JSON viewer,
ensuring users see the complete filter regardless of format.
The command preview already worked correctly since it uses
the reconstructed command string which includes these values.
- Remove text-sm from MediaPlaceholder and EventPlaceholder to inherit parent font size
- Add options to hide media and event embeds in HighlightRenderer preview
- Ensures placeholders like [image], [note] match surrounding text size
- Add VoiceMessageRenderer for kinds 1222 (voice message) and 1244 (voice reply)
- Add compact preview components with mic icon for voice messages
- Support legacy NIP-71 video kinds 34235/34236 via existing video renderers
- Add fallback URL tag parsing for video events
- Replace music note icon with mic icon for audio embeds
- Remove border/padding from audio player for cleaner display
- Add kind metadata (names, icons) for voice and legacy video kinds
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add -v, --view <list|compact> flag to req command
- Remove UI toggle controls from ReqViewer header
- View mode is now set via command flag instead of runtime toggle
- Update man page with new flag documentation and example
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Redesign SpellbookDropdown with clear status indicators (ownership, storage)
- Add SpellbookStatus component showing you/other and local/published/network
- Enhance activeSpellbook type with source, localId, isPublished fields
- Fix PublishSpellbook action to properly yield events (caller handles side-effects)
- Add k tags extraction from REQ windows for kind-based filtering/discovery
- Update terminology from "Layout" to "Spellbook" consistently
- Add comprehensive tests for k tags and source tracking
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem:
- Function signature was accidentally changed to curried pattern
- Tests were failing because they expected async generator pattern
Solution:
- Restore async function* signature that takes hub and options
- Matches test expectations and existing usage patterns
- Linter also fixed property destructuring in spellbook-storage
Tests:
- ✅ All publish-spellbook tests passing (14/14)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem:
- Saving active spellbooks was creating duplicates each time
- No deduplication logic for spellbooks with same slug + pubkey
Solution:
- Add findExistingSpellbook() to match by slug and pubkey
- Update saveSpellbook() to detect and update existing spellbooks:
* For local-only: match by slug (no pubkey)
* For published: match by slug AND pubkey
* For updates: use provided ID
- SaveSpellbookDialog now passes existing ID in update mode
Testing:
- Added comprehensive spellbook-storage.test.ts
- Tests verify deduplication logic (requires jsdom environment)
- Existing tests still pass (14/14 for publish-spellbook)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sharing Enhancements:
- Install qrcode library for QR code generation
- Create ShareSpellbookDialog with tabbed interface
- Support multiple share formats: Web URL, naddr, nevent
- QR code generation and download for each format
- Quick copy buttons with visual feedback
- Integrated into SpellbookDetailRenderer
Network Discovery:
- Add "Discover" filter to browse spellbooks from other users
- Query AGGREGATOR_RELAYS for network spellbook discovery
- Show author names using UserName component
- Conditional UI: hide owner actions for discovered spellbooks
- Support viewing and applying layouts from the community
Preview Route Polish:
- Loading states with spinner during NIP-05 resolution
- 10-second timeout for NIP-05 resolution
- Error banners for resolution failures
- Author name and creation date in preview banner
- Copy link button in preview mode
Conflict Resolution:
- compareSpellbookVersions() function in spellbook-manager
- ConflictResolutionDialog component for version conflicts
- Side-by-side comparison of local vs network versions
- Show workspace/window counts and timestamps
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Improve the preview route UX with better loading states, error handling, and metadata display. Add version comparison logic and conflict resolution dialog for handling local vs network spellbook conflicts.
Changes:
- Enhanced preview route in Home.tsx:
- Add loading state with spinner while resolving actor
- Add NIP-05 resolution timeout (10 seconds)
- Display error banner for resolution failures
- Show author name and creation date in preview banner
- Add copy link button to share spellbook easily
- Improve banner layout with metadata
- Add compareSpellbookVersions() in spellbook-manager.ts:
- Detects conflicts between local and network versions
- Compares timestamps, workspace counts, window counts
- Identifies newer version and content differences
- Returns structured comparison data
- Create ConflictResolutionDialog component:
- Side-by-side comparison of local vs network versions
- Shows metadata: timestamps, counts, author, publish status
- Clear explanation of resolution choices
- Accessible UI with proper button hierarchy
TypeScript compilation successful ✅🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactor PublishSpellbookAction from class-based to async generator pattern
following official applesauce-actions patterns. This provides better integration
with ActionHub and enables proper reactive event publishing.
Changes:
- Add publishEvent function to ActionHub with relay selection fallback strategy
(outbox relays → seen relays → error)
- Convert PublishSpellbookAction to PublishSpellbook async generator
- Update SaveSpellbookDialog and SpellbooksViewer to use hub.run()
- Add comprehensive test suite (14 tests covering validation, event creation,
slug generation, factory integration, and workspace selection)
- Improve error handling with specific error messages
- Add JSDoc documentation with usage examples
All tests passing ✅ (14/14)
TypeScript compilation successful ✅🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Implement smart banner visibility (only from client-side transitions)
- Add 'Apply to Dashboard' and 'Add to Library' to SpellbookDropdown
- Support updating layouts via standardized dialog
- Fix build errors and type mismatches
- Use ClickableEventTitle for spell and spellbook titles in all views
- Infer event kinds from spellbook windows and display KindBadges in feed/detail views
- Ensure consistent styling and navigation across spell/spellbook components
- Introduce activeGrimoireStateAtom to handle switching between persistent and temporary state
- Ensure setState and all logic callbacks are stable across re-renders
- Correctly type Jotai updaters to avoid implicit any errors
- Add temporaryStateAtom to track in-memory sessions
- Update useGrimoire to handle conditional state management
- Previews and Direct links now use temporary state, preserving dashboard
- Add Apply and Discard logic to persist or revert temporary sessions
- Add activeSpellbook to GrimoireState
- Display active spellbook title in header with clear button
- Add 'Update Layout' and 'Save as new' to SpellbookDropdown
- Highlight active spellbook in dropdown list
- Add 'Manage Spells' link to dropdown
- Refine dropdown styles (muted hover, no accent color)
- Separate preview mode to /preview/:actor/:identifier
- Direct links (/:actor/:identifier) now load layout immediately
- Add SpellbookDropdown to header center for quick layout switching
- Restore accidentally deleted wallet-related files
- Remove obsolete SpellbookLoader.tsx
- Update spellbook icon to BookHeart across the app
- Implement Preview mode with routing /:actor/:identifier
- Add Preview banner in Home component with Apply/Discard actions
- Add Preview and Share buttons to Spellbook renderers
- Clean up unused imports
- Ensure SaveSpellbookDialog passes content to PublishSpellbookAction
- Refactor SpellDialog to use PublishSpellAction instead of manual logic
- Ensure published events are added to local EventStore for immediate UI update
- Clean up unused imports and variables in SpellDialog
- Repository name in both feed and detail views now links to the repository (kind 30617)
- Uses same link styling as issues: cursor-crosshair, underline decoration-dotted
- Fetches repository event to display proper name instead of identifier
- Only "pushed <commit>" part opens the state event itself
- Repository link opens in new window using addWindow("open")
Implement renderers for NIP-34 repository state announcements:
- Add helper functions in nip34-helpers.ts to parse HEAD refs, branches, and tags
- Create RepositoryStateRenderer for compact feed view showing push notifications
- Create RepositoryStateDetailRenderer for detailed view with all refs
- Register both renderers in the kind registry
Feed view shows: "pushed <commit> to <branch> in <repo>"
Detail view shows: HEAD info, all branches, all tags with copyable commit hashes
Set up automated quality assurance checks:
- Lint: runs ESLint
- Build: runs TypeScript + Vite build
- Test: runs Vitest in CI mode
All jobs run in parallel on push/PR to main/master.