diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index b4cf86c..5f0c5ae 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -62,6 +62,7 @@ jobs: id: release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} VERSION: ${{ steps.pkg.outputs.version }} run: | set -euo pipefail @@ -202,6 +203,7 @@ jobs: - name: Attach GitHub release artifacts env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} VERSION: ${{ needs.preflight.outputs.version }} run: | set -euo pipefail diff --git a/CHANGELOG.md b/CHANGELOG.md index 55e9735..0b40e44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ 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.8.2] - 2026-07-07 + +### Added + +- 🌿 **Fork chats from any response.** Start a fresh copy of a conversation from the current response or with `/fork`, so you can try a different direction without changing the original chat. +- ✨ **Easier skill access.** Type `/` to find skills alongside chat commands, and admins can control skill behavior from a new Skills page. + +### Changed + +- 🧠 **Smarter skill upkeep.** Computer can help keep managed skills up to date after real chats, while admins can turn skill features on or off. +- ⚙️ **Tidier settings.** About, sharing, update, license, and PWA reset controls now live in General, with Skills under Admin. + +### Fixed + +- 💬 **Clearer chat controls.** Message actions now show helpful tooltips, and commands that need an existing chat stay hidden until they can be used. +- 📦 **More dependable release downloads.** Release runs now attach download files to the right repository more reliably. + ## [0.8.1] - 2026-07-06 ### Added diff --git a/README.md b/README.md index b7bbcd0..48d2294 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ See more at [cptr.sh](https://cptr.sh/) -Open WebUI Computer (`cptr`) runs on your machine and serves your whole computer (files, terminal, editor, git) to any browser. 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, 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, or plug in a coding agent you already subscribe to and skip the key entirely. Terminal multiplexer, parallel AI agents, full workstation, one tool, your computer, any device. +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. ## Install @@ -55,23 +55,27 @@ Most tunnels forward to `localhost`, so the default `cptr run` works. If your tu Or skip networking entirely and connect a [messaging bot](#messaging-bots) instead. -## What you get +## The Whole Machine + +Open WebUI Computer is the real workstation surface: files, shell, git state, workspaces, chats, tools, and sessions stay together wherever you open it. | | | |---|---| -| 📁 **File browser** | Navigate, create, rename, upload, drag and drop. Icons by type, sizes at a glance. | -| ⌨️ **Terminal** | Full shell in the browser. Run your tools, your scripts, or your favourite coding agent. | -| 🔀 **Git** | Stage, commit, diff, branch, push. Visual changes view. No command line required. | +| 📁 **Real files** | Navigate, create, rename, upload, drag and drop. Icons by type, sizes at a glance. | | ✏️ **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. | +| 🔄 **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. | | 📂 **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. | | 📱 **Mobile-first** | Not a desktop UI made smaller. Built for the screen in your pocket. | -| 🔄 **Sessions persist** | Terminal keeps running when you close the tab. Come back on any device. | ## AI agent -Bring your own API key (OpenAI, Anthropic, Ollama, or any OpenAI-compatible endpoint), or connect a coding agent you already subscribe to. +AI that works where your work actually lives. + +Bring your own API key (OpenAI, Anthropic, Ollama, or any OpenAI-compatible endpoint), or connect a coding agent you already subscribe to. It can read the workspace, edit files, run commands, browse the web, use tools, automate recurring work, and spin up parallel sub-agents on the same machine. | | | |---|---| @@ -95,7 +99,7 @@ Bring your own API key (OpenAI, Anthropic, Ollama, or any OpenAI-compatible endp ## Coding agents -Connect a coding agent as a native backend and use the subscription you already pay for. No separate API key needed. +Use the subscriptions you already pay for as native backends on your own machine. No separate API key needed. **Codex** · **Claude Code** · **Cursor** · **Grok** · **OpenCode** · **Cline** @@ -105,15 +109,15 @@ Prefer to run agents yourself? Any terminal agent (Gemini CLI, Kilo Code, Pi, an ## Messaging bots -Connect the AI to your chat apps. Full tool access, streaming responses, conversations synced back to the web UI. +Message your computer from wherever you are. Connect the AI to your chat apps with full tool access, streaming responses, and conversations synced back to the web UI. **Telegram** · **Discord** · **Slack** · **WhatsApp** · **Signal** -Message your computer from wherever you are. Ask it to check a build, push a fix, or explain a file. Switch workspaces with `/workspace`, start fresh with `/new`. +Ask it to check a build, push a fix, or explain a file. Switch workspaces with `/workspace`, start fresh with `/new`. ## Gateway API -Open WebUI Computer exposes an OpenAI-compatible API (`/v1/chat/completions`). Any client that speaks OpenAI, including [Open WebUI](https://github.com/open-webui/open-webui), can use each Open WebUI Computer workspace as a model with full agent capabilities: file access, terminal, web search, tools. +Turn each workspace into an OpenAI-compatible agent model with real machine access. Open WebUI Computer exposes `/v1/chat/completions`, so any client that speaks OpenAI, including [Open WebUI](https://github.com/open-webui/open-webui), can use a workspace with full agent capabilities: file access, terminal, web search, tools. ## More @@ -127,7 +131,7 @@ Open WebUI Computer exposes an OpenAI-compatible API (`/v1/chat/completions`). A | 📋 **Audit logging** | Structured audit trail of all API mutations with automatic redaction of sensitive data. | | 🪵 **Diagnostic logging** | Configurable structured logs (text or JSON) with optional upstream request capture. | | ⌨️ **Keyboard shortcuts** | Customisable keybindings with a settings panel. | -| 🌍 **10 languages** | EN, DE, ES, FR, JA, KO, PT-BR, RU, ZH-CN, ZH-TW. | +| 🌍 **10 languages** | English, Deutsch, Español, Français, Português (Brasil), Русский, 日本語, 한국어, 简体中文, 繁體中文. | | 🔐 **Auth** | Username/password with JWT sessions. Signup toggle for admins. | ## Design principles diff --git a/cptr/frontend/src/lib/apis/chat.ts b/cptr/frontend/src/lib/apis/chat.ts index 9277ba1..6c0d6a8 100644 --- a/cptr/frontend/src/lib/apis/chat.ts +++ b/cptr/frontend/src/lib/apis/chat.ts @@ -97,6 +97,12 @@ export const getChat = (chatId: string, modelId?: string) => { export const deleteChat = (chatId: string) => fetchJSON<{ ok: boolean }>(`/api/chats/${chatId}`, { method: 'DELETE' }); +export const forkChat = (chatId: string, messageId?: string | null) => + fetchJSON<{ ok: boolean; chat_id: string }>( + `/api/chats/${chatId}/fork`, + jsonBody({ message_id: messageId ?? null }) + ); + // ── Mutations ─────────────────────────────────────────────── export const sendMessage = ( diff --git a/cptr/frontend/src/lib/apis/skills.ts b/cptr/frontend/src/lib/apis/skills.ts index 4bdc386..d040325 100644 --- a/cptr/frontend/src/lib/apis/skills.ts +++ b/cptr/frontend/src/lib/apis/skills.ts @@ -11,6 +11,14 @@ export interface SkillInfo { license?: string; compatibility?: string; managed?: boolean; + created_by?: string | null; + created_from?: string | null; + view_count?: number; + use_count?: number; + update_count?: number; + last_viewed_at?: string | null; + last_used_at?: string | null; + last_updated_at?: string | null; } export const getSkills = (workspace: string) => diff --git a/cptr/frontend/src/lib/components/Admin/Skills.svelte b/cptr/frontend/src/lib/components/Admin/Skills.svelte new file mode 100644 index 0000000..3e301a7 --- /dev/null +++ b/cptr/frontend/src/lib/components/Admin/Skills.svelte @@ -0,0 +1,122 @@ + + +
+ {#if loading} +
+ {:else} +
+

Skills

+ +

Behavior

+
+ + + {#if enabled} + + + + {/if} +
+ + {#if enabled} +

Limits

+
+
+ + +
+
+ {/if} +
+ +
+ +
+ {/if} +
diff --git a/cptr/frontend/src/lib/components/FileBrowser.svelte b/cptr/frontend/src/lib/components/FileBrowser.svelte index d9c2a72..8b6a69a 100644 --- a/cptr/frontend/src/lib/components/FileBrowser.svelte +++ b/cptr/frontend/src/lib/components/FileBrowser.svelte @@ -882,6 +882,11 @@ closeMenu(); } + function copyPath(entry: TreeEntry) { + navigator.clipboard.writeText(entry.path); + closeMenu(); + } + async function confirmRename(entryPath: string) { const oldName = entryPath.split('/').pop() ?? ''; if (!renameValue.trim() || renameValue === oldName) { @@ -1347,6 +1352,7 @@ { label: '', divider: true, onclick: () => {} } ] : []), + { label: $t('files.copyPath'), icon: 'copy', onclick: () => copyPath(contextMenu!.entry) }, { label: $t('files.rename'), icon: 'pencil', onclick: () => startRename(contextMenu!.entry) }, ...(contextMenu.entry.type !== 'directory' ? [ diff --git a/cptr/frontend/src/lib/components/Icon.svelte b/cptr/frontend/src/lib/components/Icon.svelte index 5054444..72f45a3 100644 --- a/cptr/frontend/src/lib/components/Icon.svelte +++ b/cptr/frontend/src/lib/components/Icon.svelte @@ -62,6 +62,12 @@ /> + {:else if name === 'chat-fork'} + + + + + {:else if name === 'chat-bubble'} - import { t } from '$lib/i18n'; - import { appVersion, showChangelog, updateAvailable, latestVersion } from '$lib/stores'; - - const REPO_URL = 'https://github.com/open-webui/computer'; - const SHARE_TEXT = 'Check out Computer. Your computer, from anywhere.'; - - const shareLinks = [ - { - label: 'X', - href: `https://x.com/intent/tweet?text=${encodeURIComponent(SHARE_TEXT)}&url=${encodeURIComponent(REPO_URL)}` - }, - { - label: 'Reddit', - href: `https://reddit.com/submit?url=${encodeURIComponent(REPO_URL)}&title=${encodeURIComponent(SHARE_TEXT)}` - }, - { - label: 'LinkedIn', - href: `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(REPO_URL)}` - } - ]; - - let copied = $state(false); - - function copyLink() { - navigator.clipboard.writeText(REPO_URL); - copied = true; - setTimeout(() => (copied = false), 2000); - } - - -

- {$t('about.title')} -

- -
-
- Computer - {#if $appVersion} - - {/if} - {#if $updateAvailable} - · - {$t('about.updateAvailable', { version: $latestVersion })} - {/if} -
- -

{$t('app.tagline')}

- -

- {$t('about.license')} -

-

- {$t('about.licenseName')} - -
- {$t('about.copyright')} -

-
- -
- {$t('about.share')} - {#each shareLinks as link, i} - {#if i > 0} - · - {/if} - {link.label} - {/each} - · - -
- -

- {$t('about.createdBy')} -

diff --git a/cptr/frontend/src/lib/components/Settings/General.svelte b/cptr/frontend/src/lib/components/Settings/General.svelte index ac7dc2f..d51c1b1 100644 --- a/cptr/frontend/src/lib/components/Settings/General.svelte +++ b/cptr/frontend/src/lib/components/Settings/General.svelte @@ -1,15 +1,130 @@

{$t('general.title')}

+
+
+ Computer + {#if $appVersion} + + {/if} + {#if $updateAvailable} + · + {$t('about.updateAvailable', { version: $latestVersion })} + {/if} +
+ +

{$t('app.tagline')}

+ +
+ {$t('about.share')} + {#each shareLinks as link, i} + {#if i > 0} + · + {/if} + {link.label} + {/each} + · + +
+
+

{$t('general.language')}