Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,11 @@ jobs:
- name: Install Playwright (chromium)
run: npx playwright install --with-deps chromium

- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest

- name: Boot Supabase + run two-client Realtime e2e (R1–R7)
run: |
supabase start
npx npx supabase start
./scripts/run-e2e.sh canvas-sync-regressions.spec.ts --project=chromium --workers=2

- name: Stop Supabase
if: always()
run: supabase stop || true
run: npx npx supabase stop || true
4 changes: 2 additions & 2 deletions scripts/run-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
set -euo pipefail

# Auto-fetch keys from local Supabase if not already set
SUPABASE_STATUS_ENV="${SUPABASE_STATUS_ENV:-$(supabase status -o env 2>&1 || true)}"
SUPABASE_STATUS_ENV="${SUPABASE_STATUS_ENV:-$(npx supabase status -o env 2>&1 || true)}"

if [ -z "${SUPABASE_SERVICE_ROLE_KEY:-}" ]; then
# Try new-format secret key first (Supabase v2.x uses sb_secret_* instead of HS256 JWT)
Expand All @@ -27,7 +27,7 @@ if [ -z "${VITE_SUPABASE_ANON_KEY:-}" ]; then
fi

if [ -z "${SUPABASE_SERVICE_ROLE_KEY:-}" ] || [ -z "${VITE_SUPABASE_ANON_KEY:-}" ]; then
echo "ERROR: Could not fetch Supabase keys. Is local Supabase running? (supabase start)"
echo "ERROR: Could not fetch Supabase keys. Is local Supabase running? (npx supabase start)"
exit 1
fi

Expand Down
24 changes: 12 additions & 12 deletions src/components/QuickSortCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
class="quick-sort-card"
:class="{
'swiping': swipeState.isSwiping,
'swipe-left': swipeDirection === 'left',
'swipe-right': swipeDirection === 'right',
'swipe-up': swipeDirection === 'up',
'swipe-down': swipeDirection === 'down'
'swipeLeft': swipeDirection === 'left',
'swipeRight': swipeDirection === 'right',
'swipeUp': swipeDirection === 'up',
'swipeDown': swipeDirection === 'down'
}"
:style="cardStyle"
>
Expand Down Expand Up @@ -85,10 +85,10 @@ defineProps<{
}>()

const emit = defineEmits<{
(e: 'swipe-right'): void
(e: 'swipe-left'): void
(e: 'swipe-up'): void
(e: 'swipe-down'): void
(e: 'swipeRight'): void
(e: 'swipeLeft'): void
(e: 'swipeUp'): void
(e: 'swipeDown'): void
}>()

const cardRef = ref<HTMLElement | null>(null)
Expand All @@ -105,10 +105,10 @@ const {
haptics: true,
fourDirectional: true,
mouse: true,
onSwipeRight: () => emit('swipe-right'),
onSwipeLeft: () => emit('swipe-left'),
onSwipeUp: () => emit('swipe-up'),
onSwipeDown: () => emit('swipe-down')
onSwipeRight: () => emit('swipeRight'),
onSwipeLeft: () => emit('swipeLeft'),
onSwipeUp: () => emit('swipeUp'),
onSwipeDown: () => emit('swipeDown')
})

// Card transform style - supports both horizontal and vertical movement
Expand Down
28 changes: 21 additions & 7 deletions src/components/ai/AIMemoryHealthDashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@
</div>

<!-- Error -->
<div v-if="error" class="error-banner glass">{{ error }}</div>
<div v-if="error" class="error-banner glass">
{{ error }}
</div>

<!-- Summary Cards -->
<div v-if="report" class="summary-cards">
<div class="card glass score-card" :class="gradeClass">
<h3>Memory Grade</h3>
<div class="grade-display">{{ report.grade }}</div>
<div class="grade-display">
{{ report.grade }}
</div>
<p>{{ gradeLabel }}</p>
</div>

Expand All @@ -56,21 +60,27 @@

<div class="card glass stat-card">
<h3>Sections</h3>
<div class="stat-value">{{ report.sections.length }}</div>
<div class="stat-value">
{{ report.sections.length }}
</div>
<p>{{ report.mode === 'full' ? 'Full assessment' : 'Quick check' }}</p>
</div>

<div class="card glass stat-card">
<h3>Duration</h3>
<div class="stat-value stat-value--small">{{ formatDuration(report.durationMs) }}</div>
<div class="stat-value stat-value--small">
{{ formatDuration(report.durationMs) }}
</div>
<p>{{ formatTime(report.timestamp) }}</p>
</div>
</div>

<!-- Empty State -->
<div v-else-if="!isRunning" class="empty-state glass">
<p>No assessment results yet.</p>
<p class="empty-hint">"Quick Check" runs heuristic tests instantly. "Full Assessment" adds LLM-as-judge context utilization tests (~30s).</p>
<p class="empty-hint">
"Quick Check" runs heuristic tests instantly. "Full Assessment" adds LLM-as-judge context utilization tests (~30s).
</p>
</div>

<!-- Sections -->
Expand Down Expand Up @@ -115,7 +125,9 @@
<span class="check-name">{{ check.name }}</span>
<span class="check-score" :class="scoreColorClass(check.score)">{{ check.score }}%</span>
</div>
<div class="check-value">{{ check.value }}</div>
<div class="check-value">
{{ check.value }}
</div>
<div v-if="check.recommendation" class="check-recommendation">
{{ check.recommendation }}
</div>
Expand Down Expand Up @@ -160,7 +172,9 @@
<span class="history-time">{{ formatTime(h.timestamp) }}</span>
</div>
</div>
<button class="btn btn-ghost" @click="handleClearHistory">Clear History</button>
<button class="btn btn-ghost" @click="handleClearHistory">
Clear History
</button>
</div>
</div>
</template>
Expand Down
32 changes: 23 additions & 9 deletions src/components/ai/AIQualityDashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<button
class="btn btn-ghost"
:disabled="isRunning"
@click="handleRunTests(1)"
title="Quick check with 1 run per test"
@click="handleRunTests(1)"
>
Quick (1x)
</button>
Expand Down Expand Up @@ -45,7 +45,9 @@
<div v-if="report" class="summary-cards">
<div class="card glass score-card" :class="gradeClass">
<h3>Overall Grade</h3>
<div class="grade-display">{{ report.grade }}</div>
<div class="grade-display">
{{ report.grade }}
</div>
<p>{{ gradeLabel }}</p>
</div>

Expand All @@ -67,14 +69,18 @@

<div class="card glass stat-card">
<h3>Provider</h3>
<div class="stat-value stat-value--small">{{ report.provider }}</div>
<div class="stat-value stat-value--small">
{{ report.provider }}
</div>
<p>{{ formatTime(report.timestamp) }}</p>
</div>
</div>

<!-- Empty State -->
<div v-else-if="!isRunning" class="empty-state glass">
<h3 class="empty-title">AI Quality Assessment</h3>
<h3 class="empty-title">
AI Quality Assessment
</h3>
<p class="empty-desc">
Tests your AI assistant by sending {{ testPrompts.length }} prompts across {{ new Set(testPrompts.map(t => t.category)).size }} categories,
then judges each response against {{ rubrics.length }} quality rubrics using a second LLM call.
Expand Down Expand Up @@ -129,7 +135,7 @@
<span class="result-grade" :class="scoreColorClass(result.overallScore)">
{{ result.grade }}
</span>
<span class="result-grade-dot" :class="gradeDotClass(result.grade)"></span>
<span class="result-grade-dot" :class="gradeDotClass(result.grade)" />
</div>
</div>

Expand All @@ -142,7 +148,9 @@
<!-- AI Response Preview (first 3 lines) -->
<div class="result-response-preview">
<span class="preview-label">AI Response:</span>
<div class="preview-text">{{ result.response }}</div>
<div class="preview-text">
{{ result.response }}
</div>
</div>

<!-- Simple Verdict (derived from judge reasoning) -->
Expand All @@ -154,12 +162,16 @@
<div v-if="expandedCards.has(result.promptId)" class="expanded-content">
<div class="expanded-section">
<h4>Full AI Response</h4>
<div class="response-text">{{ result.response }}</div>
<div class="response-text">
{{ result.response }}
</div>
</div>

<div v-if="result.judgeReasoning" class="expanded-section">
<h4>Judge's Detailed Assessment</h4>
<div class="judge-text">{{ result.judgeReasoning }}</div>
<div class="judge-text">
{{ result.judgeReasoning }}
</div>
</div>

<!-- Expected Behavior -->
Expand Down Expand Up @@ -260,7 +272,9 @@
<span class="history-time">{{ formatTime(h.timestamp) }}</span>
</div>
</div>
<button class="btn btn-ghost" @click="handleClearHistory">Clear History</button>
<button class="btn btn-ghost" @click="handleClearHistory">
Clear History
</button>
</div>
</div>
</template>
Expand Down
28 changes: 20 additions & 8 deletions src/components/ai/AISetupWizard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@

<!-- ═══ Step 1: Choose Provider ═══ -->
<div v-if="step === 1" class="step-content">
<h2 class="step-title">Set up AI</h2>
<h2 class="step-title">
Set up AI
</h2>
<p class="step-desc">
FlowState uses AI for smart suggestions, task analysis, and chat.
Choose how you'd like to power it.
Expand All @@ -37,7 +39,9 @@
:class="{ selected: chosenProvider === 'groq' }"
@click="chosenProvider = 'groq'"
>
<div class="provider-badge recommended">Recommended</div>
<div class="provider-badge recommended">
Recommended
</div>
<Zap :size="22" class="provider-icon" />
<span class="provider-name">Groq Cloud</span>
<span class="provider-detail">
Expand Down Expand Up @@ -70,7 +74,9 @@

<!-- ═══ Step 2a: Groq Setup ═══ -->
<div v-if="step === 2 && chosenProvider === 'groq'" class="step-content">
<h2 class="step-title">Connect Groq</h2>
<h2 class="step-title">
Connect Groq
</h2>
<p class="step-desc">
Groq offers free AI API access with generous daily limits.
Create a free account and paste your API key below.
Expand All @@ -90,13 +96,13 @@
<label class="field-label">API Key</label>
<div class="input-row">
<input
:type="showKey ? 'text' : 'password'"
v-model="apiKey"
:type="showKey ? 'text' : 'password'"
placeholder="gsk_..."
class="text-input"
spellcheck="false"
autocomplete="off"
/>
>
<button
class="icon-btn"
:title="showKey ? 'Hide' : 'Show'"
Expand Down Expand Up @@ -133,7 +139,9 @@

<!-- ═══ Step 2b: Ollama Setup ═══ -->
<div v-if="step === 2 && chosenProvider === 'ollama'" class="step-content">
<h2 class="step-title">Connect Ollama</h2>
<h2 class="step-title">
Connect Ollama
</h2>
<p class="step-desc">
Ollama runs AI models locally on your machine.
Make sure Ollama is installed and running.
Expand All @@ -147,7 +155,9 @@
</div>

<div v-if="!ollamaDetected" class="ollama-steps">
<p class="setup-instruction">To set up Ollama:</p>
<p class="setup-instruction">
To set up Ollama:
</p>
<ol class="setup-list">
<li>
Install from
Expand Down Expand Up @@ -184,7 +194,9 @@
<div class="confirm-icon">
<CheckCircle2 :size="40" />
</div>
<h2 class="step-title">AI is ready!</h2>
<h2 class="step-title">
AI is ready!
</h2>
<p class="step-desc">
<template v-if="chosenProvider === 'groq'">
Groq Cloud is configured. FlowState will use Llama 3.3 70B for AI features.
Expand Down
Loading
Loading