diff --git a/.github/dependabot.yml b/.github/dependabot.yml index aa60cfcde..5603020f5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,8 +5,6 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 - reviewers: - - "louis030195" labels: - "dependencies" - "security" diff --git a/.gitignore b/.gitignore index 0e193043f..71b2669bc 100644 --- a/.gitignore +++ b/.gitignore @@ -202,3 +202,6 @@ apps/desktop/apps/vm-dashboard/public/*.zip # internal ops runbooks, not for public repo .claude/skills/ + +# Local-only backups of deleted GitHub issues (may contain sensitive content) +scripts/deleted-issues-backup/ diff --git a/README.md b/README.md index 55d5b7f4f..06806af56 100644 --- a/README.md +++ b/README.md @@ -1 +1,65 @@ -image +Mediar + +# Mediar + +Capture a browser workflow once, then run it on demand against cloud VMs. Mediar records what you do in the browser, turns it into a reusable workflow, and executes it headlessly through MCP-driven virtual machines. + +Live app: [app.mediar.ai](https://app.mediar.ai) + +## Monorepo layout + +| Path | What it is | +|------|------------| +| `apps/web` | Next.js 15 web app (dashboard, auth, billing, workflow management) | +| `apps/desktop` | Tauri desktop app (React + Rust) for capturing workflows | +| `crates/executor` | Rust workflow executor | +| `modal_apps` | Python executor deployed on [Modal](https://modal.com) | +| `packages/infra` | Azure / telemetry utilities | +| `supabase` | Database schema and migrations | + +## Architecture + +``` +GitHub workflows repo → Modal / Rust executor → MCP VMs → Supabase +``` + +Workflows are stored in a repo, dispatched to the Modal or Rust executor, run on MCP-controlled VMs, and results are persisted to Supabase. + +## Quick start + +Requires [Bun](https://bun.sh) and Node 20 (see `.nvmrc`). + +```bash +bun install +cp .env.example .env.local # fill in your own keys +bun run dev # run all packages +``` + +Useful scripts: + +```bash +bun run dev:web # web app only +bun run dev:desktop # desktop app only (Tauri) +bun run build # build everything +bun run type-check # typecheck all packages +bun run test # run all tests +``` + +## Deploy + +```bash +# Python executor (Modal) +export PYTHONIOENCODING=utf-8 && modal deploy modal_apps/workflow_executor.py + +# Rust executor +bun run deploy:rust # dev +bun run deploy:rust:prod # prod +``` + +## Contributing + +Issues and pull requests are welcome. Run `bun run type-check` and `bun run test` before opening a PR. + +## License + +[MIT](./LICENSE) diff --git a/apps/desktop/scripts/release.ts b/apps/desktop/scripts/release.ts index 59a72a63b..da9373caa 100644 --- a/apps/desktop/scripts/release.ts +++ b/apps/desktop/scripts/release.ts @@ -11,7 +11,7 @@ * ============================================ * * 1. SSL.com Credentials (~\SSL.com\.env) - * - Get the .env file from Louis or another team member + * - Get the .env file from a team member * - Place at: C:\Users\\SSL.com\.env * - Or set MEDIAR_SSL_DIR env var to custom location * - Required variables: diff --git a/apps/web/src/app/api/admin/cost-alerts/route.ts b/apps/web/src/app/api/admin/cost-alerts/route.ts index e0780035c..d41d1602b 100644 --- a/apps/web/src/app/api/admin/cost-alerts/route.ts +++ b/apps/web/src/app/api/admin/cost-alerts/route.ts @@ -61,7 +61,7 @@ export async function GET() { // Return existing settings or defaults const settings: CostAlertSettings = data?.value || { thresholds: DEFAULT_THRESHOLDS, - emailRecipients: ['matt@mediar.ai', 'louis@mediar.ai'], + emailRecipients: ['matt@mediar.ai'], enabled: true, }; diff --git a/apps/web/src/app/api/admin/organizations/[orgId]/members/route.ts b/apps/web/src/app/api/admin/organizations/[orgId]/members/route.ts index 886e20405..c64140e9f 100644 --- a/apps/web/src/app/api/admin/organizations/[orgId]/members/route.ts +++ b/apps/web/src/app/api/admin/organizations/[orgId]/members/route.ts @@ -38,18 +38,9 @@ export async function GET( organization: { id: targetOrgId, name: 'Mediar (Legacy/Dev)', - membersCount: 2 + membersCount: 1 }, members: [ - { - id: 'legacy-1', - userId: 'mediar-admin-1', - email: 'louis@mediar.ai', - firstName: 'Louis', - lastName: 'Beaumont', - role: 'org:admin', - createdAt: new Date().toISOString() - }, { id: 'legacy-2', userId: 'mediar-admin-2', diff --git a/apps/web/src/app/api/cron/llm-usage-reconciliation/route.ts b/apps/web/src/app/api/cron/llm-usage-reconciliation/route.ts index 6aa8b9ff4..3211644e0 100644 --- a/apps/web/src/app/api/cron/llm-usage-reconciliation/route.ts +++ b/apps/web/src/app/api/cron/llm-usage-reconciliation/route.ts @@ -108,7 +108,7 @@ async function sendDiscrepancyAlert(details: { return; } - const recipients = ['matt@mediar.ai', 'louis@mediar.ai']; + const recipients = ['matt@mediar.ai']; const subject = `LLM Token Discrepancy: API ${(details.googleTokens/1e6).toFixed(1)}M vs Traced ${(details.dbTokens/1e6).toFixed(1)}M (${details.discrepancyPercent.toFixed(1)}% diff)`; const body = ` LLM token usage reconciliation detected a significant discrepancy: diff --git a/apps/web/src/app/api/cron/process-pending-notifications/route.ts b/apps/web/src/app/api/cron/process-pending-notifications/route.ts index 74a7bd764..f6db277e5 100644 --- a/apps/web/src/app/api/cron/process-pending-notifications/route.ts +++ b/apps/web/src/app/api/cron/process-pending-notifications/route.ts @@ -11,7 +11,7 @@ async function getOrganizationMembers(orgId: string): Promise { try { // Handle legacy Mediar org (members not in Clerk; fall back to staff). if (isLegacyOrg(orgId)) { - return ['louis@mediar.ai', 'matt@mediar.ai']; + return ['matt@mediar.ai']; } const clerk = await clerkClient(); diff --git a/apps/web/src/app/api/internal/notifications/alerts/route.ts b/apps/web/src/app/api/internal/notifications/alerts/route.ts index a10c4901e..5fd6967bc 100644 --- a/apps/web/src/app/api/internal/notifications/alerts/route.ts +++ b/apps/web/src/app/api/internal/notifications/alerts/route.ts @@ -21,7 +21,7 @@ async function getOrganizationMembers(orgId: string): Promise { // Handle legacy Mediar org (members not in Clerk; fall back to staff). if (isLegacyOrg(orgId)) { - return ['louis@mediar.ai', 'matt@mediar.ai']; + return ['matt@mediar.ai']; } const clerk = await clerkClient(); diff --git a/apps/web/src/app/api/internal/send-notification-email/route.ts b/apps/web/src/app/api/internal/send-notification-email/route.ts index ec578fa96..047f8e1ff 100644 --- a/apps/web/src/app/api/internal/send-notification-email/route.ts +++ b/apps/web/src/app/api/internal/send-notification-email/route.ts @@ -62,7 +62,7 @@ export async function POST(request: NextRequest) { // Send email using Resend const { data, error } = await resend.emails.send({ from: `Mediar.ai <${fromEmail}>`, - replyTo: ['matt@mediar.ai', 'louis@mediar.ai'], + replyTo: ['matt@mediar.ai'], to: Array.isArray(to) ? to : [to], subject: enhancedSubject, html: emailHtml, @@ -476,7 +476,7 @@ function generateEmailHTML(alert: any, _config: any): string {