Files
Cortex-Inara/cortex/main.py
Scott Idem b144d8385f feat: SSH dev routing, model registry UX, chat input toolbar, doc sync
Backend / infrastructure:
- cortex/tools/_projects.py (new): shared project alias registry with ssh_host
  for workstation projects (aether_api, aether_frontend, aether_container)
- cortex/tools/git.py: all git tools route to workstation via SSH when ssh_host set
- cortex/tools/aider.py: aider_run SSH-routes to workstation using bash -l -c
- cortex/routers/local_llm.py: POST /api/models/{id}/edit AJAX endpoint — save
  model edits without page reload or tab reset; returns JSON {ok, label, model_name}
- cortex/llm_client.py: remove Gemini CLI and Claude CLI backends; clean up
  fallback chain and process group tracking (continuation of Gemini CLI removal)
- cortex/routers/auth.py: strip Claude/Gemini CLI auth status checks (CLI removed)
- cortex/routers/chat.py: remove legacy claude/gemini backend fields
- cortex/config.py: clean up CLI-related settings
- cortex/main.py: remove CLI lifecycle hooks

UI:
- cortex/static/local_llm.html: model edit forms now save via fetch() + toast;
  stay on Models tab; update row header label in place on success
- cortex/static/index.html: restructure input area to column layout — textarea
  above, compact toolbar below (Chat/Tools/Attach + Send); fixes dead space at
  M/L/XL sizes; context panel "Role" → "Model" section label
- cortex/static/style.css: column input-area layout; #input-toolbar; flex:1 →
  width:100% on textarea (fixes scrollHeight in column flex context); compact
  send/stop button padding
- cortex/static/app.js: add XL (720px) to height cycle; default M (240px)

Docs:
- cortex/static/HELP.md: S/M/L → S/M/L/XL; add Rebuild to distill table; fix
  "Role selector" references (no such UI); fix "your active role" → Chat role;
  fix  toggle description; Model Registry section cleanup
- documentation/ARCH__BACKENDS.md: reflect CLI removal, current backend state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:14:07 -04:00

76 lines
2.3 KiB
Python

import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
import uvicorn
logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(name)s: %(message)s")
from config import settings
from auth_middleware import SessionAuthMiddleware
from routers import chat, google_chat, nextcloud_talk, homeassistant, files, distill, auth, orchestrator
from routers import ui, onboarding, settings, tools_settings, help, auth_google, local_llm, push, audit, usage, crons
@asynccontextmanager
async def lifespan(app: FastAPI):
import scheduler
scheduler.start()
yield
scheduler.stop()
app = FastAPI(title="Cortex Dispatcher", lifespan=lifespan)
app.add_middleware(SessionAuthMiddleware)
# API routers
app.include_router(chat.router)
app.include_router(google_chat.router)
app.include_router(nextcloud_talk.router)
app.include_router(homeassistant.router)
app.include_router(files.router)
app.include_router(distill.router)
app.include_router(auth.router)
app.include_router(orchestrator.router)
app.include_router(push.router)
app.include_router(audit.router)
app.include_router(usage.router)
# Static files — must be mounted BEFORE ui.router so /static/* is matched first.
# ui.router has a wildcard /{username}/{persona} that would otherwise catch /static/style.css etc.
app.mount("/static", StaticFiles(directory="static"), name="static")
# Google OAuth — must be before ui.router (wildcard /{user}/{persona} would swallow it)
app.include_router(auth_google.router)
# Onboarding (invite tokens + persona creation — before ui.router)
app.include_router(onboarding.router)
# Account settings
app.include_router(settings.router)
app.include_router(tools_settings.router)
app.include_router(local_llm.router)
app.include_router(crons.router)
# Help page
app.include_router(help.router)
# Health check — must be before ui.router so /{username} catch-all doesn't swallow it.
@app.get("/health")
async def health() -> dict:
return {"status": "ok"}
# UI router (login + /{user}/{persona} — must be last to avoid swallowing API paths)
app.include_router(ui.router)
if __name__ == "__main__":
uvicorn.run(
"main:app",
host=settings.host,
port=settings.port,
reload=True,
)