const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const { spawnSync } = require('node:child_process'); const rootDir = process.cwd(); test('web and worker boot cleanly in direct node mode', (t) => { const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mastermind-startup-')); const env = { ...process.env, DATA_DIR: dataDir, DATABASE_URL: 'memory://smoke', SESSION_SECRET: 'smoke-test-secret', BOOTSTRAP_OWNER_EMAIL: 'owner@local', BOOTSTRAP_OWNER_PASSWORD: 'owner', MASTERMIND_DISABLE_LISTEN: '1', NODE_ENV: 'test', WORKER_TICK_MS: '100', WORKER_RUN_ONCE: '1' }; t.after(() => { fs.rmSync(dataDir, { recursive: true, force: true }); }); const web = spawnSync(process.execPath, ['web/src/index.js'], { cwd: rootDir, env, encoding: 'utf8' }); const worker = spawnSync(process.execPath, ['worker/src/worker.js'], { cwd: rootDir, env, encoding: 'utf8' }); assert.equal(web.status, 0, web.stderr || web.stdout); assert.equal(worker.status, 0, worker.stderr || worker.stdout); }); test('memory-backed flow supports project creation, email sorting, and draft generation', async () => { const [{ createMemoryPool }, { applyRulesToEmail }, { buildPCOBody }] = await Promise.all([ import('../web/src/lib/memory-db.js'), import('../web/src/lib/email-rules.js'), import('../web/src/lib/utils.js') ]); const pool = createMemoryPool(); const ownerInsert = await pool.query( "insert into users(email, display_name, role) values ($1,'Owner','owner') returning id", ['owner@local'] ); const ownerId = ownerInsert.rows[0].id; await pool.query( "insert into identities(user_id, provider, email, password_hash) values ($1,'local',$2,$3)", [ownerId, 'owner@local', 'hash'] ); const projectInsert = await pool.query( `insert into projects(created_by_user_id,name,job_number,role_mode,gc_name,city,state,keywords) values ($1,$2,$3,$4,$5,$6,$7,$8) returning id`, [ownerId, 'Smoke Test Project', '0222600001', 'ec', 'Example GC', 'Durham', 'NC', 'smoke'] ); const projectId = projectInsert.rows[0].id; await pool.query( `insert into project_members(project_id,user_id,project_role) values ($1,$2,'owner') on conflict do nothing`, [projectId, ownerId] ); await pool.query( `insert into email_rules(created_by_user_id, project_id, match_type, match_value, priority) values ($1,$2,$3,$4,$5) returning id`, [ownerId, projectId, 'subject_contains', '0222600001', 10] ); const emailInsert = await pool.query( `insert into ingested_emails(created_by_user_id, source, from_addr, to_addr, cc_addr, subject, date, body_text, body_html, has_attachments, raw_path, sha256, status) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,'unsorted') returning *`, [ ownerId, 'upload', 'pm@example.com', 'team@example.com', '', 'RE: 0222600001 coordination', new Date('2026-03-01T12:00:00.000Z'), 'Need pricing and schedule impact.', '', false, '/tmp/sample.eml', 'abc123' ] ); const email = emailInsert.rows[0]; const rules = (await pool.query( `select * from email_rules where enabled=true order by priority asc, created_at asc` )).rows; const match = await applyRulesToEmail(email, rules); assert.deepEqual( { projectId: match.projectId, confidence: match.confidence }, { projectId, confidence: 0.9 } ); await pool.query( `update ingested_emails set project_id=$1, status=$2, confidence=$3 where id=$4`, [projectId, 'assigned', match.confidence, email.id] ); const assignedEmails = await pool.query( `select id, from_addr, subject, date, source from ingested_emails where project_id=$1 order by date desc nulls last, created_at desc limit 300`, [projectId] ); assert.equal(assignedEmails.rows.length, 1); assert.equal(assignedEmails.rows[0].subject, 'RE: 0222600001 coordination'); const body = buildPCOBody(email, { name: 'Smoke Test Project', job_number: '0222600001' }); const draftInsert = await pool.query( `insert into pco_drafts(created_by_user_id, project_id, source_email_id, title, body) values ($1,$2,$3,$4,$5) returning id`, [ownerId, projectId, email.id, 'PCO: RE: 0222600001 coordination', body] ); const draft = await pool.query('select * from pco_drafts where id=$1', [draftInsert.rows[0].id]); assert.equal(draft.rows[0].source_email_id, email.id); assert.match(draft.rows[0].body, /Need pricing and schedule impact\./); });