Skip to content

Conversation

@tomymaritano
Copy link
Owner

Major release bringing cloud sync foundation, improved settings, error tracking, and Open Core licensing.
### New Features
Cloud Sync Foundation

  • API backend with Hono + Turso (Cloudflare Workers) - End-to-end encryption for synced notes
  • Conflict resolution UI
  • Magic link authentication

Git-Backed Notebooks

  • Auto-commit on note save
  • Commit history viewer
  • Per-notebook git toggle

Enhanced Editor

  • Wikilinks with heading anchors [[Note#Heading]]
  • Full-text search with FTS5 ranking
  • Improved markdown rendering

Settings Overhaul

  • New settings window with sections
  • Appearance settings (themes)
  • Editor preferences
  • Account & backup management

Infrastructure

Error Tracking & Analytics

  • Sentry integration for crash reporting
  • Offline-first analytics module
  • Plausible for marketing site

Design System

  • New @readied/design-system package
  • Shared tokens and components
  • CSS reset and typography

Open Source (Open Core Model)

  • MIT licenses for core packages
  • CONTRIBUTING.md guidelines
  • Community templates (issues, PRs)
  • CODE_OF_CONDUCT.md
  • SECURITY.md

Marketing Site Fixes

  • Fixed broken /blog links
  • Updated messaging for hybrid model (local-first + optional sync)
  • Corrected legal page dates
  • Added responsive tablet breakpoint

Version Changes

  • Root: 0.1.6 → 0.2.0
  • Desktop: 0.1.6 → 0.2.0

tomymaritano and others added 30 commits January 6, 2026 10:41
- Add Zustand-based settings store with schema versioning
- Add useTheme hook for dark/light/system theme + accent color
- Add new settings components (SettingGroup, SettingRow, controls)
- Add UpdatesSection for auto-update settings
- Enhance AppearanceSection with theme picker and color presets
- Add CSS variables for CodeMirror theme tokens
- Remove separate settings.html (unified window approach)
- Cross-window settings sync via IPC

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove all box-shadow effects for cleaner, flatter design:
- Context menus (NoteList, Tags)
- Modals (NotebookCreate, NotebookPicker, Settings)
- Panels (Actions, Backlinks)
- Editor header, toolbar, note-list
- Lightbox and global styles

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace LIKE queries with SQLite FTS5 for fast, ranked search:
- Add migration 008_fts5_index with FTS5 virtual table
- Triggers keep FTS index in sync on INSERT/UPDATE/DELETE
- Use bm25() for relevance ranking
- Prefix matching for partial word search ("mark" finds "markdown")
- Porter tokenizer for stemming support

Closes #67

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for heading anchors in wikilinks:
- Parse [[Note#Heading]] and [[Note#Heading|display]] syntax
- Store anchor in links table (migration 009_link_anchors)
- Pass anchor via data-anchor attribute to click handler
- Add heading utilities: extractHeadings(), headingToSlug()

Syntax now supported:
- [[Note]] - basic wikilink
- [[Note#Section]] - link to heading
- [[Note|alias]] - aliased link
- [[Note#Section|alias]] - heading with alias

Closes #68

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add core infrastructure for cloud sync:

## New Package: @readied/sync-core
- Types for sync entities, operations, conflicts
- SyncQueue for offline change management
- SyncEngine to orchestrate push/pull operations
- SyncClient interface for API communication
- Zod schemas for validation

## SQLite Migration (010_sync_fields)
- Add device_id, sync_version, last_synced_at to notes/notebooks
- Create sync_queue table for offline changes
- Create sync_metadata table for sync state

## Desktop Components
- syncStore (Zustand) for auth and sync state
- SyncStatusIndicator component
- LoginModal component for magic link auth

Backend API (Hono + Neon) to be implemented separately.

Refs #69

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document main/develop/feature branch structure
- Add workflow commands for starting work and creating PRs
- Include commit message conventions
- Add PR requirements checklist

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete backend integration with desktop app.

## Backend API (@readied/api)

New Hono-based API for Cloudflare Workers:
- Magic link passwordless authentication
- JWT tokens with refresh (15 min / 7 day)
- End-to-end encrypted sync (AES-256-GCM)
- Stripe subscription management
- Turso (libSQL) database

Security features:
- Rate limiting (10 req/min auth, 100 req/min sync)
- Stripe webhook signature verification
- OS keychain token storage (safeStorage)
- HMAC-SHA256 verification

Sync architecture:
- Pull: Download server changes with conflict detection
- Push: Upload local changes (documented, Phase 3)
- Conflict resolution UI
- Device tracking

## Desktop App Integration

Auth flow:
- Magic link email → Deep link verification
- Token storage with OS encryption
- Auth state management (Zustand)

Sync UI:
- Sync status indicator
- Conflict resolver component
- Manual sync trigger
- Auto-sync (5-min interval)

Settings:
- Account section (auth status, logout)
- Backup section (manual backup)
- Enhanced UI components

## Deployment

Multi-environment setup:
- Development: localhost:8787
- Staging: readied-api-staging.workers.dev
- Production: api.readied.app

## Documentation

- BACKEND_INTEGRATION_COMPLETE.md (2,700+ lines)
- API setup guide (SETUP.md)
- Deployment guide (DEPLOYMENT.md)
- Rate limiting docs
- Stripe webhooks docs

## Known Limitations

- Sync push not yet implemented (Phase 3)
- Conflict resolution is UI-only
- No local change tracking
- Monitoring postponed (Sentry)

## Breaking Changes

- None (new features, backward compatible)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Document architecture decision for product differentiation strategy.

Decision: Implement git-backed notebooks as core feature

Rationale:
- Differentiate from Inkdrop (no git) and Obsidian (weak sync)
- Justify $9/mo pricing (vs Inkdrop $4.99)
- Appeal to developers' trust in git
- Enable GitHub/GitLab collaboration
- Free backup via git push

Implementation approach:
- Opt-in per notebook
- Use isomorphic-git (pure JS, no binary)
- Auto-commit or manual commits
- Full history/diff/revert in UI
- Coexist with cloud sync

Consequences:
+ Unique selling proposition
+ Trust & security (user controls data)
+ Free backup & collaboration
- Complexity for non-technical users
- Performance overhead (.git storage)
- Sync complexity

Timeline: Phase 1 Sprint 2 (Semana 5-7)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements Semana 2 Sprint 1 (local change tracking + push functionality).

Database Changes:
- Migration 008: Add sync tracking columns to notes table
  - local_version: Increments on each local change
  - needs_sync: Flag (1=needs push, 0=synced)
  - last_synced_at: Timestamp of last successful sync
  - Triggers: Auto-mark notes as needs_sync=1 on INSERT/UPDATE
  - Index: Efficient querying of pending changes

Repository Methods (SQLiteNoteRepository):
- getPendingChanges(limit): Query notes where needs_sync=1
- markAsSynced(noteId): Mark note as synced after push
- markMultipleAsSynced(noteIds[]): Batch mark as synced
- getSyncStats(): Get count of pending notes + last sync time
- resetSyncTracking(noteId): Force re-sync (for conflict resolution)

Sync Service Enhancements:
- syncNow(): Now pulls AND pushes (was pull-only)
  - Gets pending changes from repository
  - Encrypts and pushes to server
  - Marks successfully pushed notes as synced
  - Handles push conflicts
- resolveConflict(): Real implementation (was stub)
  - "local" resolution: Marks note for push via resetSyncTracking()
  - "remote" resolution: Marks as synced to accept server version
- applyRemoteChange(): Marks notes as synced after pull
  - Prevents re-pushing notes just received from server

What Works Now:
✅ Edit note on Device A → marked needs_sync=1
✅ syncNow() pushes change to server
✅ Device B pulls change → marked as synced
✅ Conflict detection on push
✅ Manual conflict resolution (choose local or remote)

Next Steps (Semana 2 Sprint 2):
- Multi-device testing with 2 instances
- Test conflict scenarios
- UI for visual diff of conflicts

Related:
- Phase 1 Sprint 1 of execution plan
- Addresses critical sync blocker from audit
- Enables real multi-device sync (was read-only before)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Comprehensive testing guide for Semana 2 Sprint 1.

Includes:
- 4 test scenarios (basic, conflict, rapid edits, delete)
- Migration verification steps
- Manual sync trigger options
- Debug queries for local + server
- Expected behavior documentation
- Success criteria
- Test log template

Ready for multi-device testing phase.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds visual diff highlighting and dual view modes to ConflictResolver.

Features:
- Dual view modes: Side-by-side and Unified diff
- Visual diff highlighting:
  - Green background for additions
  - Red background with strikethrough for deletions
  - Neutral text for unchanged content
- Line-by-line diff using diff library
- Toggle between views per conflict
- Responsive layout (mobile-friendly)

UI Components:
- View toggle buttons (Side by Side / Unified Diff)
- DiffChange component for rendering highlighted changes
- UnifiedDiff component with line diff visualization
- actionsRow for resolution buttons in unified view

CSS Enhancements:
- .viewToggle - Toggle button group
- .toggleButton / .toggleActive - Toggle button states
- .unifiedDiff - Unified diff container
- .diffAdded / .diffRemoved / .diffUnchanged - Diff highlighting
- .actionsRow - Centered action buttons
- Mobile responsive breakpoints

Dependencies:
- Added `diff` library for diff computation

Integration:
- Already integrated in AccountSection (line 159)
- Shows automatically when conflicts.length > 0
- Stores expanded state and view mode per conflict

Next Steps:
- Multi-device testing to trigger actual conflicts
- User feedback on diff readability

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Comprehensive summary of bidirectional sync implementation.

Includes:
- Complete implementation details (migration, repo, service, UI)
- End-to-end flow diagrams
- Testing status and criteria
- Performance characteristics
- Critical blocker resolution
- File changes manifest
- Deployment checklist

Ready for multi-device testing.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements git-backed notebooks foundation (Differentiator #1).

Database Changes (Migration 009):
- Added git_enabled column to notebooks (INTEGER, default 0)
- Added git_auto_commit column (INTEGER, default 0)
- Added git_initialized_at column (TEXT, ISO 8601 timestamp)
- Index on git_enabled for efficient queries

GitService Implementation:
- Repository initialization with .gitignore
- File operations (write/read/delete note files)
- Git operations:
  - commit() - Stage and commit changes
  - status() - Get modified/added/deleted/untracked files
  - log() - Get commit history (configurable limit)
  - checkout() - Revert to specific commit
  - diff() - Placeholder for future implementation
- Uses isomorphic-git (pure JS, no git binary required)
- Default author: "Readied User <user@readied.app>"
- Repo path: baseDir/notebooks/{notebookId}/

Architecture:
- Each notebook = independent git repository
- Notes stored as {noteId}.md files in repo
- Full git history tracked per notebook
- Optional (user enables per notebook)

Dependencies:
- Added isomorphic-git@1.x

Next Steps:
- Integrate GitService into main process
- Add IPC handlers (init, commit, log, checkout)
- UI toggle for enabling git on notebooks
- Auto-commit on save implementation
- Commit history UI with revert

Related:
- ADR 001: Git-backed notes decision
- Phase 1, Sprint 2 of execution plan
- Differentiator #1 (vs Inkdrop/Obsidian)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Wires up GitService to Electron main process with full IPC API.

Integration:
- Import and declare GitService
- Initialize on app ready (after database init)
- BaseDir: userData path for git repositories
- Repo path pattern: {baseDir}/notebooks/{notebookId}/

IPC Handlers Added (git:*):
- init: Initialize git repo for notebook
- isRepo: Check if notebook has git
- commit: Stage and commit changes
- log: Get commit history (configurable limit)
- status: Get modified/added/deleted files
- checkout: Revert to specific commit
- writeNote: Write note file to git repo
- readNote: Read note file from git repo
- deleteNote: Delete note file from git repo

Handler Pattern:
- All return {success: boolean, ...data, error?: string}
- Error handling with try/catch
- User-friendly error messages

Initialization Flow:
1. app.whenReady()
2. initDatabase() → creates GitService
3. registerGitHandlers() → registers IPC handlers
4. Git operations available to renderer

Next Steps:
- Add preload API bindings (window.readied.git.*)
- Update NotebookRepository with git_enabled methods
- UI toggle for enabling git on notebooks
- Auto-commit on save hook

Related:
- Builds on commit 78e52d7 (GitService foundation)
- Phase 1, Sprint 2 progress
- Enables UI to interact with git

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Exposes git operations to renderer process via window.readied.git

API Added (window.readied.git.*):
- init(notebookId) - Initialize git repo for notebook
- isRepo(notebookId) - Check if notebook has git
- commit(notebookId, message, files?) - Commit changes
- log(notebookId, limit?) - Get commit history
- status(notebookId) - Get repo status (modified/added/deleted/untracked)
- checkout(notebookId, commitSha) - Revert to commit
- writeNote(notebookId, noteId, content) - Write note file
- readNote(notebookId, noteId) - Read note file
- deleteNote(notebookId, noteId) - Delete note file

TypeScript Interface:
- Full type definitions in ReadiedAPI
- All methods return Promise<{success: boolean, ...data, error?: string}>
- Matches IPC handler signatures from main process

Implementation Pattern:
- Uses ipcRenderer.invoke('git:*', ...args)
- Direct pass-through to main process handlers
- No renderer-side logic (thin binding layer)

Integration Complete:
✅ GitService (main process)
✅ IPC handlers (main process)
✅ Preload API (this commit)
Ready for: UI components to call window.readied.git.*

Next Steps:
- Update NotebookRepository with git_enabled methods
- UI toggle for enabling git on notebooks
- Auto-commit on save hook

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Completes repository layer and IPC integration for git-backed notebooks.

NotebookRepository Changes:
- Updated NotebookRow interface with git columns
- Updated all SELECT queries to include git columns
- Added 6 git methods:
  - enableGit(notebookId) - Enable git + set initialized_at
  - disableGit(notebookId) - Disable git (keeps initialized_at)
  - isGitEnabled(notebookId) - Check if git enabled
  - getGitSettings(notebookId) - Get enabled/autoCommit/initializedAt
  - setGitAutoCommit(notebookId, enabled) - Toggle auto-commit
  - getGitEnabledNotebooks() - List all git-enabled notebooks

IPC Handlers Added (main/index.ts):
- notebooks:enableGit
- notebooks:disableGit
- notebooks:isGitEnabled
- notebooks:getGitSettings
- notebooks:setGitAutoCommit
- notebooks:getGitEnabled

Preload API Added (preload/index.ts):
- window.readied.notebooks.enableGit(notebookId)
- window.readied.notebooks.disableGit(notebookId)
- window.readied.notebooks.isGitEnabled(notebookId)
- window.readied.notebooks.getGitSettings(notebookId)
- window.readied.notebooks.setGitAutoCommit(notebookId, enabled)
- window.readied.notebooks.getGitEnabled()

Full Stack Complete:
✅ Database (migration 009)
✅ Repository (git methods)
✅ IPC Handlers (main process)
✅ Preload API (renderer access)
Ready for: UI components

Next Steps:
- UI toggle for enabling git on notebooks
- Auto-commit on save hook
- Commit history UI

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add GitBranch icon from lucide-react
- Show git badge indicator when git is enabled
- Add git toggle button in notebook actions
- Check git status on component mount
- Handle git enable/disable with loading state
- CSS styles for git badge and git-enabled button state
- Check git settings when note is updated
- Auto-commit to git if notebook has git enabled and autoCommit enabled
- Write note file to git repo using writeNote IPC method
- Commit with descriptive message (Update/Rename note: title)
- Fire-and-forget approach - doesn't block save flow
- Error handling without throwing (logs only)
- Applies to both content updates and title updates
- Create CommitHistory component with modal UI
- Display commit list with message, author, timestamp
- Expandable commit details with full info and SHA
- Revert to commit functionality with confirmation
- History button in notebook actions (only visible when git enabled)
- Relative time formatting (minutes/hours/days ago)
- Loading, error, and empty states
- Animated modal with overlay and slide-up effect
- CSS module with dark theme styling
- Update API base URL to https://api.readied.app
- Fix rate limiter for Cloudflare Workers compatibility (remove global setInterval)
- Update VitePress config for custom domain (docs.readied.app)
- Upgrade Wrangler to v4.58.0
- Add comprehensive RELEASES.md documentation

Deployed infrastructure:
- API staging: https://readied-api-staging.readied.workers.dev
- API production: https://api.readied.app
- Docs: https://docs.readied.app
- Marketing: https://readied.app

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Window State Persistence:
- Save/restore window position, size, and maximized state
- Debounced state saving on resize/move events
- Persist state across app restarts

Editor Enhancements:
- Enhanced MarkdownEditor with configurable settings
- Expanded EditorSection with more customization options
- Improved GeneralSection with additional settings

Settings Sync:
- Add settings sync broadcasting across multiple windows
- Add manual update check handler (updates:checkNow IPC)

This restores settings that were previously in stash from main branch.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Combines deployment infrastructure with enhanced settings and editor features:
- Window state persistence (position, size, maximized)
- Enhanced editor settings and customization
- Settings sync across multiple windows
- Manual update check handler

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Settings Store:
- Add EditorSettings interface with editor configuration options
- Add GeneralSettings interface with app-level settings
- Add selectEditor and selectGeneral selectors
- Add updateEditor and updateGeneral actions
- Increment storage version to 2 for migration

Form Controls:
- Create controls.tsx with Toggle, NumberInput, TextInput, Select components
- Add CSS styling for all form controls
- Support disabled states and focus styles

SettingRow:
- Add optional htmlFor prop for label accessibility
- Wire up label to form controls

Fixes:
- Handle null defaultNotebookId in Select component
- Add rememberWindowPosition to GeneralSettings
- Resolve all TypeScript errors in settings sections

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add 'No default (ask each time)' option to notebook select
- Prevents empty select value issues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The settings window was showing a black screen because it was missing
the QueryClientProvider needed for useNotebooks hook.

Added:
- QueryClient instance with same config as main app
- QueryClientProvider wrapper around SettingsApp

Fixes: No QueryClient set error in GeneralSection

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
UI Improvements:
- Add Lucide icons to settings sidebar
- Active indicator bar on selected section
- Improved spacing and typography throughout
- Polished form controls (toggle, select, input)
- Better hover states and transitions
- Custom scrollbar styling
- Centered content layout with max-width

Sidebar:
- Wider sidebar (220px) with better padding
- Icons with opacity states
- Active section with accent border indicator
- Smoother transitions

Controls:
- Larger, more modern toggle switches (44x24px)
- Better focus states with accent glow
- Improved hover feedback
- Consistent border radius (0.5rem)
- Subtle backgrounds and borders

SettingRow:
- Card-like appearance with borders
- Hover effect on rows
- Better spacing (1.125rem padding)
- Improved label/description hierarchy

AppearanceSection:
- Theme selection (Dark/Light/System)
- Zoom level control (80%-130%)
- Performance mode selector
- Proper integration with stores

All sections now have:
- Consistent spacing
- Better visual hierarchy
- Modern, polished appearance
- Matches main app design language

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Marketing Site:
- Fix broken /blog links (now points to Medium)
- Update Decisions.astro for hybrid model (local-first + Pro)
- Fix inconsistent GitHub links to official repo
- Update legal pages dates to January 2026
- Add tablet responsive breakpoint (768px)
- Add Plausible analytics (production only)

Desktop App:
- Add @sentry/electron for error tracking
- Create offline-first analytics module
- Integrate Sentry with ErrorBoundary

Infrastructure:
- Create @readied/design-system package with tokens and components
- Prepare release.yml for SignPath Windows signing
- Add MIT licenses to open source packages (Open Core model)
- Add CONTRIBUTING.md for community contributions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- README.md with project overview and badges
- CODE_OF_CONDUCT.md for community guidelines
- SECURITY.md for vulnerability reporting
- Issue templates (bug report, feature request)
- PR template with checklist
- CODEOWNERS for review assignments
- FUNDING.yml for GitHub Sponsors
- dependabot.yml for dependency updates
- Update CI to run on develop branch
- Bump version to 0.2.0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a45c79388

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +355 to +356
const isConflict =
existingNote && change.deviceId !== this.apiClient['deviceInfo'].deviceId;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate conflicts on unsynced local edits, not deviceId alone

This marks any remote change from a different device as a conflict, even when the local note has no pending edits. In normal multi‑device use (e.g., edit on device B, then sync device A with no local changes), this will create unnecessary conflict copies and force user resolution for every cross‑device update. You likely want to only flag conflicts when the local note has unsynced changes (e.g., needs_sync/local_version), otherwise just apply the remote update.

Useful? React with 👍 / 👎.

Comment on lines +101 to +102
// Update cursor
this.state.cursor = result.cursor;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not advance sync cursor after a failed apply

The cursor is updated to the server’s max version even if one or more changes failed to apply in the loop above (errors are logged and ignored). That means a decrypt/DB failure will permanently skip that change, leaving the device out of sync and potentially losing data. Consider tracking apply failures and only advancing the cursor past successfully applied changes, or aborting the pull on first failure.

Useful? React with 👍 / 👎.

tomymaritano and others added 2 commits January 24, 2026 18:07
Combines:
- FTS5 full-text search
- Wikilink anchors support
- Cloud sync foundation (sync-core package)
- Settings window improvements
- Theme support
- Auto-updates check

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Unify settings stores by making settings.ts re-export from settings/settingsStore
- Fix useTheme import path
- Remove deprecated migration files from build

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants