feat: AI providers, dashboard, settings refresh, production fixes#172
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Notebooks now sync before notes in syncNow() to ensure note-notebook dependencies are satisfied. Adds pullNotebooks/pushNotebooks methods and applyRemoteNotebookChange for bidirectional notebook sync. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move validateNotebookTree from inline test definition to a shared module so it can be reused by the API route and other consumers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add conflict state to SyncStatusIndicator with amber warning icon and count. Conflicts now take priority over idle state so users discover them without navigating to Settings. Also export ConflictResolver from sync components barrel. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DatabaseConnection.transaction() already calls the inner fn — no need for extra () at call site. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix pullNotebooks() to only advance cursor to last successfully applied change (prevents skipping failed changes on retry) - Fix tree validation snapshot to properly exclude deleted notebooks (prevents ghost parent references in validation) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: add bidirectional notebook sync
test: add sync-core unit tests (62 tests)
feat: surface sync conflicts in status indicator
# Conflicts: # apps/desktop/src/main/services/apiClient.ts # apps/desktop/src/main/services/syncService.ts # packages/api/src/db/schema.ts # packages/api/src/routes/sync.ts # packages/storage-sqlite/src/migrations/index.ts
feat: add bidirectional tag sync
Configure automated code review with path-specific instructions for core, storage, desktop, and API packages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ration Add optional metadata (name, version, priority) to registerRemarkPlugin and registerRehypePlugin signatures for debugging and execution ordering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Summary
- **New `@readied/ai-core` package** — provider-agnostic AI architecture
with LLMProvider interface, ProviderRegistry, streaming SSE parser,
retry logic with exponential backoff, context builder with token
budgeting, and AIService orchestrator
- **Full Electron integration** — IPC bridge with batched streaming
events, preload API, and renderer AiPanel wired to the new streaming
architecture
- **UX fixes** — unified dual AI panel entry points (Cmd+K and Sparkles
button) into single panel, fixed panel height to fill container, made
React DevTools dev-only via dynamic import
- **Monorepo fix** — pinned `@types/react` to 18.x via pnpm overrides to
resolve lucide-react type mismatch
## Architecture
```
Renderer (AiPanel) → IPC → Main (ai-core bridge) → AIService → ProviderRegistry → AnthropicProvider → SSE stream
← batched LLMEvents (text/error/done) ←
```
## What's included
### packages/ai-core (new)
- `LLMProvider` interface + `ProviderRegistry` for pluggable providers
- `AnthropicProvider` with native SSE streaming (no SDK dependency)
- `ContextBuilder` with token budgeting and automatic content trimming
- `AIService` orchestrator with retry, cancellation, and context
building
- `LLMEvent` protocol: `text`, `error`, `done`, `tool_call`,
`tool_result`
- Reusable SSE stream parser
### apps/desktop
- IPC bridge with 50ms batched event streaming (main → renderer)
- Preload API: `window.readied.ai.chat()`, `.onEvent()`, `.cancel()`
- Unified AI panel (single instance, both Cmd+K and Sparkles button
toggle it)
- Panel height fix (fills container instead of 350px cutoff)
- Dynamic import for electron-devtools-installer (excluded from prod)
### Monorepo
- Removed deprecated `@readied/ai-assistant` package
- Added `pnpm.overrides` to pin `@types/react@18.3.27` across workspace
## Test plan
- [x] All 16 packages pass `pnpm test`
- [x] `pnpm typecheck` passes (17/17 tasks)
- [x] `pnpm build` succeeds
- [ ] Manual: Cmd+K opens AI panel in ask-notes mode
- [ ] Manual: Sparkles button toggles same panel
- [ ] Manual: AI chat streams responses correctly
- [ ] Manual: Panel fills full height of sidebar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added streaming AI chat responses for real-time interaction
* Introduced provider selection (Anthropic, OpenAI, Ollama support)
* Added ability to cancel in-flight AI requests
* Implemented configuration validation for AI providers
* Enhanced chat interface with conversation modes
* **Refactor**
* Restructured AI system for multi-provider support
* Updated settings schema with provider configuration
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - Replace manual release process with a two-stage automated pipeline using **semantic-release** - **Stage 1** (`release.yml`): `workflow_dispatch` on main → semantic-release analyzes commits, bumps version, creates tag + draft GitHub Release (~30s) - **Stage 2** (`build.yml`): tag push triggers parallel mac/win/linux builds → signs + notarizes macOS → uploads artifacts → undrafts release → tweets → auto-PR syncs main→develop ## Changes - Add `release.config.js` (conventionalcommits preset, draft release, beta channel ready) - Add `scripts/bump-version.js` with tests (syncs version across monorepo) - Replace `.github/workflows/release.yml` (200 lines → 46 lines semantic-release workflow) - Create `.github/workflows/build.yml` (parallel platform builds + publish + tweet + sync-develop) - Delete `.github/workflows/auto-tag.yml` (replaced by semantic-release) - Update CLAUDE.md Git Flow section with release process + rollback docs - Add semantic-release + plugins as devDependencies ## Required: New GitHub Secret Create a `GH_TOKEN` repository secret — a Personal Access Token with `contents: write` scope. Needed because: 1. semantic-release must push tags that trigger other workflows (GITHUB_TOKEN can't do this) 2. electron-builder needs write access to upload artifacts to GitHub Releases ## Test plan - [x] All existing tests pass (`pnpm test`) - [x] `scripts/bump-version.test.js` — 2 new tests passing - [x] `release.config.js` loads correctly - [x] All workflow YAML files are syntactically valid - [ ] Create `GH_TOKEN` secret in repo settings - [ ] After merge to main: click "Run workflow" on Release action to test end-to-end 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Implemented automated release pipeline with semantic versioning, generating changelogs automatically. * Added multi-platform build automation for simultaneous macOS, Windows, and Linux releases. * **Documentation** * Updated Git Flow and release process documentation to reflect new automated workflows. * **Tests** * Added tests for automated version management. * **Chores** * Refined release workflows for improved efficiency and reliability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - Adds `cleanUrls: true` to `vercel.json` - Fixes the 404 on `/auth/verify` (and all other static pages without `.html` extension) ## Root cause Next.js static export generates `auth/verify.html`, but without `cleanUrls: true`, Vercel doesn't know to serve it when the URL is `/auth/verify` (no `.html`). This affects the magic link email verification flow. ## Test plan - [ ] Deploy to Vercel preview - [ ] Visit `/auth/verify` — should show "Invalid Link" (no token) - [ ] Visit `/auth/verify?token=test` — should show "Opening Readied..." - [ ] Verify other pages still work (`/download`, `/pricing`, `/changelog`) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated application configuration to enable clean URLs, improving URL structure and formatting across the platform. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - **ai-core**: Add `ToolRegistry`, `runToolLoop` orchestrator, `chatWithTools()` on `AIService`, tool_use SSE parsing in AnthropicProvider, and `stop` event with `tool_use`/`tool_result` ContentPart types - **desktop (main)**: Register 6 built-in tools (search_notes, read_note, list_notebooks, create_note, insert_text, replace_selection) with confirmation flow and renderer-executed tool IPC bridge - **desktop (renderer)**: `ToolCallBlock` component with status indicators/icons, tool call tracking in `AiPanel`, and renderer-side execution of editor tools (insert_text, replace_selection) ### Tools | Tool | Type | Confirmation | |------|------|-------------| | `search_notes` | Read (main) | Auto | | `read_note` | Read (main) | Auto | | `list_notebooks` | Read (main) | Auto | | `create_note` | Write (main) | Required | | `insert_text` | Write (renderer) | Required | | `replace_selection` | Write (renderer) | Required | ## Test plan - [x] All 153 tests pass (`pnpm test`) - [x] Typecheck clean (`pnpm typecheck` — main, preload, renderer) - [x] Build succeeds (`pnpm build`) - [ ] Manual: open AI panel, send message with `tools: true`, verify tool calls render - [ ] Manual: approve/reject tool confirmation flow - [ ] Manual: verify insert_text and replace_selection modify the editor 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Streaming AI chat with multi-turn conversations and built-in note management tools (search, read, create, and editor actions) * Tool confirmation UI allowing users to approve/reject AI tool executions before they run * Enhanced chat interface with provider validation and improved request controls * **Documentation** * Added comprehensive AI architecture and tool-use implementation guides * **Style** * Updated visual color opacity tokens across UI components for consistency <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…#166) ## Summary - **Extended `sharedNotes` schema** with `tags`, `backlinks`, `wordCount`, and `notebookName` columns (all `NOT NULL DEFAULT` — backward-compatible) - **Added `GET /share/public/:userId`** list endpoint with pagination (`?limit=20&offset=0`) and permissive CORS for cross-origin portfolio consumption - **Enriched `GET /share/:slug`** detail endpoint to return metadata (tags, backlinks, wordCount, notebookName) - **Updated `POST /share`** to accept and persist metadata fields (Zod defaults keep old clients working) - **Desktop app** now sends full note metadata (tags, wordCount, notebookName, backlinks) when sharing - **Hand-corrected migration** (`0005`) uses safe `ALTER TABLE ADD COLUMN` instead of Drizzle's auto-generated `CREATE TABLE` ## Test plan - [x] `pnpm typecheck` passes (17/17 tasks) - [x] `pnpm test` passes (42/42 tests across 7 test files) - [ ] Manual: share a note from desktop → verify API receives tags/wordCount/notebookName - [ ] Manual: `curl "https://api.readied.app/share/public/<userId>?limit=5"` returns paginated notes with metadata - [ ] Manual: `curl "https://api.readied.app/share/<slug>"` returns enriched response with tags/backlinks - [ ] Manual: fetch from different origin (portfolio domain) succeeds for `/share/public/*` (CORS) - [ ] Run `pnpm db:migrate` on staging to verify migration applies cleanly 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added ability to share notes with enhanced metadata including tags, word count, and notebook context. * Introduced public notes listing endpoint with pagination support. * **Documentation** * Updated documentation component infrastructure for improved content rendering. * **Style** * Refined color and gradient utilities across the web interface for improved visual consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts: # .claude/settings.local.json # .github/workflows/build.yml # apps/desktop/package.json # apps/desktop/src/main/ai/ipc-ai.ts # apps/desktop/src/main/ai/setup.ts # apps/desktop/src/main/index.ts # apps/desktop/src/preload/index.ts # apps/desktop/src/renderer/components/ai/AiPanel.tsx # apps/desktop/src/renderer/stores/settings/settingsStore.ts # apps/web/app/(marketing)/auth/verify/AuthVerifyContent.tsx # apps/web/app/(marketing)/changelog/page.tsx # apps/web/app/(marketing)/download/page.tsx # apps/web/app/(marketing)/pricing/page.tsx # apps/web/app/docs/[[...slug]]/page.tsx # apps/web/components/Footer.tsx # apps/web/components/Navbar.tsx # apps/web/components/landing/Hero.tsx # apps/web/components/landing/VideoGuides.tsx # apps/web/components/magicui/animated-shiny-text.tsx # apps/web/components/magicui/border-beam.tsx # apps/web/components/magicui/hero-video-dialog.tsx # package.json # packages/ai-core/src/ai-service.ts # packages/ai-core/src/context-builder.ts # packages/ai-core/src/index.ts # packages/ai-core/src/providers/anthropic.ts # packages/ai-core/src/providers/sse-parser.ts # packages/ai-core/src/retry.ts # packages/ai-core/src/types.ts # packages/ai-core/tests/ai-service.test.ts # packages/ai-core/tests/retry.test.ts # packages/ai-core/tests/types.test.ts # pnpm-lock.yaml # vercel.json
…reated webhook - Parse markdown content with `marked` in SharedNoteContent instead of rendering raw text via dangerouslySetInnerHTML - Add customer.subscription.created webhook handler as fallback when checkout.session.completed is not configured in Stripe events - Clean up temporary debug logging from license handlers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add shareStore (Zustand + persist) for tracking shared note state - Update ActionsPanel with share-on-web functionality - NoteEditor and NoteList UI improvements - Note list styling updates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ript - AI chat mode now only uses the current note as context (no search) - AI ask-notes mode still searches across all notes for relevant context - Add newsletter unsubscribe page at /newsletter/unsubscribe - Add create-note.sh script for creating notes from the terminal Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exposes Readied notes to Claude Code via Model Context Protocol: - readied_list_notes: List notes with filters - readied_read_note: Read note by ID or title - readied_create_note: Create new notes - readied_update_note: Update existing notes - readied_search_notes: Search across notes - readied_list_notebooks: List notebooks - readied_trash_note: Move to trash Uses sql.js (WASM) to avoid native module conflicts with Electron. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- User messages in bubble style with rounded corners - Smooth fade-in animation on new messages - Blinking cursor for typing indicator - Better input with focus ring - Cleaner tool call blocks with subtle borders - Improved spacing and typography throughout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## AI Providers - Add OpenAI provider: GPT-4o, o1, GPT-4 Turbo with SSE streaming + tools - Add Ollama provider: local models with auto-detection, NDJSON streaming - Register all 3 providers in setup.ts ## Secure Key Storage - New AiKeyStorage service using Electron safeStorage (OS keychain) - IPC handlers: saveKey, getKey, removeKey, hasKey, listConnectedProviders - Preload bridge exposes all key management methods ## Settings UI — Connect Flow - Replace manual API key input with "Connect" button flow - "Get API Key" button opens provider's key page in browser - Paste key → auto-validate → show "Connected" badge - Connected state shows green status with "Disconnect" option - Ollama: one-click connect (no key needed) - Dynamic model list per provider - Model & context settings only shown when connected Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…aner sidebar - SettingGroup now renders as cards with dividers between rows - SettingRow simplified: no individual borders/backgrounds, hover-only highlight - Sidebar: tighter nav items, subtler active indicator, muted icons - Controls: cleaner toggle, smaller inputs, simpler slider - Section title: smaller, tighter spacing - Content area: thinner scrollbar, reduced padding - Color picker: smaller swatches with dot indicator Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## API (packages/api) - New /admin routes: /stats, /users, /sync - Protected by ADMIN_TOKEN header - Aggregated metrics: users, subscriptions, devices, sync volume, shared notes, newsletter ## Dashboard (apps/web) - New /dashboard page with token auth - Overview tab: stat cards + sync volume chart (7 days) - Users tab: table with email, plan, devices, join date - Sync tab: recent activity feed with operation colors Token auto-saved to localStorage for convenience. Page is noindex to prevent search engine crawling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mail auth - Move dashboard from (marketing) to (dashboard) route group — no navbar/footer - Standalone sidebar layout with nav, API health indicator, sign out - Admin auth now accepts JWT from authenticated admin emails - Improved stat cards, sync volume chart, quick links panel - Login screen centered without marketing chrome - Proper dark theme throughout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
||
| async *chat(options: ChatOptions, config: ProviderConfig): AsyncIterable<LLMEvent> { | ||
| const { model, system, messages, maxTokens, signal, tools } = options; | ||
| const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ''); |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
| } | ||
|
|
||
| async validate(config: ProviderConfig): Promise<{ ok: boolean; error?: string }> { | ||
| const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ''); |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
| } | ||
|
|
||
| async listModels(config: ProviderConfig): Promise<ModelInfo[]> { | ||
| const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ''); |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (38)
📝 WalkthroughWalkthroughThis PR introduces multi-provider AI support (OpenAI and Ollama) with persistent API key management in the desktop app, adds a local MCP server for database access, implements note-sharing capabilities with client-side persistence, creates an admin dashboard for web app monitoring and user management, and updates UI styling across settings and AI components. Changes
Sequence Diagram(s)sequenceDiagram
participant User as Desktop User
participant UI as Settings UI
participant IPC as IPC Bridge
participant Main as Main Process
participant Storage as AiKeyStorage
participant API as Provider API
User->>UI: Click "Connect" for AI provider
UI->>UI: Collect API key
User->>UI: Submit connection
UI->>IPC: invoke('ai:saveKey', provider, apiKey)
IPC->>Main: Handle ai:saveKey
Main->>API: validate(config with apiKey)
alt Validation succeeds
API-->>Main: { ok: true }
Main->>Storage: saveKey(provider, apiKey)
Storage->>Storage: readKeys() → decrypt/parse
Storage->>Storage: Update provider → apiKey mapping
Storage->>Storage: writeKeys() → encrypt & save to disk
Storage-->>Main: Promise resolved
Main-->>IPC: void (success)
IPC-->>UI: Promise resolved
UI->>UI: Update connectStatus to 'connected'
UI->>UI: Fetch and store provider-specific settings
else Validation fails
API-->>Main: { ok: false, error: "..." }
Main-->>IPC: Promise rejected
IPC-->>UI: Catch error
UI->>UI: Update connectStatus to 'error', set message
end
UI->>User: Display connection result
sequenceDiagram
participant Admin as Admin User (Browser)
participant Page as Dashboard Page
participant API as /admin/* Routes
participant DB as Database
Admin->>Page: Visit /dashboard?token=xyz
Page->>Page: Read token from query params
Page->>Page: Save token to localStorage
Page->>API: GET /admin/stats (header: x-admin-token)
API->>API: Verify x-admin-token matches ADMIN_TOKEN
API->>DB: Query aggregated stats (users, subscriptions, sync)
DB-->>API: Return aggregated rows
API-->>Page: { users, subscriptions, devices, syncEntries, ... }
par Parallel API Calls
Page->>API: GET /admin/users
API->>DB: Query users with subscription info & device counts
DB-->>API: Return user list
API-->>Page: [{ id, email, plan, status, joinedDate, ... }]
and
Page->>API: GET /admin/sync
API->>DB: Query recent sync entries and daily volume
DB-->>API: Return sync activity
API-->>Page: { recent: [...], dailyVolume: [...] }
end
Page->>Page: Render overview (stats cards, sync chart)
Page->>Page: Render users table
Page->>Page: Render sync activity list
Page->>Admin: Display dashboard
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes This PR introduces substantial new functionality across multiple subsystems: two new LLM providers with streaming, tool support, and error classification; encrypted persistent key storage with Electron integration; a local MCP server with database access and seven tools; an admin dashboard with auth, multi-table queries, and API routes; client-side share state management; and pervasive UI refinements. The changes span heterogeneous domains (backend providers, IPC infrastructure, UI state, styling, database schema) with dense logic in the provider implementations (streaming NDJSON parsing, error classification, message/tool conversion) and admin routes (multi-table ORM queries, auth middleware). The scope encompasses new files and substantial modifications across Possibly related PRs
Suggested labels
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7fd0ee1201
ℹ️ 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".
| const jwt = authHeader.slice(7); | ||
| const [, payloadB64] = jwt.split('.'); | ||
| if (payloadB64) { | ||
| const payload = JSON.parse(atob(payloadB64)) as { email?: string; exp?: number }; |
There was a problem hiding this comment.
Verify admin bearer tokens before trusting their email
This middleware grants /admin/* access to any bearer token whose payload decodes to an allowed email, because it never verifies the JWT signature. Unlike packages/api/src/middleware/auth.ts, which calls jose.jwtVerify, this code just atobs the middle segment and trusts it, so an attacker can forge a token with {"email":"tomymaritano@gmail.com"} and read the admin stats/users/sync endpoints.
Useful? React with 👍 / 👎.
| Authorization: `Bearer ${config.apiKey}`, | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| body: '', |
There was a problem hiding this comment.
Remove the body from the OpenAI validation GET
createAIService() wires this provider to Electron's net.fetch, which follows standard Fetch semantics. Sending body: '' on a GET request throws before the request is dispatched, so OpenAIProvider.validate() will reject every key and the new Connect flow cannot save an OpenAI credential.
Useful? React with 👍 / 👎.
| // If no row was updated, create it (handles case where checkout.session.completed was missed) | ||
| if (updated.length === 0 && sub.customer) { | ||
| // Find user by Stripe customer ID | ||
| const [existing] = await db | ||
| .select() |
There was a problem hiding this comment.
Actually create the missing subscription in the fallback path
This branch is meant to recover when checkout.session.completed was missed, but it only looks up an existing row and logs when none is found. If Stripe delivers customer.subscription.created/updated before or instead of checkout completion, the user never gets a subscriptions record, so /subscription/status keeps reporting free/inactive and paid sync stays disabled.
Useful? React with 👍 / 👎.
| const db = await openDb(); | ||
| const server = createServer(db); |
There was a problem hiding this comment.
Reopen the MCP database instead of reusing one startup snapshot
main() opens the SQLite file once and then all tool calls share that in-memory sql.js database for the lifetime of the process. Because writes later call saveDb() to export the whole snapshot back to disk, any edits the desktop app makes after the MCP server starts are missing from this snapshot and will be overwritten on the next create/update/trash operation.
Useful? React with 👍 / 👎.
Summary
Major release merging develop into main with:
AI System
Admin Dashboard
Settings Visual Refresh
Production Fixes
Other
Test plan
pnpm devstarts without errors🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements