- Add agent_session_events table + GET/POST events + SSE stream routes - Build Agent tab: hydrate from events + EventSource while running - entrypoint: create agent_sessions + agent_session_events on container start - .env.example for AGENT_RUNNER_URL, AGENT_RUNNER_SECRET, DATABASE_URL Made-with: Cursor
92 lines
3.8 KiB
Bash
92 lines
3.8 KiB
Bash
#!/bin/sh
|
|
set -e
|
|
|
|
echo "=== Syncing NextAuth schema ==="
|
|
# NOTE: Do NOT use --accept-data-loss — it drops tables not in the Prisma schema,
|
|
# which destroys fs_users, fs_projects etc. Use --skip-generate only.
|
|
npx prisma db push --skip-generate || echo "Prisma push failed (non-fatal — tables may already be correct)"
|
|
|
|
echo "=== Ensuring app tables exist ==="
|
|
node -e "
|
|
const { Pool } = require('pg');
|
|
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
pool.query(\`
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
CREATE TABLE IF NOT EXISTS fs_users (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
user_id TEXT,
|
|
data JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_fs_users_email_unique ON fs_users ((data->>'email'));
|
|
CREATE INDEX IF NOT EXISTS idx_fs_users_user_id ON fs_users (user_id);
|
|
CREATE TABLE IF NOT EXISTS fs_projects (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
user_id TEXT REFERENCES fs_users(id) ON DELETE CASCADE,
|
|
workspace TEXT, slug TEXT,
|
|
data JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_fs_projects_user_id ON fs_projects (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_fs_projects_slug ON fs_projects (slug);
|
|
CREATE TABLE IF NOT EXISTS fs_sessions (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
user_id TEXT REFERENCES fs_users(id) ON DELETE CASCADE,
|
|
data JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_fs_sessions_user_id ON fs_sessions (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_fs_sessions_project_id ON fs_sessions ((data->>'projectId'));
|
|
CREATE TABLE IF NOT EXISTS fs_knowledge_items (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
project_id TEXT NOT NULL,
|
|
data JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_fs_knowledge_project_id ON fs_knowledge_items (project_id);
|
|
CREATE TABLE IF NOT EXISTS chat_conversations (
|
|
project_id TEXT PRIMARY KEY,
|
|
messages JSONB NOT NULL DEFAULT '[]',
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE TABLE IF NOT EXISTS agent_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
project_id TEXT NOT NULL,
|
|
app_name TEXT NOT NULL,
|
|
app_path TEXT NOT NULL,
|
|
task TEXT NOT NULL,
|
|
plan JSONB,
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
output JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
changed_files JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
error TEXT,
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS agent_sessions_project_idx ON agent_sessions (project_id, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS agent_sessions_status_idx ON agent_sessions (status);
|
|
CREATE TABLE IF NOT EXISTS agent_session_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
session_id UUID NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE,
|
|
project_id TEXT NOT NULL,
|
|
seq INT NOT NULL,
|
|
ts TIMESTAMPTZ NOT NULL,
|
|
type TEXT NOT NULL,
|
|
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
client_event_id UUID UNIQUE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
UNIQUE(session_id, seq)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS agent_session_events_session_seq_idx ON agent_session_events (session_id, seq);
|
|
\`).then(() => { console.log('App tables ready'); pool.end(); }).catch(e => { console.error('Table init error:', e.message); pool.end(); });
|
|
"
|
|
|
|
echo "=== Starting Next.js server ==="
|
|
exec node server.js
|