]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/commitdiff
Always show message actions for mobile UI + improvements for user message sizing...
authorAleksander Grygier <redacted>
Fri, 26 Sep 2025 13:59:07 +0000 (15:59 +0200)
committerGitHub <redacted>
Fri, 26 Sep 2025 13:59:07 +0000 (15:59 +0200)
13 files changed:
.gitignore
.windsurf/rules/css-architecture.md [deleted file]
.windsurf/rules/sveltekit-architecture.md [deleted file]
.windsurf/rules/tests.md [deleted file]
.windsurf/rules/typescript-architecture.md [deleted file]
tools/server/public/index.html.gz
tools/server/webui/package.json
tools/server/webui/scripts/dev.sh [new file with mode: 0644]
tools/server/webui/scripts/install-git-hooks.sh
tools/server/webui/scripts/post-build.sh
tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageActions.svelte
tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageUser.svelte
tools/server/webui/src/lib/components/app/misc/MarkdownContent.svelte

index e1ecdb7a81922416d7c66ec3f6e4a1522beefa6e..c7d000978571aca57eb1a2904d9c875e9cfb9d1d 100644 (file)
@@ -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 (file)
index 10a1835..0000000
+++ /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 (file)
index c2c0aa0..0000000
+++ /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 (file)
index e388fa9..0000000
+++ /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 (file)
index a61ff6b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
----
-trigger: manual
----
-
-## TypeScript
-
--   Add JSDocs for functions
index c6d8258d7f81499c0317e6a32c3f89227ac875c4..f12ff3e62e4aa5cbcc060e7366ea2827bbbd358d 100644 (file)
Binary files a/tools/server/public/index.html.gz and b/tools/server/public/index.html.gz differ
index 30c7cd15c673ee7a688fd3011c29cca26bae4613..7bf21bf57cb612e4b77ace15eb44213143ea6159 100644 (file)
@@ -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 (file)
index 0000000..e0e8b26
--- /dev/null
@@ -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
index a2a3ca76f53e1cb1f59a50224c956a669313a59c..d14e2813891f03087b3b79612bb707fd06938699 100755 (executable)
@@ -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
index ae5c1f30be82c0871496f6c788c32560265b513c..a49d6cc107e04edb73efc17e6030fb0004e5fb24 100755 (executable)
@@ -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;
index 287acac7a1231b11b4079b286edad9e5c0f91299..803f8db001569c44c39fb78187397b5e48cdf7c7 100644 (file)
@@ -50,7 +50,7 @@
 
 <div class="relative {justify === 'start' ? 'mt-2' : ''} flex h-6 items-center justify-{justify}">
        <div
-               class="flex items-center text-xs text-muted-foreground transition-opacity group-hover:opacity-0"
+               class="hidden items-center text-xs text-muted-foreground transition-opacity md:flex md:group-hover:opacity-0"
        >
                {new Date(message.timestamp).toLocaleTimeString(undefined, {
                        hour: '2-digit',
        <div
                class="absolute top-0 {actionsPosition === 'left'
                        ? 'left-0'
-                       : 'right-0'} flex items-center gap-2 opacity-0 transition-opacity group-hover:opacity-100"
+                       : 'right-0'} flex items-center gap-2 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100"
        >
                {#if siblingInfo && siblingInfo.totalSiblings > 1}
                        <ChatMessageBranchingControls {siblingInfo} {onNavigateToSibling} />
                {/if}
 
                <div
-                       class="pointer-events-none inset-0 flex items-center gap-1 opacity-0 transition-all duration-150 group-hover:pointer-events-auto group-hover:opacity-100"
+                       class="pointer-events-auto inset-0 flex items-center gap-1 opacity-100 transition-all duration-150 md:pointer-events-none md:opacity-0 md:group-hover:pointer-events-auto md:group-hover:opacity-100"
                >
                        <ActionButton icon={Copy} tooltip="Copy" onclick={onCopy} />
 
index cd0565ef8c07115454a7c1399a770277fba2de7d..ba161ed33f59f39ef3f3ae8ac7762b20a54a9c80 100644 (file)
                onShowDeleteDialogChange,
                textareaElement = $bindable()
        }: Props = $props();
+
+       let isMultiline = $state(false);
+       let messageElement: HTMLElement | undefined = $state();
+
+       $effect(() => {
+               if (!messageElement || !message.content.trim()) return;
+
+               if (message.content.includes('\n')) {
+                       isMultiline = true;
+                       return;
+               }
+
+               const resizeObserver = new ResizeObserver((entries) => {
+                       for (const entry of entries) {
+                               const element = entry.target as HTMLElement;
+                               const estimatedSingleLineHeight = 24; // Typical line height for text-md
+
+                               isMultiline = element.offsetHeight > estimatedSingleLineHeight * 1.5;
+                       }
+               });
+
+               resizeObserver.observe(messageElement);
+
+               return () => {
+                       resizeObserver.disconnect();
+               };
+       });
 </script>
 
 <div
        aria-label="User message with actions"
-       class="group flex flex-col items-end gap-2 {className}"
+       class="group flex flex-col items-end gap-3 md:gap-2 {className}"
        role="group"
 >
        {#if isEditing}
                {/if}
 
                {#if message.content.trim()}
-                       <Card class="max-w-[80%] rounded-2xl bg-primary px-2.5 py-1.5 text-primary-foreground">
-                               <div class="text-md whitespace-pre-wrap">
+                       <Card
+                               class="max-w-[80%] rounded-[1.125rem] bg-primary px-3.75 py-1.5 text-primary-foreground data-[multiline]:py-2.5"
+                               data-multiline={isMultiline ? '' : undefined}
+                       >
+                               <span bind:this={messageElement} class="text-md whitespace-pre-wrap">
                                        {message.content}
-                               </div>
+                               </span>
                        </Card>
                {/if}
 
index c70583e671c41d56fb619fea5cc3da95a6e0be1f..7d62eaadaa82b45b731a2880f9772deca809d79d 100644 (file)
 
 <style>
        /* Base typography styles */
-       div :global(p) {
+       div :global(p:not(:last-child)) {
                margin-bottom: 1rem;
                line-height: 1.75;
        }