- AI-powered command center for offensive security.
- Recon. Exploit. Report. One terminal.
+ AI-powered cybersecurity platform for offensive security.
+ Recon. Exploit. Report. One platform.
-
-
-
-
-
+
---
## What is CrowByte?
-CrowByte Terminal is a **desktop application** for penetration testers, bug bounty hunters, and red team operators. It replaces the workflow of juggling 20+ browser tabs, terminal windows, and note apps with a unified command center powered by AI.
+CrowByte is an **AI-powered cybersecurity platform** for penetration testers, bug bounty hunters, and red team operators. It replaces the workflow of juggling 20+ browser tabs, terminal windows, and note apps with a unified command center powered by AI.
-Available for **Linux**, **Windows**, and **macOS**. Server appliance mode for browser-based access.
-
-
-
-
+**Free** in your browser at [crowbyte.io](https://crowbyte.io). **Pro** unlocks desktop apps for Linux, Windows, and macOS. **Docker** for self-hosted deployments.
---
@@ -37,19 +27,19 @@ Available for **Linux**, **Windows**, and **macOS**. Server appliance mode for b
Deploy up to 9 specialized AI agents on your own infrastructure. Agents handle reconnaissance, vulnerability analysis, exploit research, and report generation in parallel. Supports multiple LLM providers — bring your own API keys or use the built-in gateway.
### Mission Pipeline
-Phase-based operation planning from scope import through exploitation to final report. Define objectives, track task dependencies, and automate status transitions across the entire engagement lifecycle.
+Phase-based operation planning from scope import through exploitation to final report. Define objectives, track task dependencies, and manage status transitions across the entire engagement lifecycle.
### CVE Intelligence
Real-time vulnerability database with CVSS scoring, exploit status tracking, product correlation, and cross-referencing with Shodan. Search, filter, and bookmark CVEs relevant to your active engagements.
-### Integrated Terminal
-Full xterm.js terminal with tmux session management. Run Nmap, Nuclei, SQLMap, FFUF, or any CLI tool without leaving the platform. Output is automatically captured for report evidence.
+### Integrated Terminal *(Desktop only)*
+Full xterm.js terminal with tmux session management, powered by node-pty. Run Nmap, Nuclei, SQLMap, FFUF, or any CLI tool without leaving the platform. Multiple tabs, split panes, and shell presets.
### Fleet Management
-Monitor endpoints, VPS nodes, and containers from a single dashboard. Real-time hardware metrics (CPU, RAM, disk, network), process inspection, and remote agent deployment. Built-in remote desktop with E2E encryption.
+Monitor endpoints, VPS nodes, and containers from a single dashboard. Real-time hardware metrics (CPU, RAM, disk, network), process inspection, and remote agent deployment. Built-in remote desktop with encrypted communication.
-### Automated Reporting
-Generate professional reports formatted for HackerOne, Bugcrowd, or custom templates. Findings are automatically populated with severity, evidence, reproduction steps, and impact analysis.
+### Report Generator
+Generate professional pentest and bug bounty reports. Templates for HackerOne, Bugcrowd, and custom formats. Pull findings into structured reports with severity, evidence, and reproduction steps. Export as Markdown, HTML, or platform-specific JSON.
### Detection Rule Lab
Author, test, and manage detection rules across formats:
@@ -58,48 +48,48 @@ Author, test, and manage detection rules across formats:
- **YARA** rules for malware analysis
- **Snort / Suricata** signatures for network detection
-### Alert Center (SIEM Bridge)
-Connect to your existing SIEM infrastructure. Pre-built connectors for Splunk, Elasticsearch, and custom sources. Real-time alert ingestion, triage, and correlation with your findings.
+### Alert Center
+Centralized alert management with support for multiple source types. Ingest, triage, and correlate alerts with your findings. Connector framework for Splunk, Elasticsearch, and webhook sources.
### Knowledge Base
Searchable research database for techniques, tool notes, methodology references, and engagement intelligence. Tag, categorize, and attach files. Full-text search across all entries.
-### Cloud Security Posture
-CSPM scanning, SBOM generation, and compliance checks across AWS, GCP, and Azure. Identify misconfigurations, exposed resources, and policy violations.
+### Cloud Security Dashboard
+Track cloud security posture across AWS, GCP, and Azure. Manage cloud account inventory, resource tracking, and security findings. Compliance mapping against CIS, SOC2, PCI-DSS, HIPAA, and NIST frameworks.
---
## AI Infrastructure
-CrowByte supports multiple AI providers. Enterprise users can route all operations through their own infrastructure.
+CrowByte ships with a 9-agent AI swarm powered by multiple frontier models. Enterprise users can route all operations through their own infrastructure.
-| Provider | Type | Notes |
-|----------|------|-------|
-| **Built-in Gateway** | OpenAI-compatible | Zero-cost inference via bundled VPS proxy |
-| **OpenAI / Azure** | API | GPT-4o, GPT-4 Turbo |
-| **Anthropic** | API | Claude Opus 4.6, Sonnet 4.6, Haiku 4.5 |
+| Provider | Models | Notes |
+|----------|--------|-------|
+| **OpenClaw Gateway** | DeepSeek V3.2, Qwen3 Coder 480B, Qwen 3.5 397B, Mistral Large 675B, Kimi K2, GLM5 | Built-in proxy — included with Pro |
+| **Anthropic** | Claude Opus 4.6, Sonnet 4.6, Haiku 4.5 | Native CLI integration with MCP tools |
+| **NVIDIA NIM** | Any NIM-hosted model | Via OpenClaw gateway |
| **Self-hosted** | Ollama / vLLM | Any model on your hardware |
-| **Custom** | OpenAI-compatible | Any endpoint that speaks the OpenAI API |
+| **Custom** | Any OpenAI-compatible endpoint | Bring your own API |
-All AI features work offline with self-hosted models. No data leaves your machine unless you configure an external provider.
+All AI features work with self-hosted models. No data leaves your machine unless you configure an external provider.
---
## Security
-CrowByte is built with security-first principles. Your data stays yours.
-
-- **E2E Encryption** — Remote desktop and fleet communication uses X25519 ECDH key exchange with AES-256-GCM. Zero-knowledge relay.
-- **Local-First** — All data is stored locally in SQLite and Supabase (self-hostable). No telemetry, no tracking, no phone-home.
-- **Credential Isolation** — API keys and secrets are stored in encrypted storage with device-bound keys. Never transmitted to third parties.
-- **Audit Logging** — Every significant action is logged with timestamps and user attribution. Exportable for compliance.
+- **Encrypted Communication** — Remote desktop uses ECDH key exchange with AES-256-GCM for end-to-end encrypted screen sharing and input control.
+- **Credential Encryption** — Login credentials are encrypted with AES-256-GCM using device-derived keys (PBKDF2). On Electron, credentials are double-encrypted with the OS-level safeStorage API.
+- **Conversation Encryption** — Optional AES-256-GCM encryption for stored conversations with HMAC-SHA256 integrity verification.
+- **Activity Logging** — Actions across auth, API, security, network, AI, and terminal are logged with timestamps, severity levels, and categorized tags. Filterable by level and tag. Exportable as CSV or JSON.
+- **No Telemetry** — CrowByte does not collect usage data, analytics, or tracking information. All activity logs stay on your device.
+- **Supabase Backend** — All data is stored in Supabase (PostgreSQL with Row Level Security). Self-hostable for full data sovereignty.
- **No Source Exposure** — Proprietary codebase. Binary distribution only. No source code in the repository.
### Vulnerability Disclosure
If you discover a security vulnerability, report it responsibly.
-**Email**: [security@hlsitech.io](mailto:security@hlsitech.io)
+**Email**: [security@crowbyte.io](mailto:security@crowbyte.io)
Do **not** open a public GitHub issue for security vulnerabilities.
@@ -107,49 +97,13 @@ See [SECURITY.md](SECURITY.md) for our full disclosure policy and response SLA.
---
-## Screenshots
+## Get Started
-
-
-
-
-
-
-
-
-
-
-
-
-
----
-
-## Download
-
-Get CrowByte Terminal for your platform:
-
-| Platform | Format | Link |
-|----------|--------|------|
-| **Linux** | AppImage, .deb | [Download](https://crowbyte.io/download) |
-| **Windows** | Installer (.exe) | [Download](https://crowbyte.io/download) |
-| **macOS** | .dmg | [Download](https://crowbyte.io/download) |
-
-Or visit [crowbyte.io/download](https://crowbyte.io/download) for the latest release.
-
----
-
-## Tech Stack
-
-| Layer | Technology |
-|-------|-----------|
-| Desktop | Electron 39 |
-| Frontend | React 18, TypeScript 5, Vite |
-| UI | Radix UI (shadcn/ui), Tailwind CSS, Framer Motion |
-| Terminal | xterm.js + node-pty |
-| Backend | Supabase (PostgreSQL, Auth, Storage, Edge Functions) |
-| AI | Multi-provider (OpenAI-compatible, Anthropic, Ollama) |
-| Charts | Recharts |
-| Security | AES-256-GCM, X25519 ECDH, HKDF |
+| Tier | Access | How |
+|------|--------|-----|
+| **Free** | Web app | [crowbyte.io](https://crowbyte.io) — sign up, start in your browser |
+| **Pro** | Web + Desktop | Linux (.AppImage, .deb), Windows (.exe), macOS (.dmg) |
+| **Docker** | Self-hosted | `docker compose up -d` — access via browser on port 6080 |
---
@@ -157,8 +111,8 @@ Or visit [crowbyte.io/download](https://crowbyte.io/download) for the latest rel
| Tier | Price | Includes |
|------|-------|----------|
-| **Free** | $0 | Core features, 1 device, community support |
-| **Pro** | $19/mo | All features, 3 devices, AI agents, priority support |
+| **Free** | $0 | Web access, core features, community support |
+| **Pro** | $19/mo | Desktop apps, AI agent swarm, all features, priority support |
| **Team** | $49/mo | 10 seats, shared findings, fleet management |
| **Enterprise** | Custom | Unlimited seats, custom AI infra, dedicated support, SLA |
@@ -168,11 +122,15 @@ Visit [crowbyte.io](https://crowbyte.io) for details.
## Roadmap
+- [ ] Persistent audit logging with cloud sync (Supabase-backed)
+- [ ] Real-time SIEM connectors (Splunk, Elastic polling)
+- [ ] Automated terminal output capture for report evidence
+- [ ] Cloud security scanning (AWS/GCP/Azure API integration)
+- [ ] SBOM generation
- [ ] Plugin marketplace for community extensions
- [ ] Collaborative real-time editing for team engagements
- [ ] Mobile companion app (iOS / Android)
- [ ] API access for CI/CD pipeline integration
-- [ ] Custom AI agent builder with drag-and-drop workflows
---
@@ -197,11 +155,6 @@ This repository contains documentation, legal documents, and release binaries on
|---------|---------|
| Website | [crowbyte.io](https://crowbyte.io) |
| Support | [support@crowbyte.io](mailto:support@crowbyte.io) |
-| Security | [security@hlsitech.io](mailto:security@hlsitech.io) |
-| Company | [hlsitech.io](https://hlsitech.io) |
+| Security | [security@crowbyte.io](mailto:security@crowbyte.io) |
---
-
-
- Built by HLSITech — Offensive security, powered by AI.
-
diff --git a/agent/__pycache__/crowbyte-agent.cpython-313.pyc b/agent/__pycache__/crowbyte-agent.cpython-313.pyc
deleted file mode 100644
index 968a388..0000000
Binary files a/agent/__pycache__/crowbyte-agent.cpython-313.pyc and /dev/null differ
diff --git a/agent/crowbyte-agent.py b/agent/crowbyte-agent.py
index 147c5c3..b836642 100755
--- a/agent/crowbyte-agent.py
+++ b/agent/crowbyte-agent.py
@@ -165,7 +165,7 @@ def collect_metrics() -> dict:
# ─── HTTP Client ─────────────────────────────────────────────────────────────
-def make_request(url: str, data: dict, api_key: str) -> dict:
+def make_request(url: str, data: dict, api_key: str, verify_ssl: bool = True) -> dict:
"""POST JSON to URL with API key auth. Returns parsed response."""
body = json.dumps(data).encode('utf-8')
@@ -173,10 +173,13 @@ def make_request(url: str, data: dict, api_key: str) -> dict:
req.add_header('Content-Type', 'application/json')
req.add_header('X-API-Key', api_key)
- # Allow self-signed certs
- ctx = ssl.create_default_context()
- ctx.check_hostname = False
- ctx.verify_mode = ssl.CERT_NONE
+ if verify_ssl:
+ ctx = ssl.create_default_context()
+ else:
+ # Only used when explicitly opted-in via config (e.g. self-signed dev certs)
+ ctx = ssl.create_default_context()
+ ctx.check_hostname = False
+ ctx.verify_mode = ssl.CERT_NONE
try:
with urllib.request.urlopen(req, context=ctx, timeout=15) as resp:
@@ -206,6 +209,11 @@ def load_config() -> dict:
print('[!] api_key not set in config', file=sys.stderr)
sys.exit(1)
+ # Default to verifying SSL certificates; only disable if explicitly set to false
+ if config.get('verify_ssl', True) is False:
+ print('[!] WARNING: SSL certificate verification is disabled. '
+ 'Set verify_ssl=true in config for production use.', file=sys.stderr)
+
return config
@@ -225,7 +233,7 @@ def handle_signal(signum, frame):
def register(config: dict, metrics: dict) -> bool:
"""Register agent with server. Returns True on success."""
url = f"{config['server_url'].rstrip('/')}/api/fleet/register"
- result = make_request(url, metrics, config['api_key'])
+ result = make_request(url, metrics, config['api_key'], config.get('verify_ssl', True))
if result.get('ok'):
print(f"[+] Registered: {result.get('action', 'ok')} (id: {result.get('id', '?')})")
@@ -247,7 +255,7 @@ def heartbeat(config: dict, metrics: dict) -> bool:
'disk_usage': metrics['disk_usage'],
'agent_version': metrics['agent_version'],
}
- result = make_request(url, payload, config['api_key'])
+ result = make_request(url, payload, config['api_key'], config.get('verify_ssl', True))
if result.get('ok'):
return True
diff --git a/apps/desktop/.env.production b/apps/desktop/.env.production
new file mode 100644
index 0000000..c81c530
--- /dev/null
+++ b/apps/desktop/.env.production
@@ -0,0 +1,15 @@
+# CrowByte Web — Production Environment
+# Used by: npm run build:web:production
+# Deploys to: crowbyte.io
+
+VITE_BUILD_TARGET=web
+VITE_PLATFORM=web
+
+VITE_SUPABASE_URL=https://gvskdopsigtflbbylyto.supabase.co
+VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imd2c2tkb3BzaWd0ZmxiYnlseXRvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjMzMTIzMDUsImV4cCI6MjA3ODg4ODMwNX0.eQP8nS41MQy8J6dFYUwBjwupBdcxeAAeOUcAlK1m_Xs
+# NO service key — web must NEVER have it
+
+VITE_APP_URL=https://crowbyte.io
+
+# GlitchTip Error Monitoring (DSN only — no API token in web builds)
+VITE_GLITCHTIP_DSN=https://16ea5a1e0b304fc086a19d080d003897@app.glitchtip.com/21559
diff --git a/apps/desktop/.env.staging b/apps/desktop/.env.staging
new file mode 100644
index 0000000..4a18161
--- /dev/null
+++ b/apps/desktop/.env.staging
@@ -0,0 +1,15 @@
+# CrowByte Web — Staging Environment
+# Used by: npm run build:web:staging
+# Deploys to: staging.crowbyte.io
+
+VITE_BUILD_TARGET=web
+VITE_PLATFORM=web
+
+VITE_SUPABASE_URL=https://gvskdopsigtflbbylyto.supabase.co
+VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imd2c2tkb3BzaWd0ZmxiYnlseXRvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjMzMTIzMDUsImV4cCI6MjA3ODg4ODMwNX0.eQP8nS41MQy8J6dFYUwBjwupBdcxeAAeOUcAlK1m_Xs
+# NO service key — web must NEVER have it
+
+VITE_APP_URL=https://staging.crowbyte.io
+
+# GlitchTip Error Monitoring (DSN only — no API token in web builds)
+VITE_GLITCHTIP_DSN=https://16ea5a1e0b304fc086a19d080d003897@app.glitchtip.com/21559
diff --git a/apps/desktop/.gitignore b/apps/desktop/.gitignore
new file mode 100644
index 0000000..fe4afdb
--- /dev/null
+++ b/apps/desktop/.gitignore
@@ -0,0 +1 @@
+sourcemaps/
diff --git a/apps/desktop/electron/main.cjs b/apps/desktop/electron/main.cjs
index ab15405..f84493b 100644
--- a/apps/desktop/electron/main.cjs
+++ b/apps/desktop/electron/main.cjs
@@ -6,22 +6,41 @@
// Suppress EPIPE errors (broken pipe when Vite disconnects)
process.stdout.on('error', (err) => { if (err.code === 'EPIPE') return; });
process.stderr.on('error', (err) => { if (err.code === 'EPIPE') return; });
-process.on('uncaughtException', (err) => {
- if (err.code === 'EPIPE' || err.message?.includes('EPIPE')) return;
- console.error('[!] Uncaught:', err);
-});
// Suppress sourcemap warnings for MCP SDK (missing source files)
process.on('warning', (warning) => {
- if (warning.message && warning.message.includes('Sourcemap')) {
- return; // Suppress sourcemap warnings
- }
+ if (warning.message && warning.message.includes('Sourcemap')) return;
console.warn(warning);
});
const { app, BrowserWindow, ipcMain, Menu, safeStorage, WebContentsView, session } = require('electron');
const path = require('path');
const { spawn } = require('child_process');
+
+// GlitchTip — main process error monitoring (zero deps, pure fetch)
+const GLITCHTIP_STORE_URL = 'https://app.glitchtip.com/api/21559/store/?sentry_key=16ea5a1e0b304fc086a19d080d003897&sentry_version=7';
+function reportError(err) {
+ try {
+ const crypto = require('crypto');
+ const event = {
+ event_id: crypto.randomUUID().replace(/-/g, ''),
+ timestamp: new Date().toISOString(),
+ platform: 'node',
+ level: 'error',
+ environment: process.env.NODE_ENV || 'production',
+ release: `crowbyte@${require('../package.json').version || '0.0.0'}`,
+ tags: { process: 'main', platform: process.platform },
+ exception: { values: [{ type: err.name || 'Error', value: err.message, stacktrace: err.stack ? { frames: err.stack.split('\n').slice(1).map(l => { const m = l.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/); return m ? { function: m[1] || '?', filename: m[2], lineno: +m[3], colno: +m[4] } : null; }).filter(Boolean).reverse() } : undefined }] },
+ };
+ fetch(GLITCHTIP_STORE_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event) }).catch(() => {});
+ } catch (_) { /* silent */ }
+}
+process.on('uncaughtException', (err) => {
+ if (err.code === 'EPIPE' || err.message?.includes('EPIPE')) return;
+ reportError(err);
+ console.error('[!] Uncaught:', err);
+});
+console.log('[+] GlitchTip main process monitoring active (no SDK)');
const os = require('os');
const plat = require('./platform.cjs');
let pty;
@@ -41,6 +60,10 @@ try {
StdioClientTransport = null;
}
+// Force consistent app name so userData path is always ~/.config/crowbyte/
+// Without this, unpackaged Electron (npx electron) uses ~/.config/Electron/
+app.name = 'crowbyte';
+
// Disable hardware acceleration to prevent GPU errors (if app is available)
if (app && typeof app.disableHardwareAcceleration === 'function') {
app.disableHardwareAcceleration();
@@ -631,7 +654,8 @@ function createOnboardingWindow() {
titleBarStyle: 'hidden',
});
- const isDev = process.env.NODE_ENV === 'development' || process.argv.includes('--dev') || !app.isPackaged;
+ const isForceProduction = process.env.NODE_ENV === 'production';
+ const isDev = !isForceProduction && (process.env.NODE_ENV === 'development' || process.argv.includes('--dev') || !app.isPackaged);
if (isDev) {
mainWindow.loadURL('http://localhost:8081/#/onboarding');
mainWindow.webContents.openDevTools({ mode: 'detach' });
@@ -698,7 +722,7 @@ function createWindow() {
"https://api.ipify.org https://api64.ipify.org https://ipinfo.io " +
"https://api.my-ip.io https://icanhazip.com https://ipecho.net " +
"https://ifconfig.me https://ident.me https://wtfismyip.com " +
- "https://ipapi.co https://check.torproject.org " +
+ "https://ipapi.co " +
"https://api.venice.ai https://ollama.ai https://*.supabase.co wss://*.supabase.co " +
"https://*.hstgr.cloud " +
"wss://*.hstgr.cloud:* " +
@@ -713,7 +737,7 @@ function createWindow() {
"https://api.ipify.org https://api64.ipify.org https://ipinfo.io " +
"https://api.my-ip.io https://icanhazip.com https://ipecho.net " +
"https://ifconfig.me https://ident.me https://wtfismyip.com " +
- "https://ipapi.co https://check.torproject.org " +
+ "https://ipapi.co " +
"https://api.venice.ai https://ollama.ai https://*.supabase.co " +
"https://*.hstgr.cloud " +
"https://integrate.api.nvidia.com http://" + (process.env.VITE_VPS_IP || '127.0.0.1') + ":*; " +
@@ -724,7 +748,9 @@ function createWindow() {
});
// Load the app — dev server in development, built files in production
- const isDev = process.env.NODE_ENV === 'development' || process.argv.includes('--dev') || !app.isPackaged;
+ // NODE_ENV=production overrides !app.isPackaged (Docker runs from source but needs prod mode)
+ const isForceProduction = process.env.NODE_ENV === 'production';
+ const isDev = !isForceProduction && (process.env.NODE_ENV === 'development' || process.argv.includes('--dev') || !app.isPackaged);
if (isDev) {
mainWindow.loadURL('http://localhost:8081');
console.log('[*] Loading from dev server: http://localhost:8081');
@@ -733,6 +759,11 @@ function createWindow() {
console.log('[*] Loading from built files: dist/index.html');
}
+ // Auto-fullscreen in Docker/headless environments (Xvfb + Fluxbox ignores maximize/setBounds)
+ if (isForceProduction && !app.isPackaged) {
+ mainWindow.setFullScreen(true);
+ }
+
// Setup context menu (right-click menu)
mainWindow.webContents.on('context-menu', (event, params) => {
const contextMenu = Menu.buildFromTemplate([
@@ -1620,50 +1651,6 @@ ipcMain.handle('run-command', async (event, command, args = []) => {
});
});
-// Tor check proxy (avoid CORS)
-ipcMain.handle('check-tor', async () => {
- try {
- const https = require('https');
-
- return new Promise((resolve) => {
- const req = https.request('https://check.torproject.org/api/ip', {
- method: 'GET',
- timeout: 5000,
- }, (res) => {
- let data = '';
-
- res.on('data', (chunk) => {
- data += chunk;
- });
-
- res.on('end', () => {
- try {
- const parsed = JSON.parse(data);
- resolve({ success: true, data: parsed });
- } catch (error) {
- resolve({ success: false, error: 'Invalid JSON response' });
- }
- });
- });
-
- req.on('error', (error) => {
- console.error('❌ Tor check error:', error.message);
- resolve({ success: false, error: error.message });
- });
-
- req.on('timeout', () => {
- req.destroy();
- resolve({ success: false, error: 'Request timed out' });
- });
-
- req.end();
- });
- } catch (error) {
- console.error('❌ Tor check handler error:', error);
- return { success: false, error: error.message };
- }
-});
-
// NVD CVE API proxy (avoid CORS and rate limiting)
ipcMain.handle('fetch-cves', async (event, year) => {
try {
diff --git a/apps/desktop/electron/preload.js b/apps/desktop/electron/preload.js
index 60ed02f..ad1fb01 100644
--- a/apps/desktop/electron/preload.js
+++ b/apps/desktop/electron/preload.js
@@ -91,9 +91,6 @@ contextBridge.exposeInMainWorld('electronAPI', {
// Run system command (for DNS detection, etc.)
runCommand: (command, args) => ipcRenderer.invoke('run-command', command, args),
- // Tor check proxy (avoid CORS)
- checkTor: () => ipcRenderer.invoke('check-tor'),
-
// NVD CVE API proxy (avoid CORS)
fetchCVEs: (year) => ipcRenderer.invoke('fetch-cves', year),
diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index 9ba4474..4410cc5 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -17,12 +17,16 @@
"main": "electron/main.cjs",
"scripts": {
"dev": "cross-env NODE_ENV=development vite",
+ "dev:web": "cross-env VITE_BUILD_TARGET=web NODE_ENV=development vite",
"electron:dev": "node electron/launch.cjs",
- "build:vite": "vite build",
- "build:electron": "electron-builder",
- "build:electron:win": "electron-builder --win",
- "build:electron:mac": "electron-builder --mac",
- "build:electron:linux": "electron-builder --linux",
+ "build:vite": "cross-env VITE_BUILD_TARGET=electron vite build",
+ "build:web": "cross-env VITE_BUILD_TARGET=web vite build",
+ "build:web:staging": "cross-env VITE_BUILD_TARGET=web vite build --mode staging",
+ "build:web:production": "cross-env VITE_BUILD_TARGET=web vite build --mode production",
+ "build:electron-pkg": "electron-builder",
+ "build:electron-pkg:win": "electron-builder --win",
+ "build:electron-pkg:mac": "electron-builder --mac",
+ "build:electron-pkg:linux": "electron-builder --linux",
"build": "npm run build:vite",
"build:win": "npm run build:vite",
"build:mac": "npm run build:vite",
@@ -156,6 +160,8 @@
"@radix-ui/react-toggle": "^1.1.9",
"@radix-ui/react-toggle-group": "^1.1.10",
"@radix-ui/react-tooltip": "^1.2.7",
+ "@sentry/browser": "^10.46.0",
+ "@sentry/electron": "^7.10.0",
"@stackblitz/sdk": "^1.11.0",
"@supabase/supabase-js": "^2.81.0",
"@tanstack/react-query": "^5.83.0",
@@ -196,6 +202,7 @@
},
"devDependencies": {
"@eslint/js": "^9.32.0",
+ "@sentry/vite-plugin": "^5.1.1",
"@tailwindcss/typography": "^0.5.16",
"@types/debug": "^4.1.12",
"@types/fs-extra": "^11.0.4",
diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx
index 134b236..aaadae4 100644
--- a/apps/desktop/src/App.tsx
+++ b/apps/desktop/src/App.tsx
@@ -1,5 +1,6 @@
import { useState, useEffect } from "react";
import '@/services/error-monitor';
+import { glitchTipService } from '@/services/glitchtip';
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
@@ -74,9 +75,9 @@ import PreferencesWizard from "./pages/PreferencesWizard";
import SubscriptionGate from "./pages/SubscriptionGate";
import { verifyLicense, needsRecheck, CHECK_INTERVAL_MS, type LicenseStatus } from "@/services/license-guard";
import { needsPreferencesSetup } from "@/services/subscription";
+import { IS_ELECTRON } from "@/lib/platform";
const queryClient = new QueryClient();
-const isElectron = typeof window !== 'undefined' && !!(window as any).electronAPI;
/** Layout wrapper that includes TitleBar — used for all routes except /landing */
const AppWithTitleBar = () => (
@@ -84,13 +85,13 @@ const AppWithTitleBar = () => (
{/* Auth routes without sidebar */}
- } />
- } />
+ } />
+ } />
{/* Documentation - own layout, no main sidebar */}
-