feat: Init mobile app from current Tauri v2 framework

Feat:
- Using Tauri v2 by default
- Add new configuration to initiate mobile app
- Add dependencies needed for mobile build
Test:
- Confirm to be built successfully
- Confirm to keep settings for desktop and build successfully
- Reuse most of components from desktop version
This commit is contained in:
Vanalite 2025-09-16 10:52:12 +07:00
parent cf87313f28
commit fa0ed11258
52 changed files with 3246 additions and 3655 deletions

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ src-tauri/resources/bin
# Helper tools
.opencode
OpenCode.md
Claude.md
archive/
.cache/

View File

@ -18,7 +18,6 @@
"os:default",
"opener:default",
"log:default",
"updater:default",
"dialog:default",
"deep-link:default",
"core:webview:allow-create-webview-window",

View File

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false

19
src-tauri/gen/android/.gitignore vendored Normal file
View File

@ -0,0 +1,19 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
build
/captures
.externalNativeBuild
.cxx
local.properties
key.properties
/.tauri
/tauri.settings.gradle

6
src-tauri/gen/android/app/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/src/main/java/jan/ai/app/generated
/src/main/jniLibs/**/*.so
/src/main/assets/tauri.conf.json
/tauri.build.gradle.kts
/proguard-tauri.pro
/tauri.properties

View File

@ -0,0 +1,70 @@
import java.util.Properties
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("rust")
}
val tauriProperties = Properties().apply {
val propFile = file("tauri.properties")
if (propFile.exists()) {
propFile.inputStream().use { load(it) }
}
}
android {
compileSdk = 36
namespace = "jan.ai.app"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "jan.ai.app"
minSdk = 24
targetSdk = 36
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
isMinifyEnabled = true
proguardFiles(
*fileTree(".") { include("**/*.pro") }
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
.toList().toTypedArray()
)
}
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
buildConfig = true
}
}
rust {
rootDirRel = "../../../"
}
dependencies {
implementation("androidx.webkit:webkit:1.14.0")
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("androidx.activity:activity-ktx:1.10.1")
implementation("com.google.android.material:material:1.12.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
}
apply(from = "tauri.build.gradle.kts")

View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<!-- AndroidTV support -->
<uses-feature android:name="android.software.leanback" android:required="false" />
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.jan"
android:usesCleartextTraffic="${usesCleartextTraffic}">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:launchMode="singleTask"
android:label="@string/main_activity_title"
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- AndroidTV support -->
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View File

@ -0,0 +1,19 @@
Jan
Copyright 2025 Menlo Research
This product includes software developed by Menlo Research (https://menlo.ai).
Licensed under the Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Attribution is requested in user-facing documentation and materials, where appropriate.

View File

@ -0,0 +1,11 @@
package jan.ai.app
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
class MainActivity : TauriActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
}
}

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.jan" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@ -0,0 +1,4 @@
<resources>
<string name="app_name">Jan</string>
<string name="main_activity_title">Jan</string>
</resources>

View File

@ -0,0 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.jan" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="." />
<cache-path name="my_cache_images" path="." />
</paths>

View File

@ -0,0 +1,22 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.11.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
tasks.register("clean").configure {
delete("build")
}

View File

@ -0,0 +1,23 @@
plugins {
`kotlin-dsl`
}
gradlePlugin {
plugins {
create("pluginsForCoolKids") {
id = "rust"
implementationClass = "RustPlugin"
}
}
}
repositories {
google()
mavenCentral()
}
dependencies {
compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:8.11.0")
}

View File

@ -0,0 +1,52 @@
import java.io.File
import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
open class BuildTask : DefaultTask() {
@Input
var rootDirRel: String? = null
@Input
var target: String? = null
@Input
var release: Boolean? = null
@TaskAction
fun assemble() {
val executable = """yarn""";
try {
runTauriCli(executable)
} catch (e: Exception) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
runTauriCli("$executable.cmd")
} else {
throw e;
}
}
}
fun runTauriCli(executable: String) {
val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null")
val target = target ?: throw GradleException("target cannot be null")
val release = release ?: throw GradleException("release cannot be null")
val args = listOf("tauri", "android", "android-studio-script");
project.exec {
workingDir(File(project.projectDir, rootDirRel))
executable(executable)
args(args)
if (project.logger.isEnabled(LogLevel.DEBUG)) {
args("-vv")
} else if (project.logger.isEnabled(LogLevel.INFO)) {
args("-v")
}
if (release) {
args("--release")
}
args(listOf("--target", target))
}.assertNormalExitValue()
}
}

View File

@ -0,0 +1,85 @@
import com.android.build.api.dsl.ApplicationExtension
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
const val TASK_GROUP = "rust"
open class Config {
lateinit var rootDirRel: String
}
open class RustPlugin : Plugin<Project> {
private lateinit var config: Config
override fun apply(project: Project) = with(project) {
config = extensions.create("rust", Config::class.java)
val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64");
val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList
val defaultArchList = listOf("arm64", "arm", "x86", "x86_64");
val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList
val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64")
extensions.configure<ApplicationExtension> {
@Suppress("UnstableApiUsage")
flavorDimensions.add("abi")
productFlavors {
create("universal") {
dimension = "abi"
ndk {
abiFilters += abiList
}
}
defaultArchList.forEachIndexed { index, arch ->
create(arch) {
dimension = "abi"
ndk {
abiFilters.add(defaultAbiList[index])
}
}
}
}
}
afterEvaluate {
for (profile in listOf("debug", "release")) {
val profileCapitalized = profile.replaceFirstChar { it.uppercase() }
val buildTask = tasks.maybeCreate(
"rustBuildUniversal$profileCapitalized",
DefaultTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for all targets"
}
tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask)
for (targetPair in targetsList.withIndex()) {
val targetName = targetPair.value
val targetArch = archList[targetPair.index]
val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() }
val targetBuildTask = project.tasks.maybeCreate(
"rustBuild$targetArchCapitalized$profileCapitalized",
BuildTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for $targetArch"
rootDirRel = config.rootDirRel
target = targetName
release = profile == "release"
}
buildTask.dependsOn(targetBuildTask)
tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn(
targetBuildTask
)
}
}
}
}
}

View File

@ -0,0 +1,24 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.nonFinalResIds=false

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Tue May 10 19:22:52 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

185
src-tauri/gen/android/gradlew vendored Executable file
View File

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
src-tauri/gen/android/gradlew.bat vendored Normal file
View File

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,3 @@
include ':app'
apply from: 'tauri.settings.gradle'

View File

@ -0,0 +1,19 @@
Jan
Copyright 2025 Menlo Research
This product includes software developed by Menlo Research (https://menlo.ai).
Licensed under the Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Attribution is requested in user-facing documentation and materials, where appropriate.

View File

@ -12,12 +12,15 @@ use crate::core::state::AppState;
#[tauri::command]
pub fn factory_reset(app_handle: tauri::AppHandle, state: State<'_, AppState>) {
// close window
let windows = app_handle.webview_windows();
for (label, window) in windows.iter() {
window.close().unwrap_or_else(|_| {
log::warn!("Failed to close window: {:?}", label);
});
// close window (not available on mobile platforms)
#[cfg(not(any(target_os = "ios", target_os = "android")))]
{
let windows = app_handle.webview_windows();
for (label, window) in windows.iter() {
window.close().unwrap_or_else(|_| {
log::warn!("Failed to close window: {:?}", label);
});
}
}
let data_folder = get_jan_data_folder_path(app_handle.clone());
log::info!("Factory reset, removing data folder: {:?}", data_folder);

View File

@ -3,7 +3,7 @@ use std::io::{BufRead, BufReader, Write};
use tauri::Runtime;
// For async file write serialization
use once_cell::sync::Lazy;
use std::sync::OnceLock;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
@ -11,12 +11,12 @@ use tokio::sync::Mutex;
use super::utils::{get_messages_path, get_thread_metadata_path};
// Global per-thread locks for message file writes
pub static MESSAGE_LOCKS: Lazy<Mutex<HashMap<String, Arc<Mutex<()>>>>> =
Lazy::new(|| Mutex::new(HashMap::new()));
pub static MESSAGE_LOCKS: OnceLock<Mutex<HashMap<String, Arc<Mutex<()>>>>> = OnceLock::new();
/// Get a lock for a specific thread to ensure thread-safe message file operations
pub async fn get_lock_for_thread(thread_id: &str) -> Arc<Mutex<()>> {
let mut locks = MESSAGE_LOCKS.lock().await;
let locks = MESSAGE_LOCKS.get_or_init(|| Mutex::new(HashMap::new()));
let mut locks = locks.lock().await;
let lock = locks
.entry(thread_id.to_string())
.or_insert_with(|| Arc::new(Mutex::new(())))

View File

@ -30,7 +30,6 @@ pub fn run() {
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_store::Builder::new().build())
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_llamacpp::init())
.plugin(tauri_plugin_hardware::init())
@ -122,8 +121,8 @@ pub fn run() {
])
.build(),
)?;
app.handle()
.plugin(tauri_plugin_updater::Builder::new().build())?;
#[cfg(not(any(target_os = "ios", target_os = "android")))]
app.handle().plugin(tauri_plugin_updater::Builder::new().build())?;
// Install extensions
if let Err(e) = setup::install_extensions(app.handle().clone(), false) {
log::error!("Failed to install extensions: {}", e);
@ -148,9 +147,10 @@ pub fn run() {
let app_handle = app.clone();
tokio::task::block_in_place(|| {
tauri::async_runtime::block_on(async {
// Hide window immediately
// Hide window immediately (not available on mobile platforms)
if let Some(window) = app_handle.get_webview_window("main") {
let _ = window.hide();
#[cfg(not(any(target_os = "ios", target_os = "android")))]
{ let _ = window.hide(); }
let _ = window.emit("kill-mcp-servers", ());
}

View File

@ -6,7 +6,7 @@
"build": {
"frontendDist": "../web-app/dist",
"devUrl": "http://localhost:1420",
"beforeDevCommand": "cross-env IS_TAURI=true yarn dev:web",
"beforeDevCommand": "cross-env IS_TAURI=true yarn workspace @janhq/web-app dev",
"beforeBuildCommand": "cross-env IS_TAURI=true yarn build:web"
},
"app": {

View File

@ -0,0 +1,6 @@
{
"bundle": {
"iOS": {
}
}
}

View File

@ -1,7 +1,7 @@
import { useLeftPanel } from '@/hooks/useLeftPanel'
import { cn } from '@/lib/utils'
import { IconLayoutSidebar } from '@tabler/icons-react'
import { ReactNode } from '@tanstack/react-router'
import { ReactNode } from 'react'
type HeaderPageProps = {
children?: ReactNode

View File

@ -8,288 +8,124 @@
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
// Import Routes
import { Route as rootRouteImport } from './routes/__root'
import { Route as SystemMonitorRouteImport } from './routes/system-monitor'
import { Route as LogsRouteImport } from './routes/logs'
import { Route as AssistantRouteImport } from './routes/assistant'
import { Route as IndexRouteImport } from './routes/index'
import { Route as HubIndexRouteImport } from './routes/hub/index'
import { Route as ThreadsThreadIdRouteImport } from './routes/threads/$threadId'
import { Route as SettingsShortcutsRouteImport } from './routes/settings/shortcuts'
import { Route as SettingsPrivacyRouteImport } from './routes/settings/privacy'
import { Route as SettingsMcpServersRouteImport } from './routes/settings/mcp-servers'
import { Route as SettingsLocalApiServerRouteImport } from './routes/settings/local-api-server'
import { Route as SettingsHttpsProxyRouteImport } from './routes/settings/https-proxy'
import { Route as SettingsHardwareRouteImport } from './routes/settings/hardware'
import { Route as SettingsGeneralRouteImport } from './routes/settings/general'
import { Route as SettingsExtensionsRouteImport } from './routes/settings/extensions'
import { Route as SettingsAppearanceRouteImport } from './routes/settings/appearance'
import { Route as LocalApiServerLogsRouteImport } from './routes/local-api-server/logs'
import { Route as HubModelIdRouteImport } from './routes/hub/$modelId'
import { Route as SettingsProvidersIndexRouteImport } from './routes/settings/providers/index'
import { Route as SettingsProvidersProviderNameRouteImport } from './routes/settings/providers/$providerName'
import { Route as rootRoute } from './routes/__root'
import { Route as SystemMonitorImport } from './routes/system-monitor'
import { Route as LogsImport } from './routes/logs'
import { Route as AssistantImport } from './routes/assistant'
import { Route as IndexImport } from './routes/index'
import { Route as HubIndexImport } from './routes/hub/index'
import { Route as ThreadsThreadIdImport } from './routes/threads/$threadId'
import { Route as SettingsShortcutsImport } from './routes/settings/shortcuts'
import { Route as SettingsPrivacyImport } from './routes/settings/privacy'
import { Route as SettingsMcpServersImport } from './routes/settings/mcp-servers'
import { Route as SettingsLocalApiServerImport } from './routes/settings/local-api-server'
import { Route as SettingsHttpsProxyImport } from './routes/settings/https-proxy'
import { Route as SettingsHardwareImport } from './routes/settings/hardware'
import { Route as SettingsGeneralImport } from './routes/settings/general'
import { Route as SettingsExtensionsImport } from './routes/settings/extensions'
import { Route as SettingsAppearanceImport } from './routes/settings/appearance'
import { Route as LocalApiServerLogsImport } from './routes/local-api-server/logs'
import { Route as HubModelIdImport } from './routes/hub/$modelId'
import { Route as SettingsProvidersIndexImport } from './routes/settings/providers/index'
import { Route as SettingsProvidersProviderNameImport } from './routes/settings/providers/$providerName'
// Create/Update Routes
const SystemMonitorRoute = SystemMonitorImport.update({
const SystemMonitorRoute = SystemMonitorRouteImport.update({
id: '/system-monitor',
path: '/system-monitor',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const LogsRoute = LogsImport.update({
const LogsRoute = LogsRouteImport.update({
id: '/logs',
path: '/logs',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const AssistantRoute = AssistantImport.update({
const AssistantRoute = AssistantRouteImport.update({
id: '/assistant',
path: '/assistant',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const IndexRoute = IndexImport.update({
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const HubIndexRoute = HubIndexImport.update({
const HubIndexRoute = HubIndexRouteImport.update({
id: '/hub/',
path: '/hub/',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const ThreadsThreadIdRoute = ThreadsThreadIdImport.update({
const ThreadsThreadIdRoute = ThreadsThreadIdRouteImport.update({
id: '/threads/$threadId',
path: '/threads/$threadId',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsShortcutsRoute = SettingsShortcutsImport.update({
const SettingsShortcutsRoute = SettingsShortcutsRouteImport.update({
id: '/settings/shortcuts',
path: '/settings/shortcuts',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsPrivacyRoute = SettingsPrivacyImport.update({
const SettingsPrivacyRoute = SettingsPrivacyRouteImport.update({
id: '/settings/privacy',
path: '/settings/privacy',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsMcpServersRoute = SettingsMcpServersImport.update({
const SettingsMcpServersRoute = SettingsMcpServersRouteImport.update({
id: '/settings/mcp-servers',
path: '/settings/mcp-servers',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsLocalApiServerRoute = SettingsLocalApiServerImport.update({
const SettingsLocalApiServerRoute = SettingsLocalApiServerRouteImport.update({
id: '/settings/local-api-server',
path: '/settings/local-api-server',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsHttpsProxyRoute = SettingsHttpsProxyImport.update({
const SettingsHttpsProxyRoute = SettingsHttpsProxyRouteImport.update({
id: '/settings/https-proxy',
path: '/settings/https-proxy',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsHardwareRoute = SettingsHardwareImport.update({
const SettingsHardwareRoute = SettingsHardwareRouteImport.update({
id: '/settings/hardware',
path: '/settings/hardware',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsGeneralRoute = SettingsGeneralImport.update({
const SettingsGeneralRoute = SettingsGeneralRouteImport.update({
id: '/settings/general',
path: '/settings/general',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsExtensionsRoute = SettingsExtensionsImport.update({
const SettingsExtensionsRoute = SettingsExtensionsRouteImport.update({
id: '/settings/extensions',
path: '/settings/extensions',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsAppearanceRoute = SettingsAppearanceImport.update({
const SettingsAppearanceRoute = SettingsAppearanceRouteImport.update({
id: '/settings/appearance',
path: '/settings/appearance',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const LocalApiServerLogsRoute = LocalApiServerLogsImport.update({
const LocalApiServerLogsRoute = LocalApiServerLogsRouteImport.update({
id: '/local-api-server/logs',
path: '/local-api-server/logs',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const HubModelIdRoute = HubModelIdImport.update({
const HubModelIdRoute = HubModelIdRouteImport.update({
id: '/hub/$modelId',
path: '/hub/$modelId',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsProvidersIndexRoute = SettingsProvidersIndexImport.update({
const SettingsProvidersIndexRoute = SettingsProvidersIndexRouteImport.update({
id: '/settings/providers/',
path: '/settings/providers/',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
const SettingsProvidersProviderNameRoute =
SettingsProvidersProviderNameImport.update({
SettingsProvidersProviderNameRouteImport.update({
id: '/settings/providers/$providerName',
path: '/settings/providers/$providerName',
getParentRoute: () => rootRoute,
getParentRoute: () => rootRouteImport,
} as any)
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute
}
'/assistant': {
id: '/assistant'
path: '/assistant'
fullPath: '/assistant'
preLoaderRoute: typeof AssistantImport
parentRoute: typeof rootRoute
}
'/logs': {
id: '/logs'
path: '/logs'
fullPath: '/logs'
preLoaderRoute: typeof LogsImport
parentRoute: typeof rootRoute
}
'/system-monitor': {
id: '/system-monitor'
path: '/system-monitor'
fullPath: '/system-monitor'
preLoaderRoute: typeof SystemMonitorImport
parentRoute: typeof rootRoute
}
'/hub/$modelId': {
id: '/hub/$modelId'
path: '/hub/$modelId'
fullPath: '/hub/$modelId'
preLoaderRoute: typeof HubModelIdImport
parentRoute: typeof rootRoute
}
'/local-api-server/logs': {
id: '/local-api-server/logs'
path: '/local-api-server/logs'
fullPath: '/local-api-server/logs'
preLoaderRoute: typeof LocalApiServerLogsImport
parentRoute: typeof rootRoute
}
'/settings/appearance': {
id: '/settings/appearance'
path: '/settings/appearance'
fullPath: '/settings/appearance'
preLoaderRoute: typeof SettingsAppearanceImport
parentRoute: typeof rootRoute
}
'/settings/extensions': {
id: '/settings/extensions'
path: '/settings/extensions'
fullPath: '/settings/extensions'
preLoaderRoute: typeof SettingsExtensionsImport
parentRoute: typeof rootRoute
}
'/settings/general': {
id: '/settings/general'
path: '/settings/general'
fullPath: '/settings/general'
preLoaderRoute: typeof SettingsGeneralImport
parentRoute: typeof rootRoute
}
'/settings/hardware': {
id: '/settings/hardware'
path: '/settings/hardware'
fullPath: '/settings/hardware'
preLoaderRoute: typeof SettingsHardwareImport
parentRoute: typeof rootRoute
}
'/settings/https-proxy': {
id: '/settings/https-proxy'
path: '/settings/https-proxy'
fullPath: '/settings/https-proxy'
preLoaderRoute: typeof SettingsHttpsProxyImport
parentRoute: typeof rootRoute
}
'/settings/local-api-server': {
id: '/settings/local-api-server'
path: '/settings/local-api-server'
fullPath: '/settings/local-api-server'
preLoaderRoute: typeof SettingsLocalApiServerImport
parentRoute: typeof rootRoute
}
'/settings/mcp-servers': {
id: '/settings/mcp-servers'
path: '/settings/mcp-servers'
fullPath: '/settings/mcp-servers'
preLoaderRoute: typeof SettingsMcpServersImport
parentRoute: typeof rootRoute
}
'/settings/privacy': {
id: '/settings/privacy'
path: '/settings/privacy'
fullPath: '/settings/privacy'
preLoaderRoute: typeof SettingsPrivacyImport
parentRoute: typeof rootRoute
}
'/settings/shortcuts': {
id: '/settings/shortcuts'
path: '/settings/shortcuts'
fullPath: '/settings/shortcuts'
preLoaderRoute: typeof SettingsShortcutsImport
parentRoute: typeof rootRoute
}
'/threads/$threadId': {
id: '/threads/$threadId'
path: '/threads/$threadId'
fullPath: '/threads/$threadId'
preLoaderRoute: typeof ThreadsThreadIdImport
parentRoute: typeof rootRoute
}
'/hub/': {
id: '/hub/'
path: '/hub'
fullPath: '/hub'
preLoaderRoute: typeof HubIndexImport
parentRoute: typeof rootRoute
}
'/settings/providers/$providerName': {
id: '/settings/providers/$providerName'
path: '/settings/providers/$providerName'
fullPath: '/settings/providers/$providerName'
preLoaderRoute: typeof SettingsProvidersProviderNameImport
parentRoute: typeof rootRoute
}
'/settings/providers/': {
id: '/settings/providers/'
path: '/settings/providers'
fullPath: '/settings/providers'
preLoaderRoute: typeof SettingsProvidersIndexImport
parentRoute: typeof rootRoute
}
}
}
// Create and export the route tree
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/assistant': typeof AssistantRoute
@ -311,7 +147,6 @@ export interface FileRoutesByFullPath {
'/settings/providers/$providerName': typeof SettingsProvidersProviderNameRoute
'/settings/providers': typeof SettingsProvidersIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/assistant': typeof AssistantRoute
@ -333,9 +168,8 @@ export interface FileRoutesByTo {
'/settings/providers/$providerName': typeof SettingsProvidersProviderNameRoute
'/settings/providers': typeof SettingsProvidersIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRoute
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/assistant': typeof AssistantRoute
'/logs': typeof LogsRoute
@ -356,7 +190,6 @@ export interface FileRoutesById {
'/settings/providers/$providerName': typeof SettingsProvidersProviderNameRoute
'/settings/providers/': typeof SettingsProvidersIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
@ -423,7 +256,6 @@ export interface FileRouteTypes {
| '/settings/providers/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
AssistantRoute: typeof AssistantRoute
@ -446,6 +278,144 @@ export interface RootRouteChildren {
SettingsProvidersIndexRoute: typeof SettingsProvidersIndexRoute
}
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/system-monitor': {
id: '/system-monitor'
path: '/system-monitor'
fullPath: '/system-monitor'
preLoaderRoute: typeof SystemMonitorRouteImport
parentRoute: typeof rootRouteImport
}
'/logs': {
id: '/logs'
path: '/logs'
fullPath: '/logs'
preLoaderRoute: typeof LogsRouteImport
parentRoute: typeof rootRouteImport
}
'/assistant': {
id: '/assistant'
path: '/assistant'
fullPath: '/assistant'
preLoaderRoute: typeof AssistantRouteImport
parentRoute: typeof rootRouteImport
}
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexRouteImport
parentRoute: typeof rootRouteImport
}
'/hub/': {
id: '/hub/'
path: '/hub'
fullPath: '/hub'
preLoaderRoute: typeof HubIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/threads/$threadId': {
id: '/threads/$threadId'
path: '/threads/$threadId'
fullPath: '/threads/$threadId'
preLoaderRoute: typeof ThreadsThreadIdRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/shortcuts': {
id: '/settings/shortcuts'
path: '/settings/shortcuts'
fullPath: '/settings/shortcuts'
preLoaderRoute: typeof SettingsShortcutsRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/privacy': {
id: '/settings/privacy'
path: '/settings/privacy'
fullPath: '/settings/privacy'
preLoaderRoute: typeof SettingsPrivacyRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/mcp-servers': {
id: '/settings/mcp-servers'
path: '/settings/mcp-servers'
fullPath: '/settings/mcp-servers'
preLoaderRoute: typeof SettingsMcpServersRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/local-api-server': {
id: '/settings/local-api-server'
path: '/settings/local-api-server'
fullPath: '/settings/local-api-server'
preLoaderRoute: typeof SettingsLocalApiServerRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/https-proxy': {
id: '/settings/https-proxy'
path: '/settings/https-proxy'
fullPath: '/settings/https-proxy'
preLoaderRoute: typeof SettingsHttpsProxyRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/hardware': {
id: '/settings/hardware'
path: '/settings/hardware'
fullPath: '/settings/hardware'
preLoaderRoute: typeof SettingsHardwareRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/general': {
id: '/settings/general'
path: '/settings/general'
fullPath: '/settings/general'
preLoaderRoute: typeof SettingsGeneralRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/extensions': {
id: '/settings/extensions'
path: '/settings/extensions'
fullPath: '/settings/extensions'
preLoaderRoute: typeof SettingsExtensionsRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/appearance': {
id: '/settings/appearance'
path: '/settings/appearance'
fullPath: '/settings/appearance'
preLoaderRoute: typeof SettingsAppearanceRouteImport
parentRoute: typeof rootRouteImport
}
'/local-api-server/logs': {
id: '/local-api-server/logs'
path: '/local-api-server/logs'
fullPath: '/local-api-server/logs'
preLoaderRoute: typeof LocalApiServerLogsRouteImport
parentRoute: typeof rootRouteImport
}
'/hub/$modelId': {
id: '/hub/$modelId'
path: '/hub/$modelId'
fullPath: '/hub/$modelId'
preLoaderRoute: typeof HubModelIdRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/providers/': {
id: '/settings/providers/'
path: '/settings/providers'
fullPath: '/settings/providers'
preLoaderRoute: typeof SettingsProvidersIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/settings/providers/$providerName': {
id: '/settings/providers/$providerName'
path: '/settings/providers/$providerName'
fullPath: '/settings/providers/$providerName'
preLoaderRoute: typeof SettingsProvidersProviderNameRouteImport
parentRoute: typeof rootRouteImport
}
}
}
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
AssistantRoute: AssistantRoute,
@ -467,95 +437,6 @@ const rootRouteChildren: RootRouteChildren = {
SettingsProvidersProviderNameRoute: SettingsProvidersProviderNameRoute,
SettingsProvidersIndexRoute: SettingsProvidersIndexRoute,
}
export const routeTree = rootRoute
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
/* ROUTE_MANIFEST_START
{
"routes": {
"__root__": {
"filePath": "__root.tsx",
"children": [
"/",
"/assistant",
"/logs",
"/system-monitor",
"/hub/$modelId",
"/local-api-server/logs",
"/settings/appearance",
"/settings/extensions",
"/settings/general",
"/settings/hardware",
"/settings/https-proxy",
"/settings/local-api-server",
"/settings/mcp-servers",
"/settings/privacy",
"/settings/shortcuts",
"/threads/$threadId",
"/hub/",
"/settings/providers/$providerName",
"/settings/providers/"
]
},
"/": {
"filePath": "index.tsx"
},
"/assistant": {
"filePath": "assistant.tsx"
},
"/logs": {
"filePath": "logs.tsx"
},
"/system-monitor": {
"filePath": "system-monitor.tsx"
},
"/hub/$modelId": {
"filePath": "hub/$modelId.tsx"
},
"/local-api-server/logs": {
"filePath": "local-api-server/logs.tsx"
},
"/settings/appearance": {
"filePath": "settings/appearance.tsx"
},
"/settings/extensions": {
"filePath": "settings/extensions.tsx"
},
"/settings/general": {
"filePath": "settings/general.tsx"
},
"/settings/hardware": {
"filePath": "settings/hardware.tsx"
},
"/settings/https-proxy": {
"filePath": "settings/https-proxy.tsx"
},
"/settings/local-api-server": {
"filePath": "settings/local-api-server.tsx"
},
"/settings/mcp-servers": {
"filePath": "settings/mcp-servers.tsx"
},
"/settings/privacy": {
"filePath": "settings/privacy.tsx"
},
"/settings/shortcuts": {
"filePath": "settings/shortcuts.tsx"
},
"/threads/$threadId": {
"filePath": "threads/$threadId.tsx"
},
"/hub/": {
"filePath": "hub/index.tsx"
},
"/settings/providers/$providerName": {
"filePath": "settings/providers/$providerName.tsx"
},
"/settings/providers/": {
"filePath": "settings/providers/index.tsx"
}
}
}
ROUTE_MANIFEST_END */

5386
yarn.lock

File diff suppressed because it is too large Load Diff