diff --git a/.gitignore b/.gitignore index e1ecdb7a81922..c7d000978571a 100644 --- a/.gitignore +++ b/.gitignore @@ -149,6 +149,6 @@ poetry.toml /run-chat.sh .ccache/ -# Code Workspace +# IDE *.code-workspace - +.windsurf/ diff --git a/.windsurf/rules/css-architecture.md b/.windsurf/rules/css-architecture.md deleted file mode 100644 index 10a183585ce73..0000000000000 --- a/.windsurf/rules/css-architecture.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -trigger: manual ---- - -#### Tailwind & CSS - -- We are using Tailwind v4 which uses oklch colors so we now want to refer to the CSS vars directly, without wrapping it with any color function like `hsla/hsl`, `rgba` etc. diff --git a/.windsurf/rules/sveltekit-architecture.md b/.windsurf/rules/sveltekit-architecture.md deleted file mode 100644 index c2c0aa07cee74..0000000000000 --- a/.windsurf/rules/sveltekit-architecture.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -trigger: manual ---- - -# Coding rules - -## Svelte & SvelteKit - -### Services vs Stores Separation Pattern - -#### `lib/services/` - Pure Business Logic - -- **Purpose**: Stateless business logic and external communication -- **Contains**: - - API calls to external services (ApiService) - - Pure business logic functions (ChatService, etc.) -- **Rules**: - - NO Svelte runes ($state, $derived, $effect) - - NO reactive state management - - Pure functions and classes only - - Can import types but not stores - - Focus on "how" - implementation details - -#### `lib/stores/` - Reactive State Management - -- **Purpose**: Svelte-specific reactive state with runes -- **Contains**: - - Reactive state classes with $state, $derived, $effect - - Database operations (DatabaseStore) - - UI-focused state management - - Store orchestration logic -- **Rules**: - - USE Svelte runes for reactivity - - Import and use services for business logic - - NO direct database operations - - NO direct API calls (use services) - - Focus on "what" - reactive state for UI - -#### Enforcement - -- Services should be testable without Svelte -- Stores should leverage Svelte's reactivity system -- Clear separation: services handle data, stores handle state -- Services can be reused across multiple stores - -#### Misc - -- Always use `let` for $derived state variables diff --git a/.windsurf/rules/tests.md b/.windsurf/rules/tests.md deleted file mode 100644 index e388fa954472a..0000000000000 --- a/.windsurf/rules/tests.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -trigger: manual ---- - -# Automated Tests - -## General rules - -- NEVER include any test code in the production code - we should always have it in a separate dedicated files diff --git a/.windsurf/rules/typescript-architecture.md b/.windsurf/rules/typescript-architecture.md deleted file mode 100644 index a61ff6b98fbb3..0000000000000 --- a/.windsurf/rules/typescript-architecture.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -trigger: manual ---- - -## TypeScript - -- Add JSDocs for functions diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz index c6d8258d7f814..f12ff3e62e4aa 100644 Binary files a/tools/server/public/index.html.gz and b/tools/server/public/index.html.gz differ diff --git a/tools/server/webui/package.json b/tools/server/webui/package.json index 30c7cd15c673e..7bf21bf57cb61 100644 --- a/tools/server/webui/package.json +++ b/tools/server/webui/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "scripts": { - "dev": "vite dev --host 0.0.0.0 & storybook dev -p 6006 --ci", + "dev": "bash scripts/dev.sh", "build": "vite build && ./scripts/post-build.sh", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", @@ -20,7 +20,8 @@ "test:ui": "vitest --project=ui", "test:unit": "vitest", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "cleanup": "rm -rf .svelte-kit build node_modules test-results" }, "devDependencies": { "@chromatic-com/storybook": "^4.0.1", diff --git a/tools/server/webui/scripts/dev.sh b/tools/server/webui/scripts/dev.sh new file mode 100644 index 0000000000000..e0e8b26e9a013 --- /dev/null +++ b/tools/server/webui/scripts/dev.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +cd ../../../ + +# Check and install git hooks if missing +check_and_install_hooks() { + local hooks_missing=false + + # Check for required hooks + if [ ! -f ".git/hooks/pre-commit" ] || [ ! -f ".git/hooks/pre-push" ] || [ ! -f ".git/hooks/post-push" ]; then + hooks_missing=true + fi + + if [ "$hooks_missing" = true ]; then + echo "๐ง Git hooks missing, installing them..." + cd tools/server/webui + if bash scripts/install-git-hooks.sh; then + echo "โ Git hooks installed successfully" + else + echo "โ ๏ธ Failed to install git hooks, continuing anyway..." + fi + cd ../../../ + else + echo "โ Git hooks already installed" + fi +} + +# Install git hooks if needed +check_and_install_hooks + +# Check if llama-server binary already exists +if [ ! -f "build/bin/llama-server" ]; then + echo "Building llama-server..." + cmake -B build && cmake --build build --config Release -t llama-server +else + echo "llama-server binary already exists, skipping build." +fi + +# Start llama-server and capture output +echo "Starting llama-server..." +mkfifo server_output.pipe +build/bin/llama-server -hf ggml-org/gpt-oss-20b-GGUF --jinja -c 0 --no-webui > server_output.pipe 2>&1 & +SERVER_PID=$! + +# Function to wait for server to be ready +wait_for_server() { + echo "Waiting for llama-server to be ready..." + local max_wait=60 + local start_time=$(date +%s) + + # Read server output in background and look for the ready message + ( + while IFS= read -r line; do + echo "๐ Server: $line" + if [[ "$line" == *"server is listening on http://127.0.0.1:8080 - starting the main loop"* ]]; then + echo "โ llama-server is ready!" + echo "READY" > server_ready.flag + break + fi + done < server_output.pipe + ) & + + # Wait for ready flag or timeout + while [ ! -f server_ready.flag ]; do + local current_time=$(date +%s) + local elapsed=$((current_time - start_time)) + + if [ $elapsed -ge $max_wait ]; then + echo "โ Server failed to start within $max_wait seconds" + rm -f server_ready.flag + return 1 + fi + + sleep 1 + done + + rm -f server_ready.flag + return 0 +} + +# Cleanup function +cleanup() { + echo "๐งน Cleaning up..." + kill $SERVER_PID 2>/dev/null + rm -f server_output.pipe server_ready.flag + exit +} + +# Set up signal handlers +trap cleanup SIGINT SIGTERM + +# Wait for server to be ready +if wait_for_server; then + echo "๐ Starting development servers..." + cd tools/server/webui + storybook dev -p 6006 --ci & vite dev --host 0.0.0.0 & + + # Wait for all background processes + wait +else + echo "โ Failed to start development environment" + cleanup +fi diff --git a/tools/server/webui/scripts/install-git-hooks.sh b/tools/server/webui/scripts/install-git-hooks.sh index a2a3ca76f53e1..d14e2813891f0 100755 --- a/tools/server/webui/scripts/install-git-hooks.sh +++ b/tools/server/webui/scripts/install-git-hooks.sh @@ -1,14 +1,14 @@ #!/bin/bash -# Script to install pre-commit and post-commit hooks for webui -# Pre-commit: formats, lints, checks, and builds code, stashes unstaged changes -# Post-commit: automatically unstashes changes +# Script to install pre-commit and pre-push hooks for webui +# Pre-commit: formats code and runs checks +# Pre-push: builds the project, stashes unstaged changes REPO_ROOT=$(git rev-parse --show-toplevel) PRE_COMMIT_HOOK="$REPO_ROOT/.git/hooks/pre-commit" -POST_COMMIT_HOOK="$REPO_ROOT/.git/hooks/post-commit" +PRE_PUSH_HOOK="$REPO_ROOT/.git/hooks/pre-push" -echo "Installing pre-commit and post-commit hooks for webui..." +echo "Installing pre-commit and pre-push hooks for webui..." # Create the pre-commit hook cat > "$PRE_COMMIT_HOOK" << 'EOF' @@ -16,7 +16,7 @@ cat > "$PRE_COMMIT_HOOK" << 'EOF' # Check if there are any changes in the webui directory if git diff --cached --name-only | grep -q "^tools/server/webui/"; then - echo "Formatting webui code..." + echo "Formatting and checking webui code..." # Change to webui directory and run format cd tools/server/webui @@ -27,20 +27,12 @@ if git diff --cached --name-only | grep -q "^tools/server/webui/"; then exit 1 fi - # Stash any unstaged changes to avoid conflicts during format/build - echo "Stashing unstaged changes..." - git stash push --keep-index --include-untracked -m "Pre-commit hook: stashed unstaged changes" - STASH_CREATED=$? - # Run the format command npm run format # Check if format command succeeded if [ $? -ne 0 ]; then echo "Error: npm run format failed" - if [ $STASH_CREATED -eq 0 ]; then - echo "You can restore your unstaged changes with: git stash pop" - fi exit 1 fi @@ -50,9 +42,6 @@ if git diff --cached --name-only | grep -q "^tools/server/webui/"; then # Check if lint command succeeded if [ $? -ne 0 ]; then echo "Error: npm run lint failed" - if [ $STASH_CREATED -eq 0 ]; then - echo "You can restore your unstaged changes with: git stash pop" - fi exit 1 fi @@ -62,73 +51,151 @@ if git diff --cached --name-only | grep -q "^tools/server/webui/"; then # Check if check command succeeded if [ $? -ne 0 ]; then echo "Error: npm run check failed" - if [ $STASH_CREATED -eq 0 ]; then - echo "You can restore your unstaged changes with: git stash pop" - fi exit 1 fi - # Run the build command - npm run build + # Go back to repo root + cd ../../.. - # Check if build command succeeded - if [ $? -ne 0 ]; then - echo "Error: npm run build failed" - if [ $STASH_CREATED -eq 0 ]; then - echo "You can restore your unstaged changes with: git stash pop" - fi + echo "โ Webui code formatted and checked successfully" +fi + +exit 0 +EOF + +# Create the pre-push hook +cat > "$PRE_PUSH_HOOK" << 'EOF' +#!/bin/bash + +# Check if there are any webui changes that need building +WEBUI_CHANGES=$(git diff --name-only @{push}..HEAD | grep "^tools/server/webui/" || true) + +if [ -n "$WEBUI_CHANGES" ]; then + echo "Webui changes detected, checking if build is up-to-date..." + + # Change to webui directory + cd tools/server/webui + + # Check if npm is available and package.json exists + if [ ! -f "package.json" ]; then + echo "Error: package.json not found in tools/server/webui" exit 1 fi - - # Go back to repo root to add build output - cd ../../.. - # Add the build output to staging area - git add tools/server/public/index.html.gz + # Check if build output exists and is newer than source files + BUILD_FILE="../public/index.html.gz" + NEEDS_BUILD=false - if [ $STASH_CREATED -eq 0 ]; then - echo "โ Build completed. Your unstaged changes have been stashed." - echo "They will be automatically restored after the commit." - # Create a marker file to indicate stash was created by pre-commit hook - touch .git/WEBUI_STASH_MARKER + if [ ! -f "$BUILD_FILE" ]; then + echo "Build output not found, building..." + NEEDS_BUILD=true + else + # Check if any source files are newer than the build output + if find src -newer "$BUILD_FILE" -type f | head -1 | grep -q .; then + echo "Source files are newer than build output, rebuilding..." + NEEDS_BUILD=true + fi + fi + + if [ "$NEEDS_BUILD" = true ]; then + echo "Building webui..." + + # Stash any unstaged changes to avoid conflicts during build + echo "Checking for unstaged changes..." + if ! git diff --quiet || ! git diff --cached --quiet --diff-filter=A; then + echo "Stashing unstaged changes..." + git stash push --include-untracked -m "Pre-push hook: stashed unstaged changes" + STASH_CREATED=$? + else + echo "No unstaged changes to stash" + STASH_CREATED=1 + fi + + # Run the build command + npm run build + + # Check if build command succeeded + if [ $? -ne 0 ]; then + echo "Error: npm run build failed" + if [ $STASH_CREATED -eq 0 ]; then + echo "You can restore your unstaged changes with: git stash pop" + fi + exit 1 + fi + + # Go back to repo root + cd ../../.. + + # Check if build output was created/updated + if [ -f "tools/server/public/index.html.gz" ]; then + # Add the build output and commit it + git add tools/server/public/index.html.gz + if ! git diff --cached --quiet; then + echo "Committing updated build output..." + git commit -m "chore: update webui build output" + echo "โ Build output committed successfully" + else + echo "Build output unchanged" + fi + else + echo "Error: Build output not found after build" + if [ $STASH_CREATED -eq 0 ]; then + echo "You can restore your unstaged changes with: git stash pop" + fi + exit 1 + fi + + if [ $STASH_CREATED -eq 0 ]; then + echo "โ Build completed. Your unstaged changes have been stashed." + echo "They will be automatically restored after the push." + # Create a marker file to indicate stash was created by pre-push hook + touch .git/WEBUI_PUSH_STASH_MARKER + fi + else + echo "โ Build output is up-to-date" fi - echo "Webui code formatted successfully" + echo "โ Webui ready for push" fi exit 0 EOF -# Create the post-commit hook -cat > "$POST_COMMIT_HOOK" << 'EOF' +# Create the post-push hook (for restoring stashed changes after push) +cat > "$REPO_ROOT/.git/hooks/post-push" << 'EOF' #!/bin/bash -# Check if we have a stash marker from the pre-commit hook -if [ -f .git/WEBUI_STASH_MARKER ]; then - echo "Restoring your unstaged changes..." +# Check if we have a stash marker from the pre-push hook +if [ -f .git/WEBUI_PUSH_STASH_MARKER ]; then + echo "Restoring your unstaged changes after push..." git stash pop - rm -f .git/WEBUI_STASH_MARKER + rm -f .git/WEBUI_PUSH_STASH_MARKER echo "โ Your unstaged changes have been restored." fi exit 0 EOF -# Make both hooks executable +# Make all hooks executable chmod +x "$PRE_COMMIT_HOOK" -chmod +x "$POST_COMMIT_HOOK" +chmod +x "$PRE_PUSH_HOOK" +chmod +x "$REPO_ROOT/.git/hooks/post-push" if [ $? -eq 0 ]; then - echo "โ Pre-commit and post-commit hooks installed successfully!" - echo " Pre-commit: $PRE_COMMIT_HOOK" - echo " Post-commit: $POST_COMMIT_HOOK" + echo "โ Git hooks installed successfully!" + echo " Pre-commit: $PRE_COMMIT_HOOK" + echo " Pre-push: $PRE_PUSH_HOOK" + echo " Post-push: $REPO_ROOT/.git/hooks/post-push" echo "" echo "The hooks will automatically:" - echo " โข Format, lint, check, and build webui code before commits" - echo " โข Stash unstaged changes during the process" - echo " โข Restore your unstaged changes after the commit" + echo " โข Format and check webui code before commits (pre-commit)" + echo " โข Build webui code before pushes (pre-push)" + echo " โข Stash unstaged changes during build process" + echo " โข Restore your unstaged changes after the push" echo "" - echo "To test the hooks, make a change to a file in the webui directory and commit it." + echo "To test the hooks:" + echo " โข Make a change to a file in the webui directory and commit it (triggers format/check)" + echo " โข Push your commits to trigger the build process" else echo "โ Failed to make hooks executable" exit 1 diff --git a/tools/server/webui/scripts/post-build.sh b/tools/server/webui/scripts/post-build.sh index ae5c1f30be82c..a49d6cc107e04 100755 --- a/tools/server/webui/scripts/post-build.sh +++ b/tools/server/webui/scripts/post-build.sh @@ -1,3 +1,3 @@ rm -rf ../public/_app; rm ../public/favicon.svg; -rm ../public/index.html; \ No newline at end of file +rm ../public/index.html; diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageActions.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageActions.svelte index 287acac7a1231..803f8db001569 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageActions.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageActions.svelte @@ -50,7 +50,7 @@