Commit Graph

140 Commits

Author SHA1 Message Date
d6c87a052e feat(domains): P5.1 — OpenSRS registration + Cloud DNS + Coolify attach
Adds end-to-end custom apex domain support: workspace-scoped
registration via OpenSRS (Tucows), authoritative DNS via Google
Cloud DNS, and one-call attach that wires registrar nameservers,
DNS records, and Coolify app routing in a single transactional
flow.

Schema (additive, idempotent — run /api/admin/migrate after deploy)
  - vibn_workspaces.dns_provider TEXT DEFAULT 'cloud_dns'
      Per-workspace DNS backend choice. Future: 'cira_dzone' for
      strict CA-only residency on .ca.
  - vibn_domains
      One row per registered/intended apex. Tracks status
      (pending|active|failed|expired), registrar order id, encrypted
      registrar manage-user creds (AES-256-GCM, VIBN_SECRETS_KEY),
      period, dates, dns_provider/zone_id/nameservers, and a
      created_by audit field.
  - vibn_domain_events
      Append-only lifecycle audit (register.attempt/success/fail,
      attach.success, ns.update, lock.toggle, etc).
  - vibn_billing_ledger
      Workspace-scoped money ledger (CAD by default) with
      ref_type/ref_id back to the originating row.

OpenSRS XML client (lib/opensrs.ts)
  - Mode-gated host/key (OPENSRS_MODE=test → horizon sandbox,
    rejectUnauthorized:false; live → rr-n1-tor, strict TLS).
  - MD5 double-hash signature.
  - Pure Node https module (no undici dep).
  - Verbs: lookupDomain, getDomainPrice, checkDomain, registerDomain,
    updateDomainNameservers, setDomainLock, getResellerBalance.
  - TLD policy: minPeriodFor() bumps .ai to 2y; CPR/legalType
    plumbed through for .ca; registrations default to UNLOCKED so
    immediate NS updates succeed without a lock toggle.

DNS provider abstraction (lib/dns/{provider,cloud-dns}.ts)
  - DnsProvider interface (createZone/getZone/setRecords/deleteZone)
    so the workspace residency knob can swap backends later.
  - cloudDnsProvider implementation against Google Cloud DNS using
    the existing vibn-workspace-provisioner SA (roles/dns.admin).
  - Idempotent zone creation, additions+deletions diff for rrsets.

Shared GCP auth (lib/gcp-auth.ts)
  - Single getGcpAccessToken() helper used by Cloud DNS today and
    future GCP integrations. Prefers GOOGLE_SERVICE_ACCOUNT_KEY_B64,
    falls back to ADC.

Workspace-scoped helpers (lib/domains.ts)
  - listDomainsForWorkspace, getDomainForWorkspace, createDomainIntent,
    markDomainRegistered, markDomainFailed, markDomainAttached,
    recordDomainEvent, recordLedgerEntry.

Attach orchestrator (lib/domain-attach.ts)
  Single function attachDomain() reused by REST + MCP. For one
  apex it:
    1. Resolves target → Coolify app uuid OR raw IP OR CNAME.
    2. Ensures Cloud DNS managed zone exists.
    3. Writes A / CNAME records (apex + requested subdomains).
    4. Updates registrar nameservers, with auto unlock-retry-relock
       fallback for TLDs that reject NS changes while locked.
    5. PATCHes the Coolify application's domain list so Traefik
       routes the new hostname.
    6. Persists dns_provider/zone_id/nameservers and emits an
       attach.success domain_event.
  AttachError carries a stable .tag + http status so the caller
  can map registrar/dns/coolify failures cleanly.

REST endpoints
  - POST   /api/workspaces/[slug]/domains/search
  - GET    /api/workspaces/[slug]/domains
  - POST   /api/workspaces/[slug]/domains
  - GET    /api/workspaces/[slug]/domains/[domain]
  - POST   /api/workspaces/[slug]/domains/[domain]/attach
  All routes go through requireWorkspacePrincipal (session OR
  Authorization: Bearer vibn_sk_...). Register is idempotent:
  re-issuing for an existing intent re-attempts at OpenSRS without
  duplicating the row or charging twice.

MCP bridge (app/api/mcp/route.ts → version 2.2.0)
  Adds five tools backed by the same library code:
    - domains.search    (batch availability + pricing)
    - domains.list      (workspace-owned)
    - domains.get       (single + recent events)
    - domains.register  (idempotent OpenSRS register)
    - domains.attach    (full Cloud DNS + registrar + Coolify)

Sandbox smoke tests (scripts/smoke-opensrs-*.ts)
  Standalone Node scripts validating each new opensrs.ts call against
  horizon.opensrs.net: balance + lookup + check, TLD policy
  (.ca/.ai/.io/.com), full register flow, NS update with systemdns
  nameservers, and the lock/unlock toggle that backs the attach
  fallback path.

Post-deploy checklist
  1. POST https://vibnai.com/api/admin/migrate
       -H "x-admin-secret: $ADMIN_MIGRATE_SECRET"
  2. Set OPENSRS_* env vars on the vibn-frontend Coolify app
     (RESELLER_USERNAME, API_KEY_LIVE, API_KEY_TEST, HOST_LIVE,
     HOST_TEST, PORT, MODE). Without them, only domains.list/get
     work; search/register/attach return 500.
  3. GCP_PROJECT_ID is read from env or defaults to master-ai-484822.
  4. Live attach end-to-end against a real apex is queued as a
     follow-up — sandbox path is fully proven.

Not in this commit (deliberate)
  - The 100+ unrelated in-flight files (mvp-setup wizard, justine
    homepage rework, BuildLivePlanPanel, etc) — kept local to keep
    blast radius minimal.

Made-with: Cursor
2026-04-21 16:30:39 -07:00
de1cd96ec2 fix(auth): classify services by service_type, not name heuristics
Coolify exposes the template slug on `service_type`; the list endpoint
returns only summaries, so the auth list handler now fetches each
service individually to classify it reliably. Users can name auth
services anything (e.g. "my-login") and they still show up as auth
providers.

Made-with: Cursor
2026-04-21 12:37:21 -07:00
0797717bc1 Phase 4: AI-driven app/database/auth lifecycle
Workspace-owned deploy infra so AI agents can create and destroy
Coolify resources without ever touching the root admin token.

  vibn_workspaces
    + coolify_server_uuid, coolify_destination_uuid
    + coolify_environment_name (default "production")
    + coolify_private_key_uuid, gitea_bot_ssh_key_id

  ensureWorkspaceProvisioned
    + generates an ed25519 keypair per workspace
    + pushes pubkey to the Gitea bot user (read/write scoped by team)
    + registers privkey in Coolify as a reusable deploy key

  New endpoints under /api/workspaces/[slug]/
    apps/                POST (private-deploy-key from Gitea repo)
    apps/[uuid]          PATCH, DELETE?confirm=<name>
    apps/[uuid]/domains  GET, PATCH (policy: *.{ws}.vibnai.com only)
    databases/           GET, POST (8 types incl. postgres, clickhouse, dragonfly)
    databases/[uuid]     GET, PATCH, DELETE?confirm=<name>
    auth/                GET, POST (Pocketbase, Authentik, Keycloak, Pocket-ID, Logto, Supertokens)
    auth/[uuid]          DELETE?confirm=<name>

  MCP (/api/mcp) gains 15 new tools that mirror the REST surface and
  enforce the same workspace tenancy + delete-confirm guard.

  Safety: destructive ops require ?confirm=<exact-resource-name>; volumes
  are kept by default (pass delete_volumes=true to drop).

Made-with: Cursor
2026-04-21 12:04:59 -07:00
14835e2e0a Revert "fix(gitea-bot): add write:organization scope so bot can create repos"
This reverts commit 6f79a88abd.

Made-with: Cursor
2026-04-21 11:12:20 -07:00
6f79a88abd fix(gitea-bot): add write:organization scope so bot can create repos
Without this the bot PAT 403s on POST /orgs/{org}/repos, which is
the single most important operation — creating new project repos
inside the workspace's Gitea org.

Made-with: Cursor
2026-04-21 11:05:55 -07:00
b9511601bc feat(ai-access): per-workspace Gitea bot + tenant-safe Coolify proxy + MCP
Ship Phases 1–3 of the multi-tenant AI access plan so an AI agent can
act on a Vibn workspace with one bearer token and zero admin reach.

Phase 1 — Gitea bot per workspace
- Add gitea_bot_username / gitea_bot_user_id / gitea_bot_token_encrypted
  columns to vibn_workspaces (migrate route).
- New lib/auth/secret-box.ts (AES-256-GCM, VIBN_SECRETS_KEY) for PAT at rest.
- Extend lib/gitea.ts with createUser, createAccessTokenFor (Sudo PAT),
  createOrgTeam, addOrgTeamMember, ensureOrgTeamMembership.
- ensureWorkspaceProvisioned now mints a vibn-bot-<slug> user, adds it to
  a Writers team (write perms only) on the workspace's org, and stores
  its PAT encrypted.
- GET /api/workspaces/[slug]/gitea-credentials returns a workspace-scoped
  bot PAT + clone URL template; session or vibn_sk_ bearer auth.

Phase 2 — Tenant-safe Coolify proxy + real MCP
- lib/coolify.ts: projectUuidOf, listApplicationsInProject,
  getApplicationInProject, TenantError, env CRUD, deployments list.
- Workspace-scoped REST endpoints (all filtered by coolify_project_uuid):
  GET/POST /api/workspaces/[slug]/apps/[uuid](/deploy|/envs|/deployments),
  GET /api/workspaces/[slug]/deployments/[deploymentUuid]/logs.
- Full rewrite of /api/mcp off legacy Firebase onto Postgres vibn_sk_
  keys, exposing workspace.describe, gitea.credentials, projects.*,
  apps.* (list/get/deploy/deployments, envs.list/upsert/delete).

Phase 3 — Settings UI AI bundle
- GET /api/workspaces/[slug]/bootstrap.sh: curl|sh installer that writes
  .cursor/rules, .cursor/mcp.json and appends VIBN_* to .env.local.
  Embeds the caller's vibn_sk_ token when invoked with bearer auth.
- WorkspaceKeysPanel: single AiAccessBundleCard with system-prompt block,
  one-line bootstrap, Reveal-bot-PAT button, collapsible manual-setup
  fallback. Minted-key modal also shows the bootstrap one-liner.

Ops prerequisites:
  - Set VIBN_SECRETS_KEY (>=16 chars) on the frontend.
  - Run /api/admin/migrate to add the three bot columns.
  - GITEA_API_TOKEN must be a site-admin token (needed for admin/users
    + Sudo PAT mint); otherwise provision_status lands on 'partial'.

Made-with: Cursor
2026-04-21 10:49:17 -07:00
6ccfdee65f fix(settings): use NextAuth session instead of undefined Firebase auth
The settings page imported `auth` from `@/lib/firebase/config` and called
`auth.currentUser` inside an unguarded `useEffect`. Since the app runs on
PostgreSQL + NextAuth (Firebase isn't configured), `auth` was `undefined`
and the uncaught TypeError crashed React's commit, leaving the page blank
behind the Next.js dev error overlay. The WorkspaceKeysPanel never got a
chance to mount even though `/api/workspaces` was returning fine.

Swap to `useSession()` from `next-auth/react` to read display name + email
from the existing NextAuth session. Drop the dead fetch to
`/api/workspace/{slug}/settings`, which was never implemented.

Made-with: Cursor
2026-04-20 21:19:05 -07:00
0bdf598984 fix(workspace-panel): resolve workspace via /api/workspaces, not URL slug
The panel was fetching /api/workspaces/{urlSlug} where {urlSlug}
is whatever is in the `[workspace]` dynamic segment (e.g.
"mark-account"). That slug has nothing to do with vibn_workspaces.slug,
which is derived from the user's email — so the fetch 404'd, the
component showed "Loading workspace…" forever, and minting/revoking
would target a non-existent workspace.

Now:
- GET /api/workspaces lazy-creates a workspace row if the signed-in
  user has none (migration path for accounts created before the
  signIn hook was added).
- WorkspaceKeysPanel discovers the user's actual workspace from that
  list and uses *its* slug for all subsequent calls (details, keys,
  provisioning, revocation).
- Empty / error states render a proper card with a retry button
  instead of a bare "Workspace not found." line.

Made-with: Cursor
2026-04-20 20:43:46 -07:00
acb63a2a5a feat(workspaces): per-account tenancy + AI access keys + Cursor integration
Adds logical multi-tenancy on top of Coolify + Gitea so every Vibn
account gets its own isolated tenant boundary, and exposes that
boundary to AI agents (Cursor, Claude Code, scripts) through
per-workspace bearer tokens.

Schema (additive, idempotent — run /api/admin/migrate once after deploy)
  - vibn_workspaces: slug, name, owner, coolify_project_uuid,
    coolify_team_id (reserved for when Coolify ships POST /teams),
    gitea_org, provision_status
  - vibn_workspace_members: room for multi-user workspaces later
  - vibn_workspace_api_keys: sha256-hashed bearer tokens
  - fs_projects.vibn_workspace_id: nullable FK linking projects
    to their workspace

Provisioning
  - On first sign-in, ensureWorkspaceForUser() inserts the row
    (no network calls — keeps signin fast).
  - On first project create, ensureWorkspaceProvisioned() lazily
    creates a Coolify Project (vibn-ws-{slug}) and a Gitea org
    (vibn-{slug}). Failures are recorded on the row, not thrown,
    and POST /api/workspaces/{slug}/provision retries.

Auth surface
  - lib/auth/workspace-auth.ts: requireWorkspacePrincipal() accepts
    either a NextAuth session or "Authorization: Bearer vibn_sk_...".
    The bearer key is hard-pinned to one workspace — it cannot
    reach any other tenant.
  - mintWorkspaceApiKey / listWorkspaceApiKeys / revokeWorkspaceApiKey

Routes
  - GET    /api/workspaces                         list
  - GET    /api/workspaces/[slug]                  details
  - POST   /api/workspaces/[slug]/provision        retry provisioning
  - GET    /api/workspaces/[slug]/keys             list keys
  - POST   /api/workspaces/[slug]/keys             mint key (token shown once)
  - DELETE /api/workspaces/[slug]/keys/[keyId]     revoke

UI
  - components/workspace/WorkspaceKeysPanel.tsx: identity card,
    keys CRUD with one-time secret reveal, and a "Connect Cursor"
    block with copy/download for:
      .cursor/rules/vibn-workspace.mdc — rule telling the agent
        about the API + workspace IDs + house rules
      ~/.cursor/mcp.json — MCP server registration with key
        embedded (server URL is /api/mcp; HTTP MCP route lands next)
      .env.local — VIBN_API_KEY + smoke-test curl
  - Slotted into existing /[workspace]/settings between Workspace
    and Notifications cards (no other layout changes).

projects/create
  - Resolves the user's workspace (creating + provisioning lazily).
  - Repos go under workspace.gitea_org (falls back to GITEA_ADMIN_USER
    for backwards compat).
  - Coolify services are created inside workspace.coolify_project_uuid
    (renamed {slug}-{appName} to stay unique within the namespace) —
    no more per-Vibn-project Coolify Project sprawl.
  - Stamps vibn_workspace_id on fs_projects.

lib/gitea
  - createOrg, getOrg, addOrgOwner, getUser
  - createRepo now routes /orgs/{owner}/repos when owner != admin

Also includes prior-turn auth hardening that was already in
authOptions.ts (CredentialsProvider for dev-local, isLocalNextAuth
cookie config) bundled in to keep the auth layer in one consistent
state.

.env.example
  - Documents GITEA_API_URL / GITEA_API_TOKEN / GITEA_ADMIN_USER /
    GITEA_WEBHOOK_SECRET and COOLIFY_URL / COOLIFY_API_TOKEN /
    COOLIFY_SERVER_UUID, with the canonical hostnames
    (git.vibnai.com, coolify.vibnai.com).

Post-deploy
  - Run once: curl -X POST https://vibnai.com/api/admin/migrate \\
      -H "x-admin-secret: \$ADMIN_MIGRATE_SECRET"
  - Existing users get a workspace row on next sign-in.
  - Existing fs_projects keep working (legacy gitea owner + their
    own per-project Coolify Projects); new projects use the
    workspace-scoped path.

Not in this commit (follow-ups)
  - Wiring requireWorkspacePrincipal into the rest of /api/projects/*
    so API keys can drive existing routes
  - HTTP MCP server at /api/mcp (the mcp.json snippet already
    points at the right URL — no client re-setup when it lands)
  - Backfill script to assign legacy fs_projects to a workspace

Made-with: Cursor
2026-04-20 17:17:12 -07:00
ccc6cc1da5 feat(justine): isolate design system — verbatim CSS + (justine) route group
- Add app/styles/justine/01-homepage.css: rules from 01_homepage.html scoped to [data-justine]
- Replace app/(marketing) with app/(justine): layout wraps data-justine + Plus Jakarta
- JustineHomePage/Nav/Footer: original class names (btn-ink, hero-grid, …) + inline styles from HTML
- Remove app/justine-marketing.css; move /features /pricing /privacy /terms under (justine)

Made-with: Cursor
2026-04-02 12:05:33 -07:00
74f8dc4282 fix(ui): make Justine palette visible on marketing + trim rainbow chrome
- Replace blue/purple gradients with ink gradient text and cream/parch CTA surface
- Step badges and transformation icons use primary (ink) fills
- /features page icons unified to text-primary; Lora section titles
- Tree view status colors use semantic tokens instead of blue/green

Made-with: Cursor
2026-04-01 21:09:18 -07:00
bada63452f feat(ui): apply Justine ink & parchment design system
- Map Justine tokens to shadcn CSS variables (--vibn-* aliases)
- Switch fonts to Inter + Lora via next/font (IBM Plex Mono for code)
- Base typography: body Inter, h1–h3 Lora; marketing hero + wordmark serif
- Project shell and global chrome use semantic colors
- Replace Outfit/Newsreader references across TSX inline styles

Made-with: Cursor
2026-04-01 21:03:40 -07:00
26429f3517 feat(agent): event timeline API, SSE stream, Coolify DDL, env template
- 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
2026-04-01 11:48:55 -07:00
a11caafd22 feat: add 'Generate architecture' CTA banner on PRD page when arch not yet generated
Made-with: Cursor
2026-03-17 17:23:38 -07:00
8eb6c149cb fix: map Non-Functional Reqs to features_scope phase, remove circular 'Generated when PRD finalized' hint
Made-with: Cursor
2026-03-17 17:15:26 -07:00
f47205c473 rename: replace all user-facing 'Atlas' references with 'Vibn'
Updated UI text in: project-shell (tab label), AtlasChat (sender name),
FreshIdeaMain, TypeSelector, MigrateSetup, ChatImportSetup, FreshIdeaSetup,
CodeImportSetup, prd/page, build/page, projects/page, deployment/page,
activity/page, layout (page title/description), atlas-chat API route.
Code identifiers (AtlasChat component name, file names) unchanged.

Made-with: Cursor
2026-03-17 16:25:41 -07:00
317abf047b Fix auth redirect to use session email instead of hardcoded workspace
New users were being sent to /marks-account/projects. Now derives
workspace from the signed-in user's email so everyone lands on
their own workspace after Google OAuth.

Made-with: Cursor
2026-03-16 21:39:19 -07:00
63dded42a6 fix: repair JSX parse error in PRD page (nested ternary → && conditionals)
Made-with: Cursor
2026-03-10 17:29:05 -07:00
46efc41812 feat: add Architecture tab to PRD page and inject arch into COO context
- PRD page now has a tabbed view: PRD | Architecture
  Architecture tab renders apps, packages, infrastructure, integrations,
  and risk notes as structured cards. Only shown when arch doc exists.
- Advisor route now includes the architecture summary and key fields
  in the COO's knowledge context so the orchestrator knows what's
  been planned technically

Made-with: Cursor
2026-03-10 17:03:43 -07:00
cff5cd6014 fix: pass full PRD to COO without truncation
Made-with: Cursor
2026-03-10 16:36:47 -07:00
8f95270b12 feat: Assist COO routes through Orchestrator on agent runner
The advisor route now proxies to /orchestrator/chat on agents.vibnai.com
instead of calling Gemini directly. The Orchestrator (Claude Sonnet 4.6)
has full tool access — Gitea, Coolify, web search, memory, agent spawning.

- Build project knowledge_context from DB (name, vision, repo, PRD,
  phases, apps, recent sessions) and inject as COO persona + data
- Convert frontend history format (model→assistant) for the orchestrator
- Return orchestrator reply as streaming text response
- Session scoped per project for in-memory context persistence

Made-with: Cursor
2026-03-09 22:32:01 -07:00
ff0e1592fa feat(advisor): load real PRD, phases, sessions, apps into COO system prompt
Made-with: Cursor
2026-03-09 22:14:35 -07:00
1af5595e35 feat(tasks): move Tasks first in toolbar, add Tasks+PRD left nav and content
Made-with: Cursor
2026-03-09 22:02:01 -07:00
528d6bb1e3 fix: remove colon from Coolify project description — fails Coolify validation
Made-with: Cursor
2026-03-09 18:20:33 -07:00
6901a97db3 feat(migrate): wire GitHub PAT through to agent runner mirror call
MigrateSetup now sends the PAT field to the API; create route
forwards it as github_token so the agent runner can clone private repos.

Made-with: Cursor
2026-03-09 18:05:12 -07:00
0e204ced89 feat: store coolifyProjectUuid on project creation for Infrastructure panel
Made-with: Cursor
2026-03-09 17:40:21 -07:00
7979fd0518 fix: detect apps in any repo structure, not just turborepo or flagged imports
Made-with: Cursor
2026-03-09 17:23:38 -07:00
22f4c4f1c3 fix: preview URL resolved from Gitea repo via Coolify git_repository match
Made-with: Cursor
2026-03-09 17:14:55 -07:00
5778abe6c3 feat: add live app preview panel with iframe, URL bar, and reload
Made-with: Cursor
2026-03-09 17:07:33 -07:00
70c94dc60c feat: tool icons drive left nav section, remove inner pills
Made-with: Cursor
2026-03-09 16:49:47 -07:00
853e41705f feat: split top navbar to align with chat/content panels, fix Gemini API key
- Top bar left section (320px) = logo + project name, aligns with chat panel
- Top bar right section = Build|Market|Assist pills + tool icons (Preview, Tasks, Code, Design, Backend) + avatar
- Read GOOGLE_API_KEY inside POST handler (not top-level) to ensure env is resolved at request time

Made-with: Cursor
2026-03-09 16:17:31 -07:00
1ef3f9baa3 feat: top navbar (Build|Market|Assist) + persistent Assist chat in shell
- New top navbar in ProjectShell: logo + project name | Build | Market |
  Assist tabs | user avatar — replaces the left icon sidebar for project pages
- CooChat extracted to components/layout/coo-chat.tsx and moved into the
  shell so it persists across Build/Market/Assist route changes
- Build page inner layout simplified: inner nav (200px) + file viewer,
  no longer owns the chat column
- Layout: [top nav 48px] / [Assist chat 320px | content flex]

Made-with: Cursor
2026-03-09 15:51:48 -07:00
01848ba682 feat: add persistent COO/Assist chat as left-side primary AI interface
- New CooChat component: streaming Gemini-backed advisor chat, message
  bubbles, typing cursor animation, Shift+Enter for newlines
- New /api/projects/[projectId]/advisor streaming endpoint: builds a
  COO system prompt from project context (name, description, vision,
  repo), proxies Gemini SSE stream back to the client
- Restructured BuildHubInner layout:
    Left (340px): CooChat — persistent across all Build sections
    Inner nav (200px): Build pills + contextual items (apps, tree, surfaces)
    Main area: File viewer for Code, Layouts content, Infra content
- AgentMode removed from main view — execution surfaces via COO delegation

Made-with: Cursor
2026-03-09 15:34:41 -07:00
86f8960aa3 refactor: redesign Build page layout — sidebar nav+tree, agent as main, file viewer on right
- B (left sidebar, 260px): project header, Build pills (Code/Layouts/Infra),
  app list, file tree embedded below active app
- D (center): AgentMode as primary content; sessions shown as a horizontal
  chip strip at the top instead of a 220px left sidebar
- Right (460px): FileViewer — shows file selected in B's tree / code changes
- F (bottom): Terminal collapsible strip unchanged
- Split CodeContent into FileTree + FileViewer components; lifted file
  selection state to BuildHubInner so B and Right share it

Made-with: Cursor
2026-03-09 15:00:28 -07:00
2e0bc95bb0 refactor: replace code mode tabs with persistent Browse | Agent split + collapsible terminal
Removes the Browse/Agent/Terminal tab switcher from the code section.
Browse (file tree + viewer) is now the left pane, Agent chat is a
fixed 420px right pane, and Terminal is a collapsible strip at the
bottom — all visible simultaneously.

Made-with: Cursor
2026-03-09 14:29:35 -07:00
01c2d33208 fix: strip backticks from CODEBASE_MAP.md path parsing
Paths wrapped in backticks like `app/` were being captured with
the backtick character, producing invalid app names and paths.

Made-with: Cursor
2026-03-09 14:21:25 -07:00
65adcd4897 feat: detect apps for imported non-turborepo projects
- Fall back to CODEBASE_MAP.md parsing when no apps/ dir exists
- Further fallback: scan top-level dirs for deployable app signals
  (package.json, Dockerfile, requirements.txt, next.config.*, etc.)
- Skips docs, scripts, keys, and other non-app directories
- Returns isImport flag to frontend for context

Made-with: Cursor
2026-03-09 11:52:10 -07:00
9c277fd8e3 feat: add GitHub import flow, project delete fix, and analyze API
- Mirror GitHub repos to Gitea as-is on import (skip scaffold)
- Auto-trigger ImportAnalyzer agent after successful mirror
- Add POST/GET /api/projects/[projectId]/analyze route
- Fix project delete button visibility (was permanently opacity:0)
- Store isImport, importAnalysisStatus, importAnalysisJobId on projects

Made-with: Cursor
2026-03-09 11:30:51 -07:00
fc59333383 feat: auto-approve UI + session status approved
- sessions POST: look up coolifyServiceUuid, pass autoApprove:true to runner
- sessions PATCH: approved added to terminal statuses (sets completed_at)
- build/page.tsx: approved status, STATUS_COLORS/LABELS for "Shipped",
  auto-committed UI in changed files panel, bottom bar for approved state
- Architecture doc: fully updated with current state

Made-with: Cursor
2026-03-07 13:17:33 -08:00
7b228ebad2 fix(agent): context-aware task input, auto-select active session
- Running/pending: input locked with "agent is working" message
- Done: shows "+ Follow up" and "New task" buttons instead of open input
- No session: normal new-task input (unchanged UX)
- On mount: auto-selects the most recent running/pending session,
  falls back to latest session — so navigating away and back doesn't
  lose context and doesn't require manual re-selection

Made-with: Cursor
2026-03-07 13:01:16 -08:00
7f61295637 fix: remove ::uuid casts on project_id/p.id in all agent session routes
Made-with: Cursor
2026-03-07 12:44:45 -08:00
8c19dc1802 feat: agent session retry + follow-up UX
- retry/route.ts: reset failed/stopped session and re-fire agent runner
  with optional continueTask follow-up text
- build/page.tsx: Retry button and Follow up input appear on failed/stopped
  sessions so users can continue without losing context or creating a
  duplicate session; task input hint clarifies each Run = new session

Made-with: Cursor
2026-03-07 12:25:58 -08:00
28b48b74af fix: surface agent_sessions 500 and add db migration
- sessions/route.ts: replace inline CREATE TABLE DDL with a lightweight
  existence check; add `details` to all 500 responses; fix type-unsafe
  `p.id = $1::uuid` comparisons to `p.id::text = $1` to avoid the
  Postgres `text = uuid` operator error
- app/api/admin/migrate: one-shot idempotent migration endpoint secured
  with ADMIN_MIGRATE_SECRET, creates fs_* tables + agent_sessions
- scripts/migrate-fs-tables.sql: formal schema for all fs_* tables

Made-with: Cursor
2026-03-07 12:16:16 -08:00
f7d38317b2 fix: add ::uuid casts to all agent_sessions queries
PostgreSQL can't implicitly coerce text params to UUID columns.
Add explicit ::uuid casts on id and project_id in all agent session
routes (list, get, patch, stop, approve).

Made-with: Cursor
2026-03-07 11:49:40 -08:00
18f61fe95c approve & commit flow + adaptive polling in Agent mode
- Wire Approve & commit button: shows commit message input, calls
  POST /api/.../sessions/[id]/approve which asks agent runner to
  git commit + push, then marks session as approved in DB
- Adaptive polling: 500ms while session running, 5s when idle —
  output feels near-real-time without hammering the API
- Auto-refresh session list when a session completes
- Open in Theia links to theia.vibnai.com (escape hatch for manual edits)

Made-with: Cursor
2026-03-07 11:36:55 -08:00
61a43ad9b4 pass giteaRepo to agent runner; add runner secret auth on PATCH
- Sessions route now reads giteaRepo from project.data and forwards it
  to /agent/execute so the runner can clone/update the correct repo
- PATCH route now validates x-agent-runner-secret header to prevent
  unauthorized session output injection

Made-with: Cursor
2026-03-06 18:01:33 -08:00
ad3abd427b feat: agent execution scaffold — sessions DB, API, and Browse/Agent/Terminal UI
Session model:
- agent_sessions table (auto-created on first use): id, project_id,
  app_name, app_path, task, status, output (JSONB log), changed_files,
  error, timestamps
- POST /agent/sessions — create session, fires off to agent-runner
  (gracefully degrades when runner not yet wired)
- GET  /agent/sessions — list sessions newest first
- GET  /agent/sessions/[id] — full session state for polling
- PATCH /agent/sessions/[id] — internal: agent-runner appends output lines
- POST /agent/sessions/[id]/stop — stop running session

Build > Code section now has three mode tabs:
- Browse — existing file tree + code viewer
- Agent — task input, session list sidebar, live output stream,
           changed files panel, Approve & commit / Open in Theia actions,
           2s polling (Phase 3 will replace with WebSocket)
- Terminal — xterm.js placeholder (Phase 4)

Architecture documented in AGENT_EXECUTION_ARCHITECTURE.md

Made-with: Cursor
2026-03-06 17:56:10 -08:00
3cd477c295 feat: restructure project nav to Atlas | PRD | Build | Growth | Assist | Analytics
Tab bar:
- Removed: Design, Launch, Grow, Insights, Settings tabs
- Added: Growth, Assist, Analytics as top-level tabs
- Build remains, now a full hub

Build hub (/build):
- Left sub-nav groups: Code (apps), Layouts (surfaces), Infrastructure (6 items)
- Code section: scoped file browser per selected app
- Layouts section: surface overview cards with Edit link to /design
- Infrastructure section: summary panel linking to /infrastructure?tab=

Growth (/growth):
- Left nav: Marketing Site, Communications, Channels, Pages
- Each section: description + feature item grid + feedback CTA

Assist (/assist):
- Left nav: Emails, Chat Support, Support Site, Communications
- Each section: description + feature item grid + feedback CTA

Analytics (/analytics):
- Left nav: Customers, Usage, Events, Reports
- Each section: description + feature item grid + feedback CTA

Made-with: Cursor
2026-03-06 14:36:11 -08:00
3770ba1853 feat: Infrastructure section with 6 sub-sections (Builds, Databases, Services, Environment, Domains, Logs)
- Sidebar Infrastructure replaced with 6 named rows linking to /infrastructure?tab=
- New /infrastructure page with left sub-nav and per-tab content panels:
  Builds — lists deployed Coolify apps with live status
  Databases — coming soon placeholder
  Services — coming soon placeholder
  Environment — variable table with masked values (scaffold)
  Domains — lists configured domains with SSL status
  Logs — dark terminal panel, ready to stream
- Dim state on rows reflects whether data exists (e.g. no domains = dim)

Made-with: Cursor
2026-03-06 14:18:03 -08:00
39167dbe45 feat: deep-link sidebar Layouts to specific design surface
- Sidebar Layouts items now link to /design?surface=<surfaceId>
- Design page reads ?surface= param and opens that surface directly
- DesignPage split into DesignPageInner + Suspense wrapper so
  useSearchParams works in the Next.js static build

Made-with: Cursor
2026-03-06 14:12:29 -08:00