ruflo 3.42.2 → 3.42.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +422 -422
- package/bin/ruflo.js +77 -77
- package/package.json +117 -117
- package/src/chat-ui/Dockerfile +25 -25
- package/src/chat-ui/patch-mcp-url-safety.sh +28 -28
- package/src/config/config.example.json +76 -76
- package/src/mcp-bridge/Dockerfile +47 -47
- package/src/mcp-bridge/index.js +1780 -1780
- package/src/mcp-bridge/mcp-stdio-kernel.js +159 -159
- package/src/mcp-bridge/package.json +17 -17
- package/src/mcp-bridge/test-harness.js +470 -470
- package/src/mcp-bridge/test-runtime-security.mjs +208 -208
- package/src/mcp-bridge/test-security-lock.js +121 -121
- package/src/nginx/Dockerfile +10 -10
- package/src/nginx/nginx.conf +67 -67
- package/src/nginx/static/favicon-dark.svg +4 -4
- package/src/nginx/static/favicon.svg +4 -4
- package/src/nginx/static/icon.svg +5 -5
- package/src/nginx/static/logo.svg +9 -9
- package/src/nginx/static/manifest.json +22 -22
- package/src/nginx/static/welcome.js +184 -184
- package/src/ruvocal/.claude/skills/add-model-descriptions/SKILL.md +73 -73
- package/src/ruvocal/.devcontainer/Dockerfile +9 -9
- package/src/ruvocal/.devcontainer/devcontainer.json +36 -36
- package/src/ruvocal/.dockerignore +16 -16
- package/src/ruvocal/.eslintignore +13 -13
- package/src/ruvocal/.eslintrc.cjs +45 -45
- package/src/ruvocal/.gcloudignore +18 -18
- package/src/ruvocal/.github/ISSUE_TEMPLATE/bug-report--chat-ui-.md +43 -43
- package/src/ruvocal/.github/ISSUE_TEMPLATE/config-support.md +9 -9
- package/src/ruvocal/.github/ISSUE_TEMPLATE/feature-request--chat-ui-.md +17 -17
- package/src/ruvocal/.github/ISSUE_TEMPLATE/huggingchat.md +11 -11
- package/src/ruvocal/.github/release.yml +16 -16
- package/src/ruvocal/.github/workflows/build-docs.yml +18 -18
- package/src/ruvocal/.github/workflows/build-image.yml +142 -142
- package/src/ruvocal/.github/workflows/build-pr-docs.yml +20 -20
- package/src/ruvocal/.github/workflows/deploy-dev.yml +63 -63
- package/src/ruvocal/.github/workflows/deploy-prod.yml +78 -78
- package/src/ruvocal/.github/workflows/lint-and-test.yml +84 -84
- package/src/ruvocal/.github/workflows/slugify.yaml +72 -72
- package/src/ruvocal/.github/workflows/trufflehog.yml +17 -17
- package/src/ruvocal/.github/workflows/upload-pr-documentation.yml +16 -16
- package/src/ruvocal/.husky/lint-stage-config.js +4 -4
- package/src/ruvocal/.husky/pre-commit +2 -2
- package/src/ruvocal/.prettierignore +14 -14
- package/src/ruvocal/.prettierrc +7 -7
- package/src/ruvocal/CLAUDE.md +126 -126
- package/src/ruvocal/Dockerfile +96 -96
- package/src/ruvocal/LICENSE +202 -202
- package/src/ruvocal/PRIVACY.md +41 -41
- package/src/ruvocal/README.md +164 -164
- package/src/ruvocal/chart/Chart.yaml +5 -5
- package/src/ruvocal/chart/env/dev.yaml +260 -260
- package/src/ruvocal/chart/env/prod.yaml +273 -273
- package/src/ruvocal/chart/templates/_helpers.tpl +22 -22
- package/src/ruvocal/chart/templates/config.yaml +10 -10
- package/src/ruvocal/chart/templates/deployment.yaml +81 -81
- package/src/ruvocal/chart/templates/hpa.yaml +45 -45
- package/src/ruvocal/chart/templates/infisical.yaml +24 -24
- package/src/ruvocal/chart/templates/ingress-internal.yaml +32 -32
- package/src/ruvocal/chart/templates/ingress.yaml +32 -32
- package/src/ruvocal/chart/templates/network-policy.yaml +36 -36
- package/src/ruvocal/chart/templates/service-account.yaml +13 -13
- package/src/ruvocal/chart/templates/service-monitor.yaml +17 -17
- package/src/ruvocal/chart/templates/service.yaml +21 -21
- package/src/ruvocal/chart/values.yaml +73 -73
- package/src/ruvocal/cloudbuild.yaml +68 -68
- package/src/ruvocal/config/branding.env.example +19 -19
- package/src/ruvocal/docker-compose.yml +21 -21
- package/src/ruvocal/docs/adr/ADR-029-HUGGINGFACE-CHAT-UI-CLOUD-RUN.md +1236 -1236
- package/src/ruvocal/docs/adr/ADR-033-RUVECTOR-RUFLO-MCP-INTEGRATION.md +111 -111
- package/src/ruvocal/docs/adr/ADR-034-OPTIONAL-MCP-BACKENDS.md +117 -117
- package/src/ruvocal/docs/adr/ADR-035-MCP-TOOL-GROUPS.md +186 -186
- package/src/ruvocal/docs/adr/ADR-037-AUTOPILOT-CHAT-MODE.md +1500 -1500
- package/src/ruvocal/docs/adr/ADR-038-RUVOCAL-FORK.md +286 -286
- package/src/ruvocal/docs/source/_toctree.yml +30 -30
- package/src/ruvocal/docs/source/configuration/common-issues.md +38 -38
- package/src/ruvocal/docs/source/configuration/llm-router.md +105 -105
- package/src/ruvocal/docs/source/configuration/mcp-tools.md +84 -84
- package/src/ruvocal/docs/source/configuration/metrics.md +9 -9
- package/src/ruvocal/docs/source/configuration/open-id.md +57 -57
- package/src/ruvocal/docs/source/configuration/overview.md +89 -89
- package/src/ruvocal/docs/source/configuration/theming.md +20 -20
- package/src/ruvocal/docs/source/developing/architecture.md +48 -48
- package/src/ruvocal/docs/source/index.md +53 -53
- package/src/ruvocal/docs/source/installation/docker.md +43 -43
- package/src/ruvocal/docs/source/installation/helm.md +43 -43
- package/src/ruvocal/docs/source/installation/local.md +62 -62
- package/src/ruvocal/entrypoint.sh +18 -18
- package/src/ruvocal/mcp-bridge/Dockerfile +47 -47
- package/src/ruvocal/mcp-bridge/cloudbuild.yaml +49 -49
- package/src/ruvocal/mcp-bridge/index.js +1995 -1995
- package/src/ruvocal/mcp-bridge/mcp-stdio-kernel.js +159 -159
- package/src/ruvocal/mcp-bridge/package-lock.json +762 -762
- package/src/ruvocal/mcp-bridge/package.json +17 -17
- package/src/ruvocal/mcp-bridge/test-harness.js +470 -470
- package/src/ruvocal/package-lock.json +11741 -11741
- package/src/ruvocal/package.json +121 -121
- package/src/ruvocal/postcss.config.js +6 -6
- package/src/ruvocal/rvf.manifest.json +204 -204
- package/src/ruvocal/scripts/config.ts +64 -64
- package/src/ruvocal/scripts/generate-welcome.mjs +181 -181
- package/src/ruvocal/scripts/populate.ts +288 -288
- package/src/ruvocal/scripts/samples.txt +194 -194
- package/src/ruvocal/scripts/setups/vitest-setup-server.ts +44 -44
- package/src/ruvocal/scripts/updateLocalEnv.ts +48 -48
- package/src/ruvocal/src/ambient.d.ts +7 -7
- package/src/ruvocal/src/app.d.ts +29 -29
- package/src/ruvocal/src/app.html +53 -53
- package/src/ruvocal/src/hooks.server.ts +32 -32
- package/src/ruvocal/src/hooks.ts +6 -6
- package/src/ruvocal/src/lib/APIClient.ts +148 -148
- package/src/ruvocal/src/lib/actions/clickOutside.ts +18 -18
- package/src/ruvocal/src/lib/actions/snapScrollToBottom.ts +346 -346
- package/src/ruvocal/src/lib/buildPrompt.ts +33 -33
- package/src/ruvocal/src/lib/components/AnnouncementBanner.svelte +20 -20
- package/src/ruvocal/src/lib/components/BackgroundGenerationPoller.svelte +168 -168
- package/src/ruvocal/src/lib/components/CodeBlock.svelte +73 -73
- package/src/ruvocal/src/lib/components/CopyToClipBoardBtn.svelte +92 -92
- package/src/ruvocal/src/lib/components/DeleteConversationModal.svelte +75 -75
- package/src/ruvocal/src/lib/components/EditConversationModal.svelte +100 -100
- package/src/ruvocal/src/lib/components/ExpandNavigation.svelte +22 -22
- package/src/ruvocal/src/lib/components/FoundationBackground.svelte +242 -242
- package/src/ruvocal/src/lib/components/HoverTooltip.svelte +44 -44
- package/src/ruvocal/src/lib/components/HtmlPreviewModal.svelte +143 -143
- package/src/ruvocal/src/lib/components/InfiniteScroll.svelte +50 -50
- package/src/ruvocal/src/lib/components/MobileNav.svelte +300 -300
- package/src/ruvocal/src/lib/components/Modal.svelte +115 -115
- package/src/ruvocal/src/lib/components/ModelCardMetadata.svelte +71 -71
- package/src/ruvocal/src/lib/components/NavConversationItem.svelte +151 -151
- package/src/ruvocal/src/lib/components/NavMenu.svelte +313 -313
- package/src/ruvocal/src/lib/components/Pagination.svelte +97 -97
- package/src/ruvocal/src/lib/components/PaginationArrow.svelte +27 -27
- package/src/ruvocal/src/lib/components/Portal.svelte +24 -24
- package/src/ruvocal/src/lib/components/RetryBtn.svelte +18 -18
- package/src/ruvocal/src/lib/components/RuFloUniverse.svelte +185 -185
- package/src/ruvocal/src/lib/components/RufloHelpModal.svelte +411 -411
- package/src/ruvocal/src/lib/components/ScrollToBottomBtn.svelte +47 -47
- package/src/ruvocal/src/lib/components/ScrollToPreviousBtn.svelte +77 -77
- package/src/ruvocal/src/lib/components/ShareConversationModal.svelte +182 -182
- package/src/ruvocal/src/lib/components/StopGeneratingBtn.svelte +69 -69
- package/src/ruvocal/src/lib/components/SubscribeModal.svelte +87 -87
- package/src/ruvocal/src/lib/components/Switch.svelte +36 -36
- package/src/ruvocal/src/lib/components/SystemPromptModal.svelte +44 -44
- package/src/ruvocal/src/lib/components/Toast.svelte +27 -27
- package/src/ruvocal/src/lib/components/Tooltip.svelte +30 -30
- package/src/ruvocal/src/lib/components/WelcomeModal.svelte +46 -46
- package/src/ruvocal/src/lib/components/chat/Alternatives.svelte +77 -77
- package/src/ruvocal/src/lib/components/chat/BlockWrapper.svelte +72 -72
- package/src/ruvocal/src/lib/components/chat/ChatInput.svelte +490 -490
- package/src/ruvocal/src/lib/components/chat/ChatIntroduction.svelte +123 -123
- package/src/ruvocal/src/lib/components/chat/ChatMessage.svelte +548 -548
- package/src/ruvocal/src/lib/components/chat/ChatWindow.svelte +1057 -1057
- package/src/ruvocal/src/lib/components/chat/FileDropzone.svelte +92 -92
- package/src/ruvocal/src/lib/components/chat/ImageLightbox.svelte +66 -66
- package/src/ruvocal/src/lib/components/chat/MarkdownBlock.svelte +23 -23
- package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte +69 -69
- package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte.test.ts +58 -58
- package/src/ruvocal/src/lib/components/chat/MessageAvatar.svelte +103 -103
- package/src/ruvocal/src/lib/components/chat/ModelSwitch.svelte +64 -64
- package/src/ruvocal/src/lib/components/chat/OpenReasoningResults.svelte +81 -81
- package/src/ruvocal/src/lib/components/chat/TaskGroup.svelte +88 -88
- package/src/ruvocal/src/lib/components/chat/ToolUpdate.svelte +273 -273
- package/src/ruvocal/src/lib/components/chat/UploadedFile.svelte +253 -253
- package/src/ruvocal/src/lib/components/chat/UrlFetchModal.svelte +203 -203
- package/src/ruvocal/src/lib/components/chat/VoiceRecorder.svelte +214 -214
- package/src/ruvocal/src/lib/components/icons/IconBurger.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconCheap.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconChevron.svelte +24 -24
- package/src/ruvocal/src/lib/components/icons/IconDazzled.svelte +40 -40
- package/src/ruvocal/src/lib/components/icons/IconFast.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconLoading.svelte +22 -22
- package/src/ruvocal/src/lib/components/icons/IconMCP.svelte +28 -28
- package/src/ruvocal/src/lib/components/icons/IconMoon.svelte +21 -21
- package/src/ruvocal/src/lib/components/icons/IconNew.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconOmni.svelte +90 -90
- package/src/ruvocal/src/lib/components/icons/IconPaperclip.svelte +24 -24
- package/src/ruvocal/src/lib/components/icons/IconPro.svelte +37 -37
- package/src/ruvocal/src/lib/components/icons/IconShare.svelte +21 -21
- package/src/ruvocal/src/lib/components/icons/IconSun.svelte +93 -93
- package/src/ruvocal/src/lib/components/icons/Logo.svelte +68 -68
- package/src/ruvocal/src/lib/components/icons/LogoHuggingFaceBorderless.svelte +54 -54
- package/src/ruvocal/src/lib/components/mcp/AddServerForm.svelte +250 -250
- package/src/ruvocal/src/lib/components/mcp/MCPServerManager.svelte +185 -185
- package/src/ruvocal/src/lib/components/mcp/ServerCard.svelte +203 -203
- package/src/ruvocal/src/lib/components/players/AudioPlayer.svelte +82 -82
- package/src/ruvocal/src/lib/components/voice/AudioWaveform.svelte +96 -96
- package/src/ruvocal/src/lib/components/wasm/GalleryPanel.svelte +357 -357
- package/src/ruvocal/src/lib/constants/mcpExamples.ts +114 -114
- package/src/ruvocal/src/lib/constants/mime.ts +11 -11
- package/src/ruvocal/src/lib/constants/pagination.ts +1 -1
- package/src/ruvocal/src/lib/constants/publicSepToken.ts +1 -1
- package/src/ruvocal/src/lib/constants/routerExamples.ts +133 -133
- package/src/ruvocal/src/lib/constants/rvagentPresets.ts +206 -206
- package/src/ruvocal/src/lib/createShareLink.ts +27 -27
- package/src/ruvocal/src/lib/jobs/refresh-conversation-stats.ts +297 -297
- package/src/ruvocal/src/lib/migrations/lock.ts +56 -56
- package/src/ruvocal/src/lib/migrations/migrations.spec.ts +74 -74
- package/src/ruvocal/src/lib/migrations/migrations.ts +109 -109
- package/src/ruvocal/src/lib/migrations/routines/01-update-search-assistants.ts +50 -50
- package/src/ruvocal/src/lib/migrations/routines/02-update-assistants-models.ts +48 -48
- package/src/ruvocal/src/lib/migrations/routines/04-update-message-updates.ts +151 -151
- package/src/ruvocal/src/lib/migrations/routines/05-update-message-files.ts +56 -56
- package/src/ruvocal/src/lib/migrations/routines/06-trim-message-updates.ts +56 -56
- package/src/ruvocal/src/lib/migrations/routines/08-update-featured-to-review.ts +32 -32
- package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.spec.ts +214 -214
- package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.ts +88 -88
- package/src/ruvocal/src/lib/migrations/routines/10-update-reports-assistantid.ts +29 -29
- package/src/ruvocal/src/lib/migrations/routines/index.ts +15 -15
- package/src/ruvocal/src/lib/server/__tests__/conversation-stop-generating.spec.ts +103 -103
- package/src/ruvocal/src/lib/server/abortRegistry.ts +57 -57
- package/src/ruvocal/src/lib/server/abortedGenerations.ts +43 -43
- package/src/ruvocal/src/lib/server/adminToken.ts +62 -62
- package/src/ruvocal/src/lib/server/api/__tests__/conversations-id.spec.ts +296 -296
- package/src/ruvocal/src/lib/server/api/__tests__/conversations-message.spec.ts +216 -216
- package/src/ruvocal/src/lib/server/api/__tests__/conversations.spec.ts +235 -235
- package/src/ruvocal/src/lib/server/api/__tests__/misc.spec.ts +72 -72
- package/src/ruvocal/src/lib/server/api/__tests__/testHelpers.ts +86 -86
- package/src/ruvocal/src/lib/server/api/__tests__/user-reports.spec.ts +78 -78
- package/src/ruvocal/src/lib/server/api/__tests__/user.spec.ts +239 -239
- package/src/ruvocal/src/lib/server/api/types.ts +37 -37
- package/src/ruvocal/src/lib/server/api/utils/requireAuth.ts +22 -22
- package/src/ruvocal/src/lib/server/api/utils/resolveConversation.ts +69 -69
- package/src/ruvocal/src/lib/server/api/utils/resolveModel.ts +27 -27
- package/src/ruvocal/src/lib/server/api/utils/superjsonResponse.ts +15 -15
- package/src/ruvocal/src/lib/server/apiToken.ts +11 -11
- package/src/ruvocal/src/lib/server/auth.ts +554 -554
- package/src/ruvocal/src/lib/server/config.ts +187 -187
- package/src/ruvocal/src/lib/server/conversation.ts +83 -83
- package/src/ruvocal/src/lib/server/database/__tests__/rvf.spec.ts +709 -709
- package/src/ruvocal/src/lib/server/database/postgres.ts +700 -700
- package/src/ruvocal/src/lib/server/database/rvf.ts +1078 -1078
- package/src/ruvocal/src/lib/server/database.ts +145 -145
- package/src/ruvocal/src/lib/server/endpoints/document.ts +68 -68
- package/src/ruvocal/src/lib/server/endpoints/endpoints.ts +43 -43
- package/src/ruvocal/src/lib/server/endpoints/images.ts +211 -211
- package/src/ruvocal/src/lib/server/endpoints/openai/endpointOai.ts +266 -266
- package/src/ruvocal/src/lib/server/endpoints/openai/openAIChatToTextGenerationStream.ts +212 -212
- package/src/ruvocal/src/lib/server/endpoints/openai/openAICompletionToTextGenerationStream.ts +32 -32
- package/src/ruvocal/src/lib/server/endpoints/preprocessMessages.ts +61 -61
- package/src/ruvocal/src/lib/server/exitHandler.ts +59 -59
- package/src/ruvocal/src/lib/server/files/downloadFile.ts +34 -34
- package/src/ruvocal/src/lib/server/files/uploadFile.ts +29 -29
- package/src/ruvocal/src/lib/server/findRepoRoot.ts +13 -13
- package/src/ruvocal/src/lib/server/generateFromDefaultEndpoint.ts +46 -46
- package/src/ruvocal/src/lib/server/hooks/error.ts +37 -37
- package/src/ruvocal/src/lib/server/hooks/fetch.ts +22 -22
- package/src/ruvocal/src/lib/server/hooks/handle.ts +250 -250
- package/src/ruvocal/src/lib/server/hooks/init.ts +51 -51
- package/src/ruvocal/src/lib/server/isURLLocal.spec.ts +31 -31
- package/src/ruvocal/src/lib/server/isURLLocal.ts +74 -74
- package/src/ruvocal/src/lib/server/logger.ts +42 -42
- package/src/ruvocal/src/lib/server/mcp/clientPool.spec.ts +175 -175
- package/src/ruvocal/src/lib/server/mcp/hf.ts +32 -32
- package/src/ruvocal/src/lib/server/mcp/httpClient.ts +122 -122
- package/src/ruvocal/src/lib/server/mcp/registry.ts +76 -76
- package/src/ruvocal/src/lib/server/mcp/tools.ts +196 -196
- package/src/ruvocal/src/lib/server/metrics.ts +255 -255
- package/src/ruvocal/src/lib/server/models.ts +518 -518
- package/src/ruvocal/src/lib/server/requestContext.ts +55 -55
- package/src/ruvocal/src/lib/server/router/arch.ts +230 -230
- package/src/ruvocal/src/lib/server/router/endpoint.ts +316 -316
- package/src/ruvocal/src/lib/server/router/multimodal.ts +28 -28
- package/src/ruvocal/src/lib/server/router/policy.ts +49 -49
- package/src/ruvocal/src/lib/server/router/toolsRoute.ts +51 -51
- package/src/ruvocal/src/lib/server/router/types.ts +21 -21
- package/src/ruvocal/src/lib/server/sendSlack.ts +23 -23
- package/src/ruvocal/src/lib/server/textGeneration/generate.ts +258 -258
- package/src/ruvocal/src/lib/server/textGeneration/index.ts +96 -96
- package/src/ruvocal/src/lib/server/textGeneration/mcp/fileRefs.ts +155 -155
- package/src/ruvocal/src/lib/server/textGeneration/mcp/routerResolution.ts +108 -108
- package/src/ruvocal/src/lib/server/textGeneration/mcp/runMcpFlow.ts +831 -831
- package/src/ruvocal/src/lib/server/textGeneration/mcp/toolInvocation.ts +349 -349
- package/src/ruvocal/src/lib/server/textGeneration/mcp/wasmTools.test.ts +633 -633
- package/src/ruvocal/src/lib/server/textGeneration/reasoning.ts +23 -23
- package/src/ruvocal/src/lib/server/textGeneration/title.ts +83 -83
- package/src/ruvocal/src/lib/server/textGeneration/types.ts +28 -28
- package/src/ruvocal/src/lib/server/textGeneration/utils/prepareFiles.ts +88 -88
- package/src/ruvocal/src/lib/server/textGeneration/utils/routing.ts +21 -21
- package/src/ruvocal/src/lib/server/textGeneration/utils/toolPrompt.ts +49 -49
- package/src/ruvocal/src/lib/server/urlSafety.ts +77 -77
- package/src/ruvocal/src/lib/server/usageLimits.ts +30 -30
- package/src/ruvocal/src/lib/stores/autopilotStore.svelte.ts +175 -175
- package/src/ruvocal/src/lib/stores/backgroundGenerations.svelte.ts +32 -32
- package/src/ruvocal/src/lib/stores/backgroundGenerations.ts +1 -1
- package/src/ruvocal/src/lib/stores/errors.ts +9 -9
- package/src/ruvocal/src/lib/stores/isAborted.ts +3 -3
- package/src/ruvocal/src/lib/stores/isPro.ts +4 -4
- package/src/ruvocal/src/lib/stores/loading.ts +3 -3
- package/src/ruvocal/src/lib/stores/mcpServers.ts +534 -534
- package/src/ruvocal/src/lib/stores/pendingChatInput.ts +3 -3
- package/src/ruvocal/src/lib/stores/pendingMessage.ts +9 -9
- package/src/ruvocal/src/lib/stores/settings.ts +182 -182
- package/src/ruvocal/src/lib/stores/shareModal.ts +13 -13
- package/src/ruvocal/src/lib/stores/titleUpdate.ts +8 -8
- package/src/ruvocal/src/lib/stores/wasmMcp.ts +472 -472
- package/src/ruvocal/src/lib/switchTheme.ts +124 -124
- package/src/ruvocal/src/lib/types/AbortedGeneration.ts +8 -8
- package/src/ruvocal/src/lib/types/Assistant.ts +31 -31
- package/src/ruvocal/src/lib/types/AssistantStats.ts +11 -11
- package/src/ruvocal/src/lib/types/ConfigKey.ts +4 -4
- package/src/ruvocal/src/lib/types/ConvSidebar.ts +9 -9
- package/src/ruvocal/src/lib/types/Conversation.ts +27 -27
- package/src/ruvocal/src/lib/types/ConversationStats.ts +13 -13
- package/src/ruvocal/src/lib/types/Message.ts +41 -41
- package/src/ruvocal/src/lib/types/MessageEvent.ts +10 -10
- package/src/ruvocal/src/lib/types/MessageUpdate.ts +139 -139
- package/src/ruvocal/src/lib/types/MigrationResult.ts +7 -7
- package/src/ruvocal/src/lib/types/Model.ts +23 -23
- package/src/ruvocal/src/lib/types/Report.ts +12 -12
- package/src/ruvocal/src/lib/types/Review.ts +6 -6
- package/src/ruvocal/src/lib/types/Semaphore.ts +19 -19
- package/src/ruvocal/src/lib/types/Session.ts +22 -22
- package/src/ruvocal/src/lib/types/Settings.ts +93 -93
- package/src/ruvocal/src/lib/types/SharedConversation.ts +9 -9
- package/src/ruvocal/src/lib/types/Template.ts +6 -6
- package/src/ruvocal/src/lib/types/Timestamps.ts +4 -4
- package/src/ruvocal/src/lib/types/TokenCache.ts +6 -6
- package/src/ruvocal/src/lib/types/Tool.ts +77 -77
- package/src/ruvocal/src/lib/types/UrlDependency.ts +5 -5
- package/src/ruvocal/src/lib/types/User.ts +14 -14
- package/src/ruvocal/src/lib/utils/PublicConfig.svelte.ts +75 -75
- package/src/ruvocal/src/lib/utils/auth.ts +17 -17
- package/src/ruvocal/src/lib/utils/chunk.ts +33 -33
- package/src/ruvocal/src/lib/utils/cookiesAreEnabled.ts +13 -13
- package/src/ruvocal/src/lib/utils/debounce.ts +17 -17
- package/src/ruvocal/src/lib/utils/deepestChild.ts +6 -6
- package/src/ruvocal/src/lib/utils/favicon.ts +21 -21
- package/src/ruvocal/src/lib/utils/fetchJSON.ts +23 -23
- package/src/ruvocal/src/lib/utils/file2base64.ts +14 -14
- package/src/ruvocal/src/lib/utils/formatUserCount.ts +37 -37
- package/src/ruvocal/src/lib/utils/generationState.spec.ts +75 -75
- package/src/ruvocal/src/lib/utils/generationState.ts +26 -26
- package/src/ruvocal/src/lib/utils/getHref.ts +41 -41
- package/src/ruvocal/src/lib/utils/getReturnFromGenerator.ts +7 -7
- package/src/ruvocal/src/lib/utils/haptics.ts +64 -64
- package/src/ruvocal/src/lib/utils/hashConv.ts +12 -12
- package/src/ruvocal/src/lib/utils/hf.ts +17 -17
- package/src/ruvocal/src/lib/utils/isDesktop.ts +7 -7
- package/src/ruvocal/src/lib/utils/isUrl.ts +8 -8
- package/src/ruvocal/src/lib/utils/isVirtualKeyboard.ts +16 -16
- package/src/ruvocal/src/lib/utils/loadAttachmentsFromUrls.ts +115 -115
- package/src/ruvocal/src/lib/utils/marked.spec.ts +96 -96
- package/src/ruvocal/src/lib/utils/marked.ts +531 -531
- package/src/ruvocal/src/lib/utils/mcpValidation.ts +147 -147
- package/src/ruvocal/src/lib/utils/mergeAsyncGenerators.ts +38 -38
- package/src/ruvocal/src/lib/utils/messageUpdates.spec.ts +286 -286
- package/src/ruvocal/src/lib/utils/messageUpdates.ts +332 -332
- package/src/ruvocal/src/lib/utils/mime.ts +56 -56
- package/src/ruvocal/src/lib/utils/models.ts +14 -14
- package/src/ruvocal/src/lib/utils/parseBlocks.ts +120 -120
- package/src/ruvocal/src/lib/utils/parseIncompleteMarkdown.ts +644 -644
- package/src/ruvocal/src/lib/utils/parseStringToList.ts +10 -10
- package/src/ruvocal/src/lib/utils/randomUuid.ts +14 -14
- package/src/ruvocal/src/lib/utils/searchTokens.ts +33 -33
- package/src/ruvocal/src/lib/utils/sha256.ts +7 -7
- package/src/ruvocal/src/lib/utils/stringifyError.ts +12 -12
- package/src/ruvocal/src/lib/utils/sum.ts +3 -3
- package/src/ruvocal/src/lib/utils/template.spec.ts +59 -59
- package/src/ruvocal/src/lib/utils/template.ts +53 -53
- package/src/ruvocal/src/lib/utils/timeout.ts +9 -9
- package/src/ruvocal/src/lib/utils/toolProgress.spec.ts +46 -46
- package/src/ruvocal/src/lib/utils/toolProgress.ts +11 -11
- package/src/ruvocal/src/lib/utils/tree/addChildren.spec.ts +102 -102
- package/src/ruvocal/src/lib/utils/tree/addChildren.ts +48 -48
- package/src/ruvocal/src/lib/utils/tree/addSibling.spec.ts +81 -81
- package/src/ruvocal/src/lib/utils/tree/addSibling.ts +41 -41
- package/src/ruvocal/src/lib/utils/tree/buildSubtree.spec.ts +110 -110
- package/src/ruvocal/src/lib/utils/tree/buildSubtree.ts +24 -24
- package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.spec.ts +31 -31
- package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.ts +36 -36
- package/src/ruvocal/src/lib/utils/tree/isMessageId.spec.ts +15 -15
- package/src/ruvocal/src/lib/utils/tree/isMessageId.ts +5 -5
- package/src/ruvocal/src/lib/utils/tree/tree.d.ts +14 -14
- package/src/ruvocal/src/lib/utils/tree/treeHelpers.spec.ts +167 -167
- package/src/ruvocal/src/lib/utils/updates.ts +39 -39
- package/src/ruvocal/src/lib/utils/urlParams.ts +13 -13
- package/src/ruvocal/src/lib/wasm/idb.ts +438 -438
- package/src/ruvocal/src/lib/wasm/index.ts +1213 -1213
- package/src/ruvocal/src/lib/wasm/tests/wasm-capabilities.test.ts +565 -565
- package/src/ruvocal/src/lib/wasm/wasm.worker.ts +332 -332
- package/src/ruvocal/src/lib/wasm/workerClient.ts +166 -166
- package/src/ruvocal/src/lib/workers/autopilotWorker.ts +221 -221
- package/src/ruvocal/src/lib/workers/detailFetchWorker.ts +100 -100
- package/src/ruvocal/src/lib/workers/markdownWorker.ts +61 -61
- package/src/ruvocal/src/routes/+error.svelte +20 -20
- package/src/ruvocal/src/routes/+layout.svelte +324 -324
- package/src/ruvocal/src/routes/+layout.ts +91 -91
- package/src/ruvocal/src/routes/+page.svelte +168 -168
- package/src/ruvocal/src/routes/.well-known/oauth-cimd/+server.ts +37 -37
- package/src/ruvocal/src/routes/__debug/openai/+server.ts +21 -21
- package/src/ruvocal/src/routes/admin/export/+server.ts +159 -159
- package/src/ruvocal/src/routes/admin/stats/compute/+server.ts +16 -16
- package/src/ruvocal/src/routes/api/conversation/[id]/+server.ts +40 -40
- package/src/ruvocal/src/routes/api/conversation/[id]/message/[messageId]/+server.ts +42 -42
- package/src/ruvocal/src/routes/api/conversations/+server.ts +48 -48
- package/src/ruvocal/src/routes/api/fetch-url/+server.ts +147 -147
- package/src/ruvocal/src/routes/api/mcp/health/+server.ts +292 -292
- package/src/ruvocal/src/routes/api/mcp/servers/+server.ts +32 -32
- package/src/ruvocal/src/routes/api/models/+server.ts +25 -25
- package/src/ruvocal/src/routes/api/transcribe/+server.ts +104 -104
- package/src/ruvocal/src/routes/api/user/+server.ts +15 -15
- package/src/ruvocal/src/routes/api/user/validate-token/+server.ts +20 -20
- package/src/ruvocal/src/routes/api/v2/conversations/+server.ts +48 -48
- package/src/ruvocal/src/routes/api/v2/conversations/[id]/+server.ts +94 -94
- package/src/ruvocal/src/routes/api/v2/conversations/[id]/message/[messageId]/+server.ts +43 -43
- package/src/ruvocal/src/routes/api/v2/conversations/import-share/+server.ts +23 -23
- package/src/ruvocal/src/routes/api/v2/debug/config/+server.ts +16 -16
- package/src/ruvocal/src/routes/api/v2/debug/refresh/+server.ts +30 -30
- package/src/ruvocal/src/routes/api/v2/export/+server.ts +196 -196
- package/src/ruvocal/src/routes/api/v2/feature-flags/+server.ts +14 -14
- package/src/ruvocal/src/routes/api/v2/models/+server.ts +38 -38
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/+server.ts +8 -8
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/+server.ts +8 -8
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/subscribe/+server.ts +28 -28
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/subscribe/+server.ts +28 -28
- package/src/ruvocal/src/routes/api/v2/models/old/+server.ts +7 -7
- package/src/ruvocal/src/routes/api/v2/models/refresh/+server.ts +33 -33
- package/src/ruvocal/src/routes/api/v2/public-config/+server.ts +7 -7
- package/src/ruvocal/src/routes/api/v2/user/+server.ts +17 -17
- package/src/ruvocal/src/routes/api/v2/user/billing-orgs/+server.ts +73 -73
- package/src/ruvocal/src/routes/api/v2/user/reports/+server.ts +17 -17
- package/src/ruvocal/src/routes/api/v2/user/settings/+server.ts +110 -110
- package/src/ruvocal/src/routes/conversation/+server.ts +115 -115
- package/src/ruvocal/src/routes/conversation/[id]/+page.svelte +593 -593
- package/src/ruvocal/src/routes/conversation/[id]/+page.ts +60 -60
- package/src/ruvocal/src/routes/conversation/[id]/+server.ts +740 -740
- package/src/ruvocal/src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +66 -66
- package/src/ruvocal/src/routes/conversation/[id]/share/+server.ts +69 -69
- package/src/ruvocal/src/routes/conversation/[id]/stop-generating/+server.ts +35 -35
- package/src/ruvocal/src/routes/healthcheck/+server.ts +3 -3
- package/src/ruvocal/src/routes/login/+server.ts +5 -5
- package/src/ruvocal/src/routes/login/callback/+server.ts +103 -103
- package/src/ruvocal/src/routes/login/callback/updateUser.spec.ts +157 -157
- package/src/ruvocal/src/routes/login/callback/updateUser.ts +215 -215
- package/src/ruvocal/src/routes/logout/+server.ts +18 -18
- package/src/ruvocal/src/routes/metrics/+server.ts +18 -18
- package/src/ruvocal/src/routes/models/+page.svelte +233 -233
- package/src/ruvocal/src/routes/models/[...model]/+page.svelte +161 -161
- package/src/ruvocal/src/routes/models/[...model]/+page.ts +14 -14
- package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/+server.ts +64 -64
- package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/ModelThumbnail.svelte +28 -28
- package/src/ruvocal/src/routes/privacy/+page.svelte +11 -11
- package/src/ruvocal/src/routes/r/[id]/+page.ts +34 -34
- package/src/ruvocal/src/routes/settings/(nav)/+layout.svelte +282 -282
- package/src/ruvocal/src/routes/settings/(nav)/+layout.ts +1 -1
- package/src/ruvocal/src/routes/settings/(nav)/+server.ts +59 -59
- package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.svelte +464 -464
- package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.ts +14 -14
- package/src/ruvocal/src/routes/settings/(nav)/application/+page.svelte +362 -362
- package/src/ruvocal/src/routes/settings/+layout.svelte +40 -40
- package/src/ruvocal/src/styles/highlight-js.css +195 -195
- package/src/ruvocal/src/styles/main.css +144 -144
- package/src/ruvocal/static/chatui/favicon-dark.svg +3 -3
- package/src/ruvocal/static/chatui/favicon-dev.svg +3 -3
- package/src/ruvocal/static/chatui/favicon.svg +3 -3
- package/src/ruvocal/static/chatui/icon.svg +3 -3
- package/src/ruvocal/static/chatui/logo.svg +7 -7
- package/src/ruvocal/static/chatui/manifest.json +54 -54
- package/src/ruvocal/static/chatui/welcome.js +184 -184
- package/src/ruvocal/static/huggingchat/favicon-dark.svg +4 -4
- package/src/ruvocal/static/huggingchat/favicon-dev.svg +4 -4
- package/src/ruvocal/static/huggingchat/favicon.svg +4 -4
- package/src/ruvocal/static/huggingchat/fulltext-logo.svg +1 -1
- package/src/ruvocal/static/huggingchat/icon.svg +4 -4
- package/src/ruvocal/static/huggingchat/logo.svg +4 -4
- package/src/ruvocal/static/huggingchat/manifest.json +54 -54
- package/src/ruvocal/static/huggingchat/routes.chat.json +226 -226
- package/src/ruvocal/static/robots.txt +10 -10
- package/src/ruvocal/static/wasm/rvagent_wasm.js +1539 -1539
- package/src/ruvocal/stub/@reflink/reflink/package.json +5 -5
- package/src/ruvocal/svelte.config.js +53 -53
- package/src/ruvocal/tailwind.config.cjs +30 -30
- package/src/ruvocal/tsconfig.json +19 -19
- package/src/ruvocal/vite.config.ts +87 -87
- package/src/scripts/deploy.sh +116 -116
- package/src/scripts/generate-config.js +245 -245
- package/src/scripts/generate-welcome.js +187 -187
- package/src/scripts/package-rvf.sh +116 -116
|
@@ -1,300 +1,300 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
let isOpen = $state(false);
|
|
3
|
-
|
|
4
|
-
export function closeMobileNav() {
|
|
5
|
-
isOpen = false;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function openMobileNav() {
|
|
9
|
-
isOpen = true;
|
|
10
|
-
}
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<script lang="ts">
|
|
14
|
-
import { browser } from "$app/environment";
|
|
15
|
-
import { beforeNavigate } from "$app/navigation";
|
|
16
|
-
import { onMount, onDestroy } from "svelte";
|
|
17
|
-
import { base } from "$app/paths";
|
|
18
|
-
import { page } from "$app/state";
|
|
19
|
-
import IconNew from "$lib/components/icons/IconNew.svelte";
|
|
20
|
-
import IconShare from "$lib/components/icons/IconShare.svelte";
|
|
21
|
-
import IconBurger from "$lib/components/icons/IconBurger.svelte";
|
|
22
|
-
import { Spring } from "svelte/motion";
|
|
23
|
-
import { shareModal } from "$lib/stores/shareModal";
|
|
24
|
-
import { loading } from "$lib/stores/loading";
|
|
25
|
-
import { requireAuthUser } from "$lib/utils/auth";
|
|
26
|
-
import { tap } from "$lib/utils/haptics";
|
|
27
|
-
|
|
28
|
-
interface Props {
|
|
29
|
-
title: string | undefined;
|
|
30
|
-
children?: import("svelte").Snippet;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
let { title = $bindable(), children }: Props = $props();
|
|
34
|
-
|
|
35
|
-
let closeEl: HTMLButtonElement | undefined = $state();
|
|
36
|
-
let openEl: HTMLButtonElement | undefined = $state();
|
|
37
|
-
|
|
38
|
-
const isHuggingChat = $derived(Boolean(page.data?.publicConfig?.isHuggingChat));
|
|
39
|
-
const canShare = $derived(
|
|
40
|
-
isHuggingChat &&
|
|
41
|
-
!$loading &&
|
|
42
|
-
Boolean(page.params?.id) &&
|
|
43
|
-
page.route.id?.startsWith("/conversation/")
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
// Define the width for the drawer (less than 100% to create the gap)
|
|
47
|
-
const drawerWidthPercentage = 85;
|
|
48
|
-
|
|
49
|
-
$effect(() => {
|
|
50
|
-
title ??= "New Chat";
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
beforeNavigate(() => {
|
|
54
|
-
isOpen = false;
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
let shouldFocusClose = $derived(isOpen && closeEl);
|
|
58
|
-
let shouldRefocusOpen = $derived(!isOpen && browser && document.activeElement === closeEl);
|
|
59
|
-
|
|
60
|
-
$effect(() => {
|
|
61
|
-
if (shouldFocusClose) {
|
|
62
|
-
closeEl?.focus();
|
|
63
|
-
} else if (shouldRefocusOpen) {
|
|
64
|
-
openEl?.focus();
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Function to close the drawer when background is tapped
|
|
69
|
-
function closeDrawer() {
|
|
70
|
-
isOpen = false;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Swipe gesture support for opening/closing the nav with live feedback
|
|
74
|
-
// Thresholds from vaul drawer library
|
|
75
|
-
const VELOCITY_THRESHOLD = 0.4; // px/ms - if exceeded, snap in swipe direction
|
|
76
|
-
const DIRECTION_LOCK_THRESHOLD = 10; // px - movement needed to lock direction
|
|
77
|
-
|
|
78
|
-
let touchstart: Touch | null = null;
|
|
79
|
-
let lastTouchX: number | null = null;
|
|
80
|
-
let dragStartTime: number = 0;
|
|
81
|
-
let isDragging = $state(false);
|
|
82
|
-
let dragOffset = $state(-100); // percentage: -100 (closed) to 0 (open)
|
|
83
|
-
let dragStartedOpen = false;
|
|
84
|
-
|
|
85
|
-
// Direction lock: null = undecided, 'horizontal' = drawer drag, 'vertical' = scroll
|
|
86
|
-
let directionLock: "horizontal" | "vertical" | null = null;
|
|
87
|
-
let potentialDrag = false;
|
|
88
|
-
|
|
89
|
-
// Spring target: follows dragOffset during drag, follows isOpen after drag ends
|
|
90
|
-
const springTarget = $derived(isDragging ? dragOffset : isOpen ? 0 : -100);
|
|
91
|
-
const tween = Spring.of(() => springTarget, { stiffness: 0.2, damping: 0.8 });
|
|
92
|
-
|
|
93
|
-
function onTouchStart(e: TouchEvent) {
|
|
94
|
-
// Ignore touch events when a modal is open (app is inert)
|
|
95
|
-
if (document.getElementById("app")?.hasAttribute("inert")) return;
|
|
96
|
-
|
|
97
|
-
const touch = e.changedTouches[0];
|
|
98
|
-
touchstart = touch;
|
|
99
|
-
dragStartTime = Date.now();
|
|
100
|
-
directionLock = null;
|
|
101
|
-
|
|
102
|
-
const drawerWidth = window.innerWidth * (drawerWidthPercentage / 100);
|
|
103
|
-
const touchOnDrawer = isOpen && touch.clientX < drawerWidth;
|
|
104
|
-
|
|
105
|
-
// Check if touch is on an interactive element (don't block taps on buttons/links)
|
|
106
|
-
const target = e.target as HTMLElement;
|
|
107
|
-
const isInteractive = target.closest("button, a, input, [role='button']");
|
|
108
|
-
|
|
109
|
-
// Potential drag scenarios - never start isDragging until direction is locked
|
|
110
|
-
// Exception: overlay tap (no scroll content, so no direction conflict)
|
|
111
|
-
if (!isOpen && touch.clientX < 40) {
|
|
112
|
-
// Opening gesture - wait for direction lock before starting drag
|
|
113
|
-
// Prevent Safari's back navigation gesture on iOS (but not on interactive elements)
|
|
114
|
-
if (!isInteractive) {
|
|
115
|
-
e.preventDefault();
|
|
116
|
-
}
|
|
117
|
-
potentialDrag = true;
|
|
118
|
-
dragStartedOpen = false;
|
|
119
|
-
} else if (isOpen && !touchOnDrawer) {
|
|
120
|
-
// Touch on overlay - can start immediately (no scroll conflict)
|
|
121
|
-
potentialDrag = true;
|
|
122
|
-
isDragging = true;
|
|
123
|
-
dragStartedOpen = true;
|
|
124
|
-
dragOffset = 0;
|
|
125
|
-
directionLock = "horizontal";
|
|
126
|
-
} else if (isOpen && touchOnDrawer) {
|
|
127
|
-
// Touch on drawer content - wait for direction lock
|
|
128
|
-
potentialDrag = true;
|
|
129
|
-
dragStartedOpen = true;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function onTouchMove(e: TouchEvent) {
|
|
134
|
-
if (!touchstart || !potentialDrag) return;
|
|
135
|
-
|
|
136
|
-
const touch = e.changedTouches[0];
|
|
137
|
-
const deltaX = touch.clientX - touchstart.clientX;
|
|
138
|
-
const deltaY = touch.clientY - touchstart.clientY;
|
|
139
|
-
|
|
140
|
-
// Determine direction lock if not yet decided
|
|
141
|
-
if (directionLock === null) {
|
|
142
|
-
const absX = Math.abs(deltaX);
|
|
143
|
-
const absY = Math.abs(deltaY);
|
|
144
|
-
|
|
145
|
-
if (absX > DIRECTION_LOCK_THRESHOLD || absY > DIRECTION_LOCK_THRESHOLD) {
|
|
146
|
-
if (absX > absY) {
|
|
147
|
-
// Horizontal movement - commit to drawer drag
|
|
148
|
-
directionLock = "horizontal";
|
|
149
|
-
isDragging = true;
|
|
150
|
-
dragOffset = dragStartedOpen ? 0 : -100;
|
|
151
|
-
} else {
|
|
152
|
-
// Vertical movement - abort potential drag, let content scroll
|
|
153
|
-
directionLock = "vertical";
|
|
154
|
-
potentialDrag = false;
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (directionLock !== "horizontal") return;
|
|
163
|
-
|
|
164
|
-
const drawerWidth = window.innerWidth * (drawerWidthPercentage / 100);
|
|
165
|
-
|
|
166
|
-
if (dragStartedOpen) {
|
|
167
|
-
dragOffset = Math.max(-100, Math.min(0, (deltaX / drawerWidth) * 100));
|
|
168
|
-
} else {
|
|
169
|
-
dragOffset = Math.max(-100, Math.min(0, -100 + (deltaX / drawerWidth) * 100));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
lastTouchX = touch.clientX;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function onTouchEnd(e: TouchEvent) {
|
|
176
|
-
if (!potentialDrag) return;
|
|
177
|
-
|
|
178
|
-
if (!isDragging || !touchstart) {
|
|
179
|
-
resetDragState();
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const touch = e.changedTouches[0];
|
|
184
|
-
const timeTaken = Date.now() - dragStartTime;
|
|
185
|
-
const distMoved = touch.clientX - touchstart.clientX;
|
|
186
|
-
const velocity = Math.abs(distMoved) / timeTaken;
|
|
187
|
-
|
|
188
|
-
// Determine snap direction based on velocity first, then final movement direction
|
|
189
|
-
if (velocity > VELOCITY_THRESHOLD) {
|
|
190
|
-
isOpen = distMoved > 0;
|
|
191
|
-
} else {
|
|
192
|
-
// For slow drags, use the final movement direction (allows "change of mind")
|
|
193
|
-
const finalDirection = lastTouchX !== null ? touch.clientX - lastTouchX : distMoved;
|
|
194
|
-
isOpen = finalDirection > 0;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
tap();
|
|
198
|
-
resetDragState();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function onTouchCancel() {
|
|
202
|
-
if (isDragging) {
|
|
203
|
-
isOpen = dragStartedOpen;
|
|
204
|
-
}
|
|
205
|
-
resetDragState();
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function resetDragState() {
|
|
209
|
-
isDragging = false;
|
|
210
|
-
potentialDrag = false;
|
|
211
|
-
touchstart = null;
|
|
212
|
-
lastTouchX = null;
|
|
213
|
-
directionLock = null;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
onMount(() => {
|
|
217
|
-
// touchstart needs passive: false to allow preventDefault() for Safari back gesture
|
|
218
|
-
window.addEventListener("touchstart", onTouchStart, { passive: false });
|
|
219
|
-
window.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
220
|
-
window.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
221
|
-
window.addEventListener("touchcancel", onTouchCancel, { passive: true });
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
onDestroy(() => {
|
|
225
|
-
if (browser) {
|
|
226
|
-
window.removeEventListener("touchstart", onTouchStart);
|
|
227
|
-
window.removeEventListener("touchmove", onTouchMove);
|
|
228
|
-
window.removeEventListener("touchend", onTouchEnd);
|
|
229
|
-
window.removeEventListener("touchcancel", onTouchCancel);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
</script>
|
|
233
|
-
|
|
234
|
-
<nav
|
|
235
|
-
class="mx-4 mt-4 flex h-12 items-center justify-between rounded-b-xl border-b bg-gray-50 px-3 dark:border-gray-800 dark:bg-gray-800/30 dark:shadow-xl max-md:rounded-xl max-md:border md:hidden"
|
|
236
|
-
>
|
|
237
|
-
<button
|
|
238
|
-
type="button"
|
|
239
|
-
class="-ml-3 flex size-12 shrink-0 items-center justify-center text-lg"
|
|
240
|
-
onclick={() => (isOpen = true)}
|
|
241
|
-
aria-label="Open menu"
|
|
242
|
-
bind:this={openEl}><IconBurger /></button
|
|
243
|
-
>
|
|
244
|
-
<div class="flex h-full items-center justify-center overflow-hidden">
|
|
245
|
-
{#if page.params?.id}
|
|
246
|
-
<span class="max-w-full truncate px-4 first-letter:uppercase" data-testid="chat-title"
|
|
247
|
-
>{title}</span
|
|
248
|
-
>
|
|
249
|
-
{/if}
|
|
250
|
-
</div>
|
|
251
|
-
<div class="-mr-3 flex items-center">
|
|
252
|
-
{#if isHuggingChat}
|
|
253
|
-
<button
|
|
254
|
-
type="button"
|
|
255
|
-
class="flex h-12 w-6 shrink-0 items-center justify-center text-lg"
|
|
256
|
-
disabled={!canShare}
|
|
257
|
-
onclick={() => {
|
|
258
|
-
if (!canShare) return;
|
|
259
|
-
shareModal.open();
|
|
260
|
-
}}
|
|
261
|
-
aria-label="Share conversation"
|
|
262
|
-
>
|
|
263
|
-
<IconShare classNames={!canShare ? "opacity-40" : ""} />
|
|
264
|
-
</button>
|
|
265
|
-
{/if}
|
|
266
|
-
<a
|
|
267
|
-
href="{base}/"
|
|
268
|
-
class="flex size-12 shrink-0 items-center justify-center text-lg"
|
|
269
|
-
onclick={(e) => {
|
|
270
|
-
if (requireAuthUser()) {
|
|
271
|
-
e.preventDefault();
|
|
272
|
-
}
|
|
273
|
-
}}
|
|
274
|
-
>
|
|
275
|
-
<IconNew />
|
|
276
|
-
</a>
|
|
277
|
-
</div>
|
|
278
|
-
</nav>
|
|
279
|
-
|
|
280
|
-
<!-- Mobile drawer overlay - shows when drawer is open or dragging -->
|
|
281
|
-
{#if isOpen || isDragging}
|
|
282
|
-
<button
|
|
283
|
-
type="button"
|
|
284
|
-
class="fixed inset-0 z-20 cursor-default bg-black/30 md:hidden"
|
|
285
|
-
style="opacity: {Math.max(0, Math.min(1, (100 + tween.current) / 100))}; will-change: opacity;"
|
|
286
|
-
onclick={closeDrawer}
|
|
287
|
-
aria-label="Close mobile navigation"
|
|
288
|
-
></button>
|
|
289
|
-
{/if}
|
|
290
|
-
|
|
291
|
-
<nav
|
|
292
|
-
style="transform: translateX({isDragging
|
|
293
|
-
? dragOffset
|
|
294
|
-
: tween.current}%); width: {drawerWidthPercentage}%; will-change: transform;"
|
|
295
|
-
class:shadow-[5px_0_15px_0_rgba(0,0,0,0.3)]={isOpen || isDragging}
|
|
296
|
-
class="fixed bottom-0 left-0 top-0 z-30 grid max-h-dvh grid-cols-1
|
|
297
|
-
grid-rows-[auto,1fr,auto,auto] rounded-r-xl bg-white pt-4 dark:bg-gray-900 md:hidden"
|
|
298
|
-
>
|
|
299
|
-
{@render children?.()}
|
|
300
|
-
</nav>
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
let isOpen = $state(false);
|
|
3
|
+
|
|
4
|
+
export function closeMobileNav() {
|
|
5
|
+
isOpen = false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function openMobileNav() {
|
|
9
|
+
isOpen = true;
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import { browser } from "$app/environment";
|
|
15
|
+
import { beforeNavigate } from "$app/navigation";
|
|
16
|
+
import { onMount, onDestroy } from "svelte";
|
|
17
|
+
import { base } from "$app/paths";
|
|
18
|
+
import { page } from "$app/state";
|
|
19
|
+
import IconNew from "$lib/components/icons/IconNew.svelte";
|
|
20
|
+
import IconShare from "$lib/components/icons/IconShare.svelte";
|
|
21
|
+
import IconBurger from "$lib/components/icons/IconBurger.svelte";
|
|
22
|
+
import { Spring } from "svelte/motion";
|
|
23
|
+
import { shareModal } from "$lib/stores/shareModal";
|
|
24
|
+
import { loading } from "$lib/stores/loading";
|
|
25
|
+
import { requireAuthUser } from "$lib/utils/auth";
|
|
26
|
+
import { tap } from "$lib/utils/haptics";
|
|
27
|
+
|
|
28
|
+
interface Props {
|
|
29
|
+
title: string | undefined;
|
|
30
|
+
children?: import("svelte").Snippet;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let { title = $bindable(), children }: Props = $props();
|
|
34
|
+
|
|
35
|
+
let closeEl: HTMLButtonElement | undefined = $state();
|
|
36
|
+
let openEl: HTMLButtonElement | undefined = $state();
|
|
37
|
+
|
|
38
|
+
const isHuggingChat = $derived(Boolean(page.data?.publicConfig?.isHuggingChat));
|
|
39
|
+
const canShare = $derived(
|
|
40
|
+
isHuggingChat &&
|
|
41
|
+
!$loading &&
|
|
42
|
+
Boolean(page.params?.id) &&
|
|
43
|
+
page.route.id?.startsWith("/conversation/")
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Define the width for the drawer (less than 100% to create the gap)
|
|
47
|
+
const drawerWidthPercentage = 85;
|
|
48
|
+
|
|
49
|
+
$effect(() => {
|
|
50
|
+
title ??= "New Chat";
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
beforeNavigate(() => {
|
|
54
|
+
isOpen = false;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let shouldFocusClose = $derived(isOpen && closeEl);
|
|
58
|
+
let shouldRefocusOpen = $derived(!isOpen && browser && document.activeElement === closeEl);
|
|
59
|
+
|
|
60
|
+
$effect(() => {
|
|
61
|
+
if (shouldFocusClose) {
|
|
62
|
+
closeEl?.focus();
|
|
63
|
+
} else if (shouldRefocusOpen) {
|
|
64
|
+
openEl?.focus();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Function to close the drawer when background is tapped
|
|
69
|
+
function closeDrawer() {
|
|
70
|
+
isOpen = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Swipe gesture support for opening/closing the nav with live feedback
|
|
74
|
+
// Thresholds from vaul drawer library
|
|
75
|
+
const VELOCITY_THRESHOLD = 0.4; // px/ms - if exceeded, snap in swipe direction
|
|
76
|
+
const DIRECTION_LOCK_THRESHOLD = 10; // px - movement needed to lock direction
|
|
77
|
+
|
|
78
|
+
let touchstart: Touch | null = null;
|
|
79
|
+
let lastTouchX: number | null = null;
|
|
80
|
+
let dragStartTime: number = 0;
|
|
81
|
+
let isDragging = $state(false);
|
|
82
|
+
let dragOffset = $state(-100); // percentage: -100 (closed) to 0 (open)
|
|
83
|
+
let dragStartedOpen = false;
|
|
84
|
+
|
|
85
|
+
// Direction lock: null = undecided, 'horizontal' = drawer drag, 'vertical' = scroll
|
|
86
|
+
let directionLock: "horizontal" | "vertical" | null = null;
|
|
87
|
+
let potentialDrag = false;
|
|
88
|
+
|
|
89
|
+
// Spring target: follows dragOffset during drag, follows isOpen after drag ends
|
|
90
|
+
const springTarget = $derived(isDragging ? dragOffset : isOpen ? 0 : -100);
|
|
91
|
+
const tween = Spring.of(() => springTarget, { stiffness: 0.2, damping: 0.8 });
|
|
92
|
+
|
|
93
|
+
function onTouchStart(e: TouchEvent) {
|
|
94
|
+
// Ignore touch events when a modal is open (app is inert)
|
|
95
|
+
if (document.getElementById("app")?.hasAttribute("inert")) return;
|
|
96
|
+
|
|
97
|
+
const touch = e.changedTouches[0];
|
|
98
|
+
touchstart = touch;
|
|
99
|
+
dragStartTime = Date.now();
|
|
100
|
+
directionLock = null;
|
|
101
|
+
|
|
102
|
+
const drawerWidth = window.innerWidth * (drawerWidthPercentage / 100);
|
|
103
|
+
const touchOnDrawer = isOpen && touch.clientX < drawerWidth;
|
|
104
|
+
|
|
105
|
+
// Check if touch is on an interactive element (don't block taps on buttons/links)
|
|
106
|
+
const target = e.target as HTMLElement;
|
|
107
|
+
const isInteractive = target.closest("button, a, input, [role='button']");
|
|
108
|
+
|
|
109
|
+
// Potential drag scenarios - never start isDragging until direction is locked
|
|
110
|
+
// Exception: overlay tap (no scroll content, so no direction conflict)
|
|
111
|
+
if (!isOpen && touch.clientX < 40) {
|
|
112
|
+
// Opening gesture - wait for direction lock before starting drag
|
|
113
|
+
// Prevent Safari's back navigation gesture on iOS (but not on interactive elements)
|
|
114
|
+
if (!isInteractive) {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
}
|
|
117
|
+
potentialDrag = true;
|
|
118
|
+
dragStartedOpen = false;
|
|
119
|
+
} else if (isOpen && !touchOnDrawer) {
|
|
120
|
+
// Touch on overlay - can start immediately (no scroll conflict)
|
|
121
|
+
potentialDrag = true;
|
|
122
|
+
isDragging = true;
|
|
123
|
+
dragStartedOpen = true;
|
|
124
|
+
dragOffset = 0;
|
|
125
|
+
directionLock = "horizontal";
|
|
126
|
+
} else if (isOpen && touchOnDrawer) {
|
|
127
|
+
// Touch on drawer content - wait for direction lock
|
|
128
|
+
potentialDrag = true;
|
|
129
|
+
dragStartedOpen = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function onTouchMove(e: TouchEvent) {
|
|
134
|
+
if (!touchstart || !potentialDrag) return;
|
|
135
|
+
|
|
136
|
+
const touch = e.changedTouches[0];
|
|
137
|
+
const deltaX = touch.clientX - touchstart.clientX;
|
|
138
|
+
const deltaY = touch.clientY - touchstart.clientY;
|
|
139
|
+
|
|
140
|
+
// Determine direction lock if not yet decided
|
|
141
|
+
if (directionLock === null) {
|
|
142
|
+
const absX = Math.abs(deltaX);
|
|
143
|
+
const absY = Math.abs(deltaY);
|
|
144
|
+
|
|
145
|
+
if (absX > DIRECTION_LOCK_THRESHOLD || absY > DIRECTION_LOCK_THRESHOLD) {
|
|
146
|
+
if (absX > absY) {
|
|
147
|
+
// Horizontal movement - commit to drawer drag
|
|
148
|
+
directionLock = "horizontal";
|
|
149
|
+
isDragging = true;
|
|
150
|
+
dragOffset = dragStartedOpen ? 0 : -100;
|
|
151
|
+
} else {
|
|
152
|
+
// Vertical movement - abort potential drag, let content scroll
|
|
153
|
+
directionLock = "vertical";
|
|
154
|
+
potentialDrag = false;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (directionLock !== "horizontal") return;
|
|
163
|
+
|
|
164
|
+
const drawerWidth = window.innerWidth * (drawerWidthPercentage / 100);
|
|
165
|
+
|
|
166
|
+
if (dragStartedOpen) {
|
|
167
|
+
dragOffset = Math.max(-100, Math.min(0, (deltaX / drawerWidth) * 100));
|
|
168
|
+
} else {
|
|
169
|
+
dragOffset = Math.max(-100, Math.min(0, -100 + (deltaX / drawerWidth) * 100));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
lastTouchX = touch.clientX;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function onTouchEnd(e: TouchEvent) {
|
|
176
|
+
if (!potentialDrag) return;
|
|
177
|
+
|
|
178
|
+
if (!isDragging || !touchstart) {
|
|
179
|
+
resetDragState();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const touch = e.changedTouches[0];
|
|
184
|
+
const timeTaken = Date.now() - dragStartTime;
|
|
185
|
+
const distMoved = touch.clientX - touchstart.clientX;
|
|
186
|
+
const velocity = Math.abs(distMoved) / timeTaken;
|
|
187
|
+
|
|
188
|
+
// Determine snap direction based on velocity first, then final movement direction
|
|
189
|
+
if (velocity > VELOCITY_THRESHOLD) {
|
|
190
|
+
isOpen = distMoved > 0;
|
|
191
|
+
} else {
|
|
192
|
+
// For slow drags, use the final movement direction (allows "change of mind")
|
|
193
|
+
const finalDirection = lastTouchX !== null ? touch.clientX - lastTouchX : distMoved;
|
|
194
|
+
isOpen = finalDirection > 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
tap();
|
|
198
|
+
resetDragState();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function onTouchCancel() {
|
|
202
|
+
if (isDragging) {
|
|
203
|
+
isOpen = dragStartedOpen;
|
|
204
|
+
}
|
|
205
|
+
resetDragState();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function resetDragState() {
|
|
209
|
+
isDragging = false;
|
|
210
|
+
potentialDrag = false;
|
|
211
|
+
touchstart = null;
|
|
212
|
+
lastTouchX = null;
|
|
213
|
+
directionLock = null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
onMount(() => {
|
|
217
|
+
// touchstart needs passive: false to allow preventDefault() for Safari back gesture
|
|
218
|
+
window.addEventListener("touchstart", onTouchStart, { passive: false });
|
|
219
|
+
window.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
220
|
+
window.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
221
|
+
window.addEventListener("touchcancel", onTouchCancel, { passive: true });
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
onDestroy(() => {
|
|
225
|
+
if (browser) {
|
|
226
|
+
window.removeEventListener("touchstart", onTouchStart);
|
|
227
|
+
window.removeEventListener("touchmove", onTouchMove);
|
|
228
|
+
window.removeEventListener("touchend", onTouchEnd);
|
|
229
|
+
window.removeEventListener("touchcancel", onTouchCancel);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
</script>
|
|
233
|
+
|
|
234
|
+
<nav
|
|
235
|
+
class="mx-4 mt-4 flex h-12 items-center justify-between rounded-b-xl border-b bg-gray-50 px-3 dark:border-gray-800 dark:bg-gray-800/30 dark:shadow-xl max-md:rounded-xl max-md:border md:hidden"
|
|
236
|
+
>
|
|
237
|
+
<button
|
|
238
|
+
type="button"
|
|
239
|
+
class="-ml-3 flex size-12 shrink-0 items-center justify-center text-lg"
|
|
240
|
+
onclick={() => (isOpen = true)}
|
|
241
|
+
aria-label="Open menu"
|
|
242
|
+
bind:this={openEl}><IconBurger /></button
|
|
243
|
+
>
|
|
244
|
+
<div class="flex h-full items-center justify-center overflow-hidden">
|
|
245
|
+
{#if page.params?.id}
|
|
246
|
+
<span class="max-w-full truncate px-4 first-letter:uppercase" data-testid="chat-title"
|
|
247
|
+
>{title}</span
|
|
248
|
+
>
|
|
249
|
+
{/if}
|
|
250
|
+
</div>
|
|
251
|
+
<div class="-mr-3 flex items-center">
|
|
252
|
+
{#if isHuggingChat}
|
|
253
|
+
<button
|
|
254
|
+
type="button"
|
|
255
|
+
class="flex h-12 w-6 shrink-0 items-center justify-center text-lg"
|
|
256
|
+
disabled={!canShare}
|
|
257
|
+
onclick={() => {
|
|
258
|
+
if (!canShare) return;
|
|
259
|
+
shareModal.open();
|
|
260
|
+
}}
|
|
261
|
+
aria-label="Share conversation"
|
|
262
|
+
>
|
|
263
|
+
<IconShare classNames={!canShare ? "opacity-40" : ""} />
|
|
264
|
+
</button>
|
|
265
|
+
{/if}
|
|
266
|
+
<a
|
|
267
|
+
href="{base}/"
|
|
268
|
+
class="flex size-12 shrink-0 items-center justify-center text-lg"
|
|
269
|
+
onclick={(e) => {
|
|
270
|
+
if (requireAuthUser()) {
|
|
271
|
+
e.preventDefault();
|
|
272
|
+
}
|
|
273
|
+
}}
|
|
274
|
+
>
|
|
275
|
+
<IconNew />
|
|
276
|
+
</a>
|
|
277
|
+
</div>
|
|
278
|
+
</nav>
|
|
279
|
+
|
|
280
|
+
<!-- Mobile drawer overlay - shows when drawer is open or dragging -->
|
|
281
|
+
{#if isOpen || isDragging}
|
|
282
|
+
<button
|
|
283
|
+
type="button"
|
|
284
|
+
class="fixed inset-0 z-20 cursor-default bg-black/30 md:hidden"
|
|
285
|
+
style="opacity: {Math.max(0, Math.min(1, (100 + tween.current) / 100))}; will-change: opacity;"
|
|
286
|
+
onclick={closeDrawer}
|
|
287
|
+
aria-label="Close mobile navigation"
|
|
288
|
+
></button>
|
|
289
|
+
{/if}
|
|
290
|
+
|
|
291
|
+
<nav
|
|
292
|
+
style="transform: translateX({isDragging
|
|
293
|
+
? dragOffset
|
|
294
|
+
: tween.current}%); width: {drawerWidthPercentage}%; will-change: transform;"
|
|
295
|
+
class:shadow-[5px_0_15px_0_rgba(0,0,0,0.3)]={isOpen || isDragging}
|
|
296
|
+
class="fixed bottom-0 left-0 top-0 z-30 grid max-h-dvh grid-cols-1
|
|
297
|
+
grid-rows-[auto,1fr,auto,auto] rounded-r-xl bg-white pt-4 dark:bg-gray-900 md:hidden"
|
|
298
|
+
>
|
|
299
|
+
{@render children?.()}
|
|
300
|
+
</nav>
|