#!/usr/bin/env tsx /** * Bootstrap a new pitch admin user. * * Usage: * tsx scripts/create-admin.ts --email=ben@breakpilot.ai --name="Benjamin" --password='...' * * Or via env vars (useful in CI): * PITCH_ADMIN_BOOTSTRAP_EMAIL=... PITCH_ADMIN_BOOTSTRAP_NAME=... PITCH_ADMIN_BOOTSTRAP_PASSWORD=... \ * tsx scripts/create-admin.ts * * Idempotent: if an admin with the email already exists, the password is updated * (so you can use it to reset). The script always re-activates the account. */ import { Pool } from 'pg' import bcrypt from 'bcryptjs' function arg(name: string): string | undefined { const prefix = `--${name}=` const m = process.argv.find(a => a.startsWith(prefix)) return m ? m.slice(prefix.length) : undefined } const email = (arg('email') || process.env.PITCH_ADMIN_BOOTSTRAP_EMAIL || '').trim().toLowerCase() const name = arg('name') || process.env.PITCH_ADMIN_BOOTSTRAP_NAME || 'Admin' const password = arg('password') || process.env.PITCH_ADMIN_BOOTSTRAP_PASSWORD || '' if (!email || !password) { console.error('ERROR: --email and --password are required (or set env vars).') console.error(' tsx scripts/create-admin.ts --email=user@example.com --name="Name" --password=secret') process.exit(1) } if (password.length < 12) { console.error('ERROR: password must be at least 12 characters.') process.exit(1) } const pool = new Pool({ connectionString: process.env.DATABASE_URL || 'postgres://breakpilot:breakpilot123@localhost:5432/breakpilot_db', }) async function main() { const hash = await bcrypt.hash(password, 12) const { rows } = await pool.query( `INSERT INTO pitch_admins (email, name, password_hash, is_active) VALUES ($1, $2, $3, true) ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name, password_hash = EXCLUDED.password_hash, is_active = true, updated_at = NOW() RETURNING id, email, name, created_at`, [email, name, hash], ) const row = rows[0] console.log(`✓ Admin ready: ${row.email} (${row.name})`) console.log(` id: ${row.id}`) console.log(` created_at: ${row.created_at.toISOString()}`) await pool.end() } main().catch(err => { console.error('ERROR:', err.message) pool.end().catch(() => {}) process.exit(1) })