diff --git a/CHANGELOG.md b/CHANGELOG.md index 59ffa46..bfc4be5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.1] - 2026-07-11 + +### Fixed + +- 🏠 **Home chats work like workspace chats.** Home keeps chats, terminals, and browser pages alive while you switch tabs, streams replies as they arrive, and correctly loads global skills. + ## [0.9.0] - 2026-07-11 ### Added diff --git a/README.md b/README.md index 9badcb6..0116694 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ![Open WebUI Computer Demo](./demo.png) -Open WebUI Computer (`cptr`) runs on your machine and serves your whole computer to any browser: files, terminal, editor, git, running sessions, AI agents, and tools. It literally is your computer. +Open WebUI Computer (`cptr`) runs on your machine and serves your whole computer to any browser: files, terminal, editor, git, browser tabs, running sessions, AI agents, and tools. It literally is your computer. Use it from your phone, tablet, laptop, another computer, or the machine it's running on. Designed to feel native on every screen. Connect your own AI via API key, plug in a coding agent you already subscribe to, or work directly in the terminal. One tool, full workstation, any device. @@ -65,10 +65,11 @@ Open WebUI Computer is the real workstation surface: files, shell, git state, wo | ✏️ **Editor** | Syntax-highlighted editing with tabs. Open multiple files side by side. | | 🔀 **Git** | Stage, commit, diff, branch, push. Visual changes view. No command line required. | | ⌨️ **Terminal** | Full shell in the browser. Run your tools, your scripts, or your favourite coding agent. | +| 🌐 **Browser** | Browse with Proxy, a private Managed Chrome profile, or your own Personal Chrome session. | | 🔄 **Sessions persist** | Terminal keeps running when you close the tab. Come back on any device. | -| 🗂️ **Tabs** | Open terminals, files, chats, and tools in separate tabs. Rearrange or split your layout. | +| 🗂️ **Tabs** | Open browsers, terminals, files, chats, and tools in separate tabs. Rearrange or split your layout. | | 📂 **Workspaces** | Multiple projects, one instance. Switch without losing your place. | -| 🔍 **Search** | Find files by name, search across file contents and chat history. ⌘K to find anything. | +| 🔍 **Search** | Find files by name or contents, then jump straight to a matching line. ⌘K also searches chat history. | | 📱 **Mobile-first** | Not a desktop UI made smaller. Built for the screen in your pocket. | ## AI agent diff --git a/cptr/frontend/src/routes/+layout.svelte b/cptr/frontend/src/routes/+layout.svelte index a48b808..4700a97 100644 --- a/cptr/frontend/src/routes/+layout.svelte +++ b/cptr/frontend/src/routes/+layout.svelte @@ -351,16 +351,23 @@ }); } - // Connect system events when workspace is active + // Chat events belong to the authenticated user, not a workspace. + $effect(() => { + if (authState === 'authenticated') { + socketStore.connect(); + bindGlobalChatListener(); + } else { + socketStore.disconnect(); + } + }); + + // Filesystem events remain workspace-scoped. $effect(() => { const ws = $currentWorkspace; if (ws) { systemEvents.connect(ws.fileBrowserCwd || ws.path); - socketStore.connect(); - bindGlobalChatListener(); } else { systemEvents.disconnect(); - socketStore.disconnect(); } }); diff --git a/cptr/frontend/src/routes/+page.svelte b/cptr/frontend/src/routes/+page.svelte index 9545041..6aa03af 100644 --- a/cptr/frontend/src/routes/+page.svelte +++ b/cptr/frontend/src/routes/+page.svelte @@ -1035,6 +1035,37 @@ }} />
+ {#each homePane.tabs.filter((tab) => tab.type === 'chat') as tab (tab.id)} +
+ + updateHomeChatTab(tabId, chatId, label, homePane.id)} + onopenchat={(chatId) => openHomeChat(chatId, homePane.id)} + /> +
+ {/each} + {#each homePane.tabs.filter((tab) => tab.type === 'terminal' && tab.sessionId) as tab (tab.id)} +
+ +
+ {/each} + {#each homePane.tabs.filter((tab) => tab.type === 'browser' && tab.browserSessionId) as tab (tab.id)} +
+ updateHomeBrowserTab(tab.id, label, homePane.id)} + onOpenBrowser={(url) => openHomeBrowser(url, homePane.id)} + /> +
+ {/each} {#if homeTab?.type === 'home'}
@@ -1213,27 +1244,6 @@ {/if}
- {:else if homeTab?.type === 'chat'} - - updateHomeChatTab(tabId, chatId, label, homePane.id)} - onopenchat={(chatId) => openHomeChat(chatId, homePane.id)} - /> - {:else if homeTab?.type === 'terminal' && homeTab.sessionId} - - {:else if homeTab?.type === 'browser' && homeTab.browserSessionId} - updateHomeBrowserTab(homeTab.id, label, homePane.id)} - onOpenBrowser={(url) => openHomeBrowser(url, homePane.id)} - /> {/if}
{#if dragOverZone?.groupId === homePane.id} diff --git a/cptr/utils/skills.py b/cptr/utils/skills.py index 790b060..53d4b7f 100644 --- a/cptr/utils/skills.py +++ b/cptr/utils/skills.py @@ -423,7 +423,7 @@ def discover_skills(workspace: str) -> list[SkillMeta]: ws = Path(workspace) # 1. Workspace-level skills (project-specific, git-trackable) - if ws.is_dir(): + if workspace and ws.is_dir(): for rel_dir in WORKSPACE_SKILL_DIRS: skills_dir = ws / rel_dir for skill in _scan_skills_dir(skills_dir, source="workspace", workspace=workspace): diff --git a/pyproject.toml b/pyproject.toml index edfb6d1..fbea2a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cptr" -version = "0.9.0" +version = "0.9.1" description = "Your computer, from anywhere. Code, manage, and control your machine from the web." license = {file = "LICENSE"} readme = "README.md" diff --git a/uv.lock b/uv.lock index c878d04..95f6185 100644 --- a/uv.lock +++ b/uv.lock @@ -284,7 +284,7 @@ wheels = [ [[package]] name = "cptr" -version = "0.9.0" +version = "0.9.1" source = { editable = "." } dependencies = [ { name = "aiosqlite" },