Compare commits

..

7 Commits

Author SHA1 Message Date
Keysat 0ed41765da Mine AGENTS.md brain onto disk: resolve TODOs, extract AI subsystem guide
CI / proof-of-work (Next.js app) (push) Has been cancelled
CI / start9/0.4 (StartOS package code) (push) Has been cancelled
Retrofit per the playbook. Resolve both AGENTS.md TODOs with verified
facts (make-target set; db:seed is live at image-build + local dev),
reconcile the AI-provider count (4 files -> 5 registered providers), and
extract the AI subsystem cheat-sheet into docs/guides/ai-subsystem.md,
lazy-loaded via a .claude/rules symlink with an index line in AGENTS.md.

All AGENTS.md commands verified green (tests 177/177, build, tsc, lint).
2026-06-12 20:26:14 -05:00
Keysat 29b9d2437c Add AGENTS.md, ROADMAP.md, and CLAUDE.md symlink
Onboarding doc for fresh agent sessions: stack, commands, layout,
conventions, and an Always/Never list of gotchas hit during the AI
overhaul. Current state section tracks the 1.1.0:7 checkpoint.
ROADMAP.md holds the longer-term backlog. CLAUDE.md symlinks AGENTS.md
so Claude Code loads it. Secrets kept out — private registry/file-host
URLs and creds referenced by file location, not value.
2026-06-12 20:02:27 -05:00
Keysat 1a77a0bfc2 v1.1.0:7 — exercise-history popup auto-loads on scroll
The popup HAD an IntersectionObserver-based infinite scroll (since
v1.0.0:6 alongside the main workout-history page), but the observer
was unreliable inside an `absolute`-positioned scroll container with
a small 60px rootMargin. It often didn't fire at all — leaving the
user with a popup that scrolled internally but never fetched more
data even when hundreds of history entries existed server-side.

Fix: replace IntersectionObserver with a plain `scroll` event
listener on the popup. Fires whenever the user scrolls within 300px
of the bottom (matching WorkoutsList's lookahead on the main page).
Also runs once on mount in case the first page doesn't fill the
popup.

Bottom status row now shows "Loading more..." / "Scroll to load
more" / "End of history" so the user has feedback on state.

No schema, no API, no data.
2026-05-13 09:35:53 -05:00
Keysat 01529204cb v1.1.0:6 — exercise history popup scrolls further
The clock-icon popup in the workout editor was capped at max-h-80
(~320px = ~5 history rows). Users with multi-year history saw older
sessions hidden behind a tiny inner scrollbar. Bumped to 70vh so it
scales with the viewport — ~15+ rows on a normal display, more on a
large monitor.

The IntersectionObserver pagination already loaded more rows on
demand; the old cap just kept them off-screen.

Pure CSS-class change. No schema, no API, no data.
2026-05-13 09:28:32 -05:00
Keysat 35539a9341 v1.1.0:5 — Gemini model menu correctness
User pointed out their Google AI Studio dropdown shows gemini-3-pro,
gemini-3.1-pro, gemini-3-flash and gemini-2.5-flash — not the longer
preview names I shipped in v1.1.0:4. The menu was missing all the
Flash variants entirely.

Fix:
  - Add gemini-3.1-pro (short form, what AI Studio shows)
  - Add gemini-3.1-flash + gemini-3.1-flash-lite (the cheapest 3.x)
  - Add gemini-3-pro + gemini-3-flash (older tier, still available)
  - Pricing entries for all of the above (~$0.50/$3 per M for Flash)

Pure data fix; no schema or behavior changes.
2026-05-11 12:51:17 -05:00
Keysat 7a62690a4a v1.1.0:4 — multi-config AI, background generation, ollama auto-detect, system prompt overhaul
User-feedback-driven release after testing v1.1.0:3. Nine themes:

1. Multi-config persistence
   - New AIConfigProfile table (per-user). Save N configs, toggle one
     active. Switching providers no longer wipes the previous setup.
   - UserPreferences gains activeAIConfigId; legacy single-config
     columns are mirrored from the active profile so existing reads
     keep working without conditional logic.
   - Idempotent boot migration lifts any existing single-config row
     into a default profile.

2. Ollama auto-detect
   - The "Add config" form probes /api/tags on the StartOS internal
     addresses (ollama.startos / ollama.embassy on :11434). If
     reachable: URL pre-fills, model field becomes a dropdown of
     installed models. Fixes the copy-paste UX.

3. Curated model dropdowns for major providers
   - Claude: Opus 4.7, Sonnet 4.6 (1M ctx), Haiku 4.5
   - OpenAI: GPT-5.5, 5.4, 5.4-mini, 5.4-nano
   - Gemini: 3.1-pro-preview, 2.5-pro, 2.5-flash, etc.
   - "Other (type your own)" stays for niche models.
   - Fixes "I tried gemini-3.0-pro and got 404."

4. Background generation
   - lib/ai/generationRunner.ts: detached runner with in-memory
     pub/sub bus. POST /api/ai/generate kicks it off and returns
     immediately. SSE stream attaches by id. The runner survives
     request cancellation; navigating away no longer kills it.
   - New AIGeneration columns: progressText (in-flight stream),
     durationMs (final wall-clock).
   - Generate UI shows a banner explaining background-safety.
   - History detail page polls progress + renders partial JSON
     live for cross-process resume (page refresh, new tab).

5. System prompt overhaul
   - lib/ai/systemPromptBase.ts: structural contract prepended to
     every template. Forces JSON-only output, library-exerciseId
     usage (kills "exerciseId doesn't belong to this user" errors),
     and per-resistance-exercise suggestedWeight (with-history vs
     without-history variants).
   - aiExerciseSchema + ProgramExercise gain suggestedWeight +
     suggestedWeightUnit. Starting a workout from a ProgramDay
     pre-populates SetLog.weight from the suggestion.

6. Test connection improvements
   - Latency in seconds (was ms — confusing for slow Ollama).
   - Stale "✓ Connected" clears on form change.
   - Per-config Test (no need to activate first).
   - Generous maxOutputTokens for thinking models.
   - Gemini surfaces finishReason on empty response (e.g. "blocked
     by safety filter") instead of generic "empty response."
   - Test endpoint accepts a draft body so you can verify before
     saving + before activating.

7. History detail view
   - Click row → full program tree + exact prompts sent. Apply from
     here without re-generating. Pending rows poll for progress.

8. Sidebar sub-navigation
   - AI: Generate / History / Templates
   - Settings: General / Password / Sessions / AI integration /
     Export / Instance (admin) / Danger zone, with anchor scroll.

9. API key UX
   - "Key saved" indicator on saved configs (was confusing to see
     an empty input after a successful save).

Schema migrations (additive, idempotent in entrypoint):
  - AIConfigProfile table created
  - UserPreferences.activeAIConfigId
  - AIGeneration.progressText + durationMs
  - ProgramExercise.suggestedWeight + suggestedWeightUnit

Tests: 16 new (systemPromptBase, modelMenu, generationRunner). 177
total pass.
2026-05-11 08:09:01 -05:00
Keysat dba478aa23 v1.1.0:3 — AI upgrades: history context, test connection, cost estimator, streaming preview
Four incremental upgrades to the AI program generator. No schema change, no /data migration.

1. History as context (the killer feature)
   - lib/ai/historyContext.ts builds a 90-day per-exercise rollup:
     frequency, recent weights, estimated 1RM (Epley), avg RPE,
     days-since-last, plus a STAGNANT flag when the heaviest weight in
     the new half doesn't beat the old half.
   - Generate page surfaces an "Include my workout history as context"
     checkbox (default on at >=10 logged workouts). When checked, the
     ~1-3 KB summary is appended to the system prompt so the model can
     recommend things like "you've stalled bench at 245 — try paused reps."
   - We deliberately don't ship raw set logs (privacy + token cost).

2. Test connection
   - POST /api/ai/test sends a tiny "say hi in 3 words" prompt and
     reports latency + first sample, or the error inline.
   - "Test connection" button next to "Save AI config" in
     Settings -> AI integration. Verifies provider/model/key/baseUrl
     without going through full program generation.

3. Cost estimator
   - lib/ai/pricing.ts ships a price table for major models
     (Claude 3.5/3.7/4/4.5, GPT-4o/5/o1/o3/o4-mini, Gemini 1.5/2.0/2.5).
     Ollama always returns 0; openai-compatible returns null.
   - Generation history shows per-row cost + a 30-day rolling total
     at the top of the page.

4. Streaming preview render
   - lib/ai/lenientJson.ts: stack-aware partial-JSON parser that
     auto-closes open strings/brackets/braces in reverse-of-opening
     order, drops dangling key:value pairs and partial keywords.
     Returns a best-effort snapshot of the program-so-far on each chunk.
   - Generate UI now renders a live "Building program..." panel that
     updates as weeks/days/exercises arrive instead of just showing
     raw text and waiting for stream end.

Tests: 26 new (ai-historyContext.test.ts, ai-lenientJson.test.ts,
ai-pricing.test.ts). 161 total pass.
2026-05-10 22:17:35 -05:00

Diff Content Not Available