diff --git a/AGENTS.md b/AGENTS.md index dc2791f..58b7691 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,7 +26,7 @@ proof-of-work/ ← the Next.js app (THIS is where you run npm) app/main/ ← authed UI; navigation.tsx = sidebar components/ ← React components (workouts/, ai/, settings/) lib/ai/ ← AI subsystem (see below) - lib/ai/providers/ ← claude.ts openai.ts gemini.ts ollama.ts + index.ts (getProvider; openai.ts exports both openai + openai-compatible = 5 registered providers) + lib/ai/providers/ ← claude.ts openai.ts gemini.ts ollama.ts sparkcontrol.ts + index.ts (getProvider; openai.ts exports both openai + openai-compatible = 6 registered providers) prisma/schema.prisma ← schema (mirror; real DB migrates via entrypoint ALTERs) prisma/*.seed.json ← curated exercise library + AI templates (reconciled each boot) tests/ ← Vitest specs (ai-*.test.ts, routes-*.test.ts, ...) @@ -116,15 +116,15 @@ Canonical publish path for this project: `~/.proof-of-work/publish.sh` (builds, ## Current state -Latest version is **1.2.0:6** — **AI "generate today's workout"**: describe one session in plain words → a streamed, ready-to-log workout (suggested weights/reps/set-counts grounded in 90-day history) → inline-edit or **Refine** (round-trips changes back to the LLM) → **Use this workout** pre-fills the New Workout form (nothing persists until you save). Reuses the program-generation spine via a new `AIGeneration.kind` discriminant (`"program" | "workout"`); workout rows are ephemeral (the saved Workout is the durable record) so they're filtered out of the program-shaped AI History. New `AIGeneration.kind` column (default "program") via boot-time guarded `ALTER`. **Architecture + hand-off (sessionStorage `?from=ai` → `AiWorkoutPrefill`, `EditWorkoutData.id?`→CREATE, per-exercise weight-unit grounding) are documented in `docs/guides/ai-subsystem.md` → "Two generation kinds".** **Built + sideloaded** (`immense-voyage.local`, 2026-06-19, `master`) as `proof-of-work_x86_64.s9pk` (80M). tsc clean (app + packaging), lint clean (pre-existing only), **251 tests pass**, `next build` + s9pk build succeed. Registry empty, **publishing parked** (sideload-only via `make install`). +Latest version is **1.2.0:7** — **SparkControl AI provider + base-URL footgun fix**. Adds a 6th provider, **SparkControl (local)** — the operator's own self-hosted local-inference gateway. OpenAI-compatible wire format (reuses `generateOpenAIStyle`), **keyless** on the LAN (`requireApiKey:false` → no `Authorization` header), reached over the **internal same-box StartOS address** `http://spark-control.startos:9999/v1` (plain HTTP — no TLS, no cert-skip; the public LAN interface is HTTPS w/ a self-signed cert we deliberately avoid). The Settings form **auto-detects the loaded vLLM model** via SparkControl's `/api/endpoints` (`app/api/ai/sparkcontrol/model`, admin-only + SSRF-guarded), mirroring Ollama auto-detect; $0 in the cost UI. Also fixes a **config footgun** (origin of this session): a custom base URL could ride along to a fixed-URL provider (claude/openai/gemini) whose form field is hidden, get stored, and be **silently ignored** (the provider hits its hardcoded endpoint) — both config write paths (`configs` POST + `[id]` PATCH) now null `baseUrl` for non-custom-URL providers and the form clears it on provider change. **No schema/data change** (`AIConfigProfile.provider` is a free-text column). Details: `docs/guides/ai-subsystem.md` → Provider abstraction (incl. the new "adding a provider" fan-out checklist). **Built + sideloaded** (`immense-voyage.local`, 2026-06-19, `master`) as `proof-of-work_x86_64.s9pk` (80M). tsc clean (app + packaging), lint clean (pre-existing only), **259 tests pass**, `next build` + s9pk build succeed. Registry empty, **publishing parked** (sideload-only via `make install`). **Design contract established this session (2026-06-19, committed `7fda9ce`, no UI code changed):** the `design/` folder now holds the durable contract — `DESIGN.md` (9-section brief) + `tokens.tokens.json` (DTCG) + `brand/palette.css` + `inspiration/` provenance. From a Case-B *document-as-is* extract of the as-built dark UI: **monochrome gym-brutalist** (`#0A0A0A` canvas, zinc-only neutral, white primary button, Bebas-uppercase/tracked headings, flat border-based depth), plus two owner calls — **red elevated to the single brand accent `#DC2626`** and a **two-tier radius** (4px controls / 8px containers). AGENTS.md carries the read-before-UI Design line; `ROADMAP.md` → **Design** holds the `design-checker` cleanup backlog (gray→zinc, green→emerald, yellow→amber, `rounded-md`→`rounded`, overlay-only shadows, and a shared `