diff --git a/app/store/database.go b/app/store/database.go
index 8747e9598..97e792e17 100644
--- a/app/store/database.go
+++ b/app/store/database.go
@@ -82,7 +82,7 @@ func (db *database) init() error {
websearch_enabled BOOLEAN NOT NULL DEFAULT 0,
selected_model TEXT NOT NULL DEFAULT '',
sidebar_open BOOLEAN NOT NULL DEFAULT 0,
- last_home_view TEXT NOT NULL DEFAULT 'chat',
+ last_home_view TEXT NOT NULL DEFAULT 'launch',
think_enabled BOOLEAN NOT NULL DEFAULT 0,
think_level TEXT NOT NULL DEFAULT '',
cloud_setting_migrated BOOLEAN NOT NULL DEFAULT 0,
@@ -527,7 +527,7 @@ func (db *database) migrateV14ToV15() error {
// migrateV15ToV16 adds the last_home_view column to the settings table
func (db *database) migrateV15ToV16() error {
- _, err := db.conn.Exec(`ALTER TABLE settings ADD COLUMN last_home_view TEXT NOT NULL DEFAULT 'chat'`)
+ _, err := db.conn.Exec(`ALTER TABLE settings ADD COLUMN last_home_view TEXT NOT NULL DEFAULT 'launch'`)
if err != nil && !duplicateColumnError(err) {
return fmt.Errorf("add last_home_view column: %w", err)
}
@@ -1211,7 +1211,7 @@ func (db *database) setSettings(s Settings) error {
}
if lastHomeView != "chat" {
if _, ok := validLaunchView[lastHomeView]; !ok {
- lastHomeView = "chat"
+ lastHomeView = "launch"
}
}
diff --git a/app/store/database_test.go b/app/store/database_test.go
index a5ebabd2e..3411e11bf 100644
--- a/app/store/database_test.go
+++ b/app/store/database_test.go
@@ -135,6 +135,45 @@ func TestMigrationV13ToV14ContextLength(t *testing.T) {
}
}
+func TestMigrationV15ToV16LastHomeViewDefaultsToLaunch(t *testing.T) {
+ tmpDir := t.TempDir()
+ dbPath := filepath.Join(tmpDir, "test.db")
+
+ db, err := newDatabase(dbPath)
+ if err != nil {
+ t.Fatalf("failed to create database: %v", err)
+ }
+ defer db.Close()
+
+ if _, err := db.conn.Exec(`
+ ALTER TABLE settings DROP COLUMN last_home_view;
+ UPDATE settings SET schema_version = 15;
+ `); err != nil {
+ t.Fatalf("failed to seed v15 settings row: %v", err)
+ }
+
+ if err := db.migrate(); err != nil {
+ t.Fatalf("migration from v15 to v16 failed: %v", err)
+ }
+
+ var lastHomeView string
+ if err := db.conn.QueryRow("SELECT last_home_view FROM settings").Scan(&lastHomeView); err != nil {
+ t.Fatalf("failed to read last_home_view: %v", err)
+ }
+
+ if lastHomeView != "launch" {
+ t.Fatalf("expected last_home_view to default to launch after migration, got %q", lastHomeView)
+ }
+
+ version, err := db.getSchemaVersion()
+ if err != nil {
+ t.Fatalf("failed to get schema version: %v", err)
+ }
+ if version != currentSchemaVersion {
+ t.Fatalf("expected schema version %d, got %d", currentSchemaVersion, version)
+ }
+}
+
func TestChatDeletionWithCascade(t *testing.T) {
t.Run("chat deletion cascades to related messages", func(t *testing.T) {
tmpDir := t.TempDir()
diff --git a/app/store/store.go b/app/store/store.go
index 2fd5ce495..369c1db20 100644
--- a/app/store/store.go
+++ b/app/store/store.go
@@ -393,7 +393,7 @@ func (s *Store) Settings() (Settings, error) {
}
if settings.LastHomeView == "" {
- settings.LastHomeView = "chat"
+ settings.LastHomeView = "launch"
}
return settings, nil
diff --git a/app/store/store_test.go b/app/store/store_test.go
index dfe6435f1..1985fda7d 100644
--- a/app/store/store_test.go
+++ b/app/store/store_test.go
@@ -81,6 +81,32 @@ func TestStore(t *testing.T) {
}
})
+ t.Run("settings default home view is launch", func(t *testing.T) {
+ loaded, err := s.Settings()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if loaded.LastHomeView != "launch" {
+ t.Fatalf("expected default LastHomeView to be launch, got %q", loaded.LastHomeView)
+ }
+ })
+
+ t.Run("settings empty home view falls back to launch", func(t *testing.T) {
+ if err := s.SetSettings(Settings{LastHomeView: ""}); err != nil {
+ t.Fatal(err)
+ }
+
+ loaded, err := s.Settings()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if loaded.LastHomeView != "launch" {
+ t.Fatalf("expected empty LastHomeView to fall back to launch, got %q", loaded.LastHomeView)
+ }
+ })
+
t.Run("window size", func(t *testing.T) {
if err := s.SetWindowSize(1024, 768); err != nil {
t.Fatal(err)
diff --git a/app/ui/app/src/components/ChatSidebar.tsx b/app/ui/app/src/components/ChatSidebar.tsx
index 8b9209908..2d1b07a61 100644
--- a/app/ui/app/src/components/ChatSidebar.tsx
+++ b/app/ui/app/src/components/ChatSidebar.tsx
@@ -12,6 +12,7 @@ import { CogIcon, RocketLaunchIcon } from "@heroicons/react/24/outline";
// holding shift and clicking this many times within this many seconds
const DEBUG_SHIFT_CLICKS_REQUIRED = 5;
const DEBUG_SHIFT_CLICK_WINDOW_MS = 7000; // 7 seconds
+const launchSidebarRequestedKey = "ollama.launchSidebarRequested";
interface ChatSidebarProps {
currentChatId?: string;
@@ -285,6 +286,11 @@ export function ChatSidebar({ currentChatId }: ChatSidebarProps) {
{
+ if (currentChatId !== "launch") {
+ sessionStorage.setItem(launchSidebarRequestedKey, "1");
+ }
+ }}
className={`flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left text-sm text-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-800 dark:text-neutral-100 cursor-pointer ${currentChatId === "launch"
? "bg-neutral-100 dark:bg-neutral-800"
: ""
diff --git a/app/ui/app/src/hooks/useSettings.ts b/app/ui/app/src/hooks/useSettings.ts
index 030447646..1eebcf533 100644
--- a/app/ui/app/src/hooks/useSettings.ts
+++ b/app/ui/app/src/hooks/useSettings.ts
@@ -52,7 +52,7 @@ export function useSettings() {
thinkLevel: settingsData?.settings?.ThinkLevel ?? "none",
selectedModel: settingsData?.settings?.SelectedModel ?? "",
sidebarOpen: settingsData?.settings?.SidebarOpen ?? false,
- lastHomeView: settingsData?.settings?.LastHomeView ?? "chat",
+ lastHomeView: settingsData?.settings?.LastHomeView ?? "launch",
}),
[settingsData?.settings],
);
diff --git a/app/ui/app/src/routes/c.$chatId.tsx b/app/ui/app/src/routes/c.$chatId.tsx
index b0061f421..fa72ac496 100644
--- a/app/ui/app/src/routes/c.$chatId.tsx
+++ b/app/ui/app/src/routes/c.$chatId.tsx
@@ -5,9 +5,31 @@ import { getChat } from "@/api";
import { SidebarLayout } from "@/components/layout/layout";
import { ChatSidebar } from "@/components/ChatSidebar";
import LaunchCommands from "@/components/LaunchCommands";
-import { useEffect } from "react";
+import { useEffect, useRef } from "react";
import { useSettings } from "@/hooks/useSettings";
+const launchSidebarRequestedKey = "ollama.launchSidebarRequested";
+const launchSidebarSeenKey = "ollama.launchSidebarSeen";
+const fallbackSessionState = new Map();
+
+function getSessionState() {
+ if (typeof sessionStorage !== "undefined") {
+ return sessionStorage;
+ }
+
+ return {
+ getItem(key: string) {
+ return fallbackSessionState.get(key) ?? null;
+ },
+ setItem(key: string, value: string) {
+ fallbackSessionState.set(key, value);
+ },
+ removeItem(key: string) {
+ fallbackSessionState.delete(key);
+ },
+ };
+}
+
export const Route = createFileRoute("/c/$chatId")({
component: RouteComponent,
loader: async ({ context, params }) => {
@@ -25,6 +47,7 @@ export const Route = createFileRoute("/c/$chatId")({
function RouteComponent() {
const { chatId } = Route.useParams();
const { settingsData, setSettings } = useSettings();
+ const previousChatIdRef = useRef(null);
// Always call hooks at the top level - use a flag to skip data when chatId is a special view
const {
@@ -38,15 +61,42 @@ function RouteComponent() {
return;
}
+ const previousChatId = previousChatIdRef.current;
+ previousChatIdRef.current = chatId;
+
if (chatId === "launch") {
- if (
- settingsData.LastHomeView !== "chat" &&
- settingsData.LastHomeView !== "launch"
- ) {
+ const sessionState = getSessionState();
+ const shouldOpenSidebar =
+ previousChatId !== "launch" &&
+ (() => {
+ if (sessionState.getItem(launchSidebarRequestedKey) === "1") {
+ sessionState.removeItem(launchSidebarRequestedKey);
+ sessionState.setItem(launchSidebarSeenKey, "1");
+ return true;
+ }
+
+ if (sessionState.getItem(launchSidebarSeenKey) !== "1") {
+ sessionState.setItem(launchSidebarSeenKey, "1");
+ return true;
+ }
+
+ return false;
+ })();
+ const updates: { LastHomeView?: string; SidebarOpen?: boolean } = {};
+
+ if (settingsData.LastHomeView !== "launch") {
+ updates.LastHomeView = "launch";
+ }
+
+ if (shouldOpenSidebar && !settingsData.SidebarOpen) {
+ updates.SidebarOpen = true;
+ }
+
+ if (Object.keys(updates).length === 0) {
return;
}
- setSettings({ LastHomeView: "openclaw" }).catch(() => {
+ setSettings(updates).catch(() => {
// Best effort persistence for home view preference.
});
return;
diff --git a/app/ui/app/src/routes/index.tsx b/app/ui/app/src/routes/index.tsx
index 65ba4ed65..9aadf0027 100644
--- a/app/ui/app/src/routes/index.tsx
+++ b/app/ui/app/src/routes/index.tsx
@@ -7,8 +7,8 @@ export const Route = createFileRoute("/")({
queryKey: ["settings"],
queryFn: getSettings,
});
- const lastHomeView = settingsData?.settings?.LastHomeView ?? "chat";
- const chatId = lastHomeView === "chat" ? "new" : "launch";
+ const chatId =
+ settingsData?.settings?.LastHomeView === "chat" ? "new" : "launch";
throw redirect({
to: "/c/$chatId",