From da87d649d62d6bdb5548218c09b44b54a84943a6 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sat, 28 Mar 2026 17:05:59 +0000 Subject: [PATCH 01/13] Persist project selection on new task screen --- .../features/settings/stores/settingsStore.ts | 12 ++++++++ .../task-detail/components/TaskInput.tsx | 29 +++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/apps/code/src/renderer/features/settings/stores/settingsStore.ts b/apps/code/src/renderer/features/settings/stores/settingsStore.ts index 12162f0cf..984a3b5bc 100644 --- a/apps/code/src/renderer/features/settings/stores/settingsStore.ts +++ b/apps/code/src/renderer/features/settings/stores/settingsStore.ts @@ -26,6 +26,8 @@ interface SettingsStore { lastUsedAdapter: AgentAdapter; lastUsedModel: string | null; lastUsedEnvironments: Record; + lastUsedDirectory: string; + lastUsedCloudRepository: string | null; desktopNotifications: boolean; dockBadgeNotifications: boolean; dockBounceNotifications: boolean; @@ -62,6 +64,8 @@ interface SettingsStore { environmentId: string | null, ) => void; getLastUsedEnvironment: (repoPath: string) => string | null; + setLastUsedDirectory: (directory: string) => void; + setLastUsedCloudRepository: (repository: string | null) => void; setDesktopNotifications: (enabled: boolean) => void; setDockBadgeNotifications: (enabled: boolean) => void; setDockBounceNotifications: (enabled: boolean) => void; @@ -89,6 +93,8 @@ export const useSettingsStore = create()( lastUsedAdapter: "claude", lastUsedModel: null, lastUsedEnvironments: {}, + lastUsedDirectory: "", + lastUsedCloudRepository: null, desktopNotifications: true, dockBadgeNotifications: true, dockBounceNotifications: false, @@ -155,6 +161,10 @@ export const useSettingsStore = create()( }), getLastUsedEnvironment: (repoPath) => get().lastUsedEnvironments[repoPath] ?? null, + setLastUsedDirectory: (directory) => + set({ lastUsedDirectory: directory }), + setLastUsedCloudRepository: (repository) => + set({ lastUsedCloudRepository: repository }), setDesktopNotifications: (enabled) => set({ desktopNotifications: enabled }), setDockBadgeNotifications: (enabled) => @@ -191,6 +201,8 @@ export const useSettingsStore = create()( lastUsedAdapter: state.lastUsedAdapter, lastUsedModel: state.lastUsedModel, lastUsedEnvironments: state.lastUsedEnvironments, + lastUsedDirectory: state.lastUsedDirectory, + lastUsedCloudRepository: state.lastUsedCloudRepository, desktopNotifications: state.desktopNotifications, dockBadgeNotifications: state.dockBadgeNotifications, dockBounceNotifications: state.dockBounceNotifications, diff --git a/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx b/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx index dc78d1939..52802c660 100644 --- a/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx +++ b/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx @@ -49,6 +49,10 @@ export function TaskInput() { getLastUsedEnvironment, defaultInitialTaskMode, lastUsedInitialTaskMode, + lastUsedDirectory: persistedDirectory, + setLastUsedDirectory: persistDirectory, + lastUsedCloudRepository: persistedCloudRepository, + setLastUsedCloudRepository: persistCloudRepository, } = useSettingsStore(); const editorRef = useRef(null); @@ -62,7 +66,15 @@ export function TaskInput() { string | null >(null); - const [selectedDirectory, setSelectedDirectory] = useState(""); + const [selectedDirectory, setSelectedDirectoryRaw] = + useState(persistedDirectory); + const setSelectedDirectory = useCallback( + (dir: string) => { + setSelectedDirectoryRaw(dir); + persistDirectory(dir); + }, + [persistDirectory], + ); const workspaceMode = lastUsedWorkspaceMode || "local"; const adapter = lastUsedAdapter; @@ -70,7 +82,7 @@ export function TaskInput() { if (!selectedDirectory && mostRecentRepo?.path) { setSelectedDirectory(mostRecentRepo.path); } - }, [mostRecentRepo?.path, selectedDirectory]); + }, [mostRecentRepo?.path, selectedDirectory, setSelectedDirectory]); const setWorkspaceMode = (mode: WorkspaceMode) => { setLastUsedWorkspaceMode(mode); @@ -83,8 +95,15 @@ export function TaskInput() { const { githubIntegration, repositories, isLoadingRepos } = useRepositoryIntegration(); - const [selectedRepository, setSelectedRepository] = useState( - null, + const [selectedRepository, setSelectedRepositoryRaw] = useState< + string | null + >(persistedCloudRepository); + const setSelectedRepository = useCallback( + (repo: string | null) => { + setSelectedRepositoryRaw(repo); + persistCloudRepository(repo); + }, + [persistCloudRepository], ); const { currentBranch, branchLoading, defaultBranch } = useGitQueries(selectedDirectory); @@ -112,7 +131,7 @@ export function TaskInput() { setSelectedDirectory(folder.path); } } - }, [view.folderId, folders]); + }, [view.folderId, folders, setSelectedDirectory]); const effectiveRepoPath = workspaceMode === "cloud" ? selectedRepository : selectedDirectory; From e31bab596868cc145981f652be28eff3309a37e3 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sat, 28 Mar 2026 17:06:25 +0000 Subject: [PATCH 02/13] Lower window minWidth to 480px for split-screen use --- apps/code/src/main/window.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/src/main/window.ts b/apps/code/src/main/window.ts index 6bdd895bc..30b8903f4 100644 --- a/apps/code/src/main/window.ts +++ b/apps/code/src/main/window.ts @@ -123,7 +123,7 @@ export function createWindow(): void { ...(savedState.y !== undefined && { y: savedState.y }), width: savedState.width, height: savedState.height, - minWidth: 1200, + minWidth: 480, minHeight: 600, backgroundColor: "#0a0a0a", ...platformWindowConfig, From 3295be1eda212ab96696de6ce7666d81ed19f83b Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sat, 28 Mar 2026 17:12:34 +0000 Subject: [PATCH 03/13] Fix Enter key blocked after dismissing empty suggestion popup --- .../features/message-editor/tiptap/CommandMention.ts | 5 +++++ .../renderer/features/message-editor/tiptap/FileMention.ts | 5 +++++ .../features/message-editor/tiptap/SuggestionList.tsx | 7 +++++-- .../features/message-editor/tiptap/useTiptapEditor.ts | 7 ++++--- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/code/src/renderer/features/message-editor/tiptap/CommandMention.ts b/apps/code/src/renderer/features/message-editor/tiptap/CommandMention.ts index 1c68e308c..dccdbc3d6 100644 --- a/apps/code/src/renderer/features/message-editor/tiptap/CommandMention.ts +++ b/apps/code/src/renderer/features/message-editor/tiptap/CommandMention.ts @@ -23,9 +23,11 @@ function createSuggestion( render: () => { let component: ReactRenderer | null = null; let popup: TippyInstance | null = null; + let dismissed = false; return { onStart: (props) => { + dismissed = false; component = new ReactRenderer(SuggestionList, { props: { items: props.items, @@ -67,9 +69,12 @@ function createSuggestion( if (props.event.key === "Escape") { props.event.stopPropagation(); popup?.hide(); + dismissed = true; return true; } + if (dismissed) return false; + return component?.ref?.onKeyDown(props) ?? false; }, diff --git a/apps/code/src/renderer/features/message-editor/tiptap/FileMention.ts b/apps/code/src/renderer/features/message-editor/tiptap/FileMention.ts index 3ba26bed4..2eaece93d 100644 --- a/apps/code/src/renderer/features/message-editor/tiptap/FileMention.ts +++ b/apps/code/src/renderer/features/message-editor/tiptap/FileMention.ts @@ -27,9 +27,11 @@ function createSuggestion( render: () => { let component: ReactRenderer | null = null; let popup: TippyInstance | null = null; + let dismissed = false; return { onStart: (props) => { + dismissed = false; const items = props.items.length > 0 ? props.items : lastItems; component = new ReactRenderer(SuggestionList, { props: { @@ -73,9 +75,12 @@ function createSuggestion( if (props.event.key === "Escape") { props.event.stopPropagation(); popup?.hide(); + dismissed = true; return true; } + if (dismissed) return false; + return component?.ref?.onKeyDown(props) ?? false; }, diff --git a/apps/code/src/renderer/features/message-editor/tiptap/SuggestionList.tsx b/apps/code/src/renderer/features/message-editor/tiptap/SuggestionList.tsx index aed1a863e..3d4622f84 100644 --- a/apps/code/src/renderer/features/message-editor/tiptap/SuggestionList.tsx +++ b/apps/code/src/renderer/features/message-editor/tiptap/SuggestionList.tsx @@ -57,8 +57,11 @@ export const SuggestionList = forwardRef< return true; } if (event.key === "Enter" || event.key === "Tab") { - if (items[selectedIndex]) command(items[selectedIndex]); - return true; + if (items[selectedIndex]) { + command(items[selectedIndex]); + return true; + } + return false; } return false; }, diff --git a/apps/code/src/renderer/features/message-editor/tiptap/useTiptapEditor.ts b/apps/code/src/renderer/features/message-editor/tiptap/useTiptapEditor.ts index 7a8a7d47a..26e07784e 100644 --- a/apps/code/src/renderer/features/message-editor/tiptap/useTiptapEditor.ts +++ b/apps/code/src/renderer/features/message-editor/tiptap/useTiptapEditor.ts @@ -187,9 +187,10 @@ export function useTiptapEditor(options: UseTiptapEditorOptions) { if (isSubmitKey) { if (!view.editable || submitDisabledRef.current) return false; - const suggestionPopup = - document.querySelector("[data-tippy-root]"); - if (suggestionPopup) return false; + const visibleSuggestion = document.querySelector( + "[data-tippy-root] .tippy-box:not([data-state='hidden'])", + ); + if (visibleSuggestion) return false; event.preventDefault(); historyActions.reset(); submitRef.current(); From 0923ffbb34b4dee36ecfcd62ad8488fe827ce637 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sat, 28 Mar 2026 17:18:19 +0000 Subject: [PATCH 04/13] Style hyperlinks in Tiptap editor --- apps/code/src/renderer/styles/globals.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/code/src/renderer/styles/globals.css b/apps/code/src/renderer/styles/globals.css index 47eb24bef..ae2b62c0f 100644 --- a/apps/code/src/renderer/styles/globals.css +++ b/apps/code/src/renderer/styles/globals.css @@ -531,6 +531,16 @@ body { outline: none; } +.ProseMirror a { + color: var(--accent-11); + text-decoration: underline; + cursor: pointer; +} + +.ProseMirror a:hover { + color: var(--accent-12); +} + .CollapsibleContent { overflow: hidden; } From 7ecb7c37afce3c2ed5f7246f13b2a97e0689304a Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sat, 28 Mar 2026 17:26:46 +0000 Subject: [PATCH 05/13] Polish message editor padding, separators and scrollbar --- .../components/AttachmentsBar.tsx | 6 +++++- .../components/MessageEditor.tsx | 12 ++++++++---- .../components/message-editor.css | 18 ++++++++++++++++++ .../message-editor/tiptap/useTiptapEditor.ts | 2 +- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apps/code/src/renderer/features/message-editor/components/AttachmentsBar.tsx b/apps/code/src/renderer/features/message-editor/components/AttachmentsBar.tsx index 15423d001..f40b64abf 100644 --- a/apps/code/src/renderer/features/message-editor/components/AttachmentsBar.tsx +++ b/apps/code/src/renderer/features/message-editor/components/AttachmentsBar.tsx @@ -153,7 +153,11 @@ export function AttachmentsBar({ attachments, onRemove }: AttachmentsBarProps) { if (attachments.length === 0) return null; return ( - + {attachments.map((att) => isImageFile(att.label) ? ( @@ -270,19 +270,23 @@ export const MessageEditor = forwardRef( direction="column" gap="2" onClick={handleContainerClick} - className={`rounded-md p-2 ${isBashMode ? "ring-1 ring-blue-9" : ""}`} + className={`rounded-md py-2 pr-0 pl-1.5 ${isBashMode ? "ring-1 ring-blue-9" : ""}`} style={{ cursor: "text" }} >
- + Date: Sat, 28 Mar 2026 17:38:10 +0000 Subject: [PATCH 06/13] Show parent directory in file mention chips --- .../suggestions/getSuggestions.ts | 19 ++++++++++++------- .../message-editor/tiptap/MentionChipView.tsx | 9 ++++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/code/src/renderer/features/message-editor/suggestions/getSuggestions.ts b/apps/code/src/renderer/features/message-editor/suggestions/getSuggestions.ts index 032a04781..30a6c51b8 100644 --- a/apps/code/src/renderer/features/message-editor/suggestions/getSuggestions.ts +++ b/apps/code/src/renderer/features/message-editor/suggestions/getSuggestions.ts @@ -52,13 +52,18 @@ export async function getFileSuggestions( const { files, fzf } = await fetchRepoFiles(repoPath); const matched = searchFiles(fzf, files, query); - return matched.map((file) => ({ - id: file.path, - label: file.name, - description: file.dir || undefined, - filename: file.name, - path: file.path, - })); + return matched.map((file) => { + const parentDir = file.dir ? file.dir.split("/").pop() : undefined; + const label = parentDir ? `${parentDir}/${file.name}` : file.name; + + return { + id: file.path, + label, + description: file.dir || undefined, + filename: file.name, + path: file.path, + }; + }); } export function getCommandSuggestions( diff --git a/apps/code/src/renderer/features/message-editor/tiptap/MentionChipView.tsx b/apps/code/src/renderer/features/message-editor/tiptap/MentionChipView.tsx index 0a459455d..ae1733913 100644 --- a/apps/code/src/renderer/features/message-editor/tiptap/MentionChipView.tsx +++ b/apps/code/src/renderer/features/message-editor/tiptap/MentionChipView.tsx @@ -35,8 +35,9 @@ function DefaultChip({ const isCommand = type === "command"; const prefix = isCommand ? "/" : "@"; + const isFile = type === "file"; - return ( + const chip = ( ); + + if (isFile) { + return {chip}; + } + + return chip; } function PastedTextChip({ From f5964c146a6686dedadda74684a71fe28f75948d Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sat, 28 Mar 2026 17:39:54 +0000 Subject: [PATCH 07/13] Rename bypass permissions to auto-accept permissions --- .../components/sections/ClaudeCodeSettings.tsx | 14 +++++++------- .../claude/permissions/permission-options.ts | 2 +- packages/agent/src/execution-mode.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx index 11000245b..772d7bd42 100644 --- a/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx @@ -178,8 +178,8 @@ export function ClaudeCodeSettings() { - Bypass Permissions mode is enabled. All permission rules are - ignored. + Auto-accept is enabled. All permission requests are automatically + approved. )} @@ -210,14 +210,14 @@ export function ClaudeCodeSettings() { - Enable Bypass Permissions mode + Enable auto-accept permissions - In Bypass Permissions mode, PostHog Code will not ask for your + With auto-accept enabled, PostHog Code will not ask for your approval before running potentially dangerous commands. @@ -227,7 +227,7 @@ export function ClaudeCodeSettings() { By proceeding, you accept all responsibility for actions taken - while running in Bypass Permissions mode. + while auto-accept is enabled. diff --git a/packages/agent/src/adapters/claude/permissions/permission-options.ts b/packages/agent/src/adapters/claude/permissions/permission-options.ts index 551be7c31..aed7a27cf 100644 --- a/packages/agent/src/adapters/claude/permissions/permission-options.ts +++ b/packages/agent/src/adapters/claude/permissions/permission-options.ts @@ -100,7 +100,7 @@ export function buildExitPlanModePermissionOptions(): PermissionOption[] { if (ALLOW_BYPASS) { options.push({ kind: "allow_always", - name: "Yes, bypass all permissions", + name: "Yes, auto-accept all permissions", optionId: "bypassPermissions", }); } diff --git a/packages/agent/src/execution-mode.ts b/packages/agent/src/execution-mode.ts index 59c7b4cd8..e2468f54a 100644 --- a/packages/agent/src/execution-mode.ts +++ b/packages/agent/src/execution-mode.ts @@ -35,8 +35,8 @@ const availableModes: ModeInfo[] = [ if (ALLOW_BYPASS) { availableModes.push({ id: "bypassPermissions", - name: "Bypass Permissions", - description: "Bypass all permission checks", + name: "Auto-accept Permissions", + description: "Auto-accept all permission requests", }); } From ebe338bc0681fb1d948b8d4ab21eb3c094719351 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sat, 28 Mar 2026 18:31:38 +0000 Subject: [PATCH 08/13] Add shift+tab hint to auto-accept callout --- .../settings/components/sections/ClaudeCodeSettings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx index 772d7bd42..c4839a738 100644 --- a/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/ClaudeCodeSettings.tsx @@ -195,8 +195,8 @@ export function ClaudeCodeSettings() { - Auto-accept is enabled. All permission requests are automatically - approved. + Auto-accept is enabled. Use shift+tab to cycle to this mode in each + session. )} From 83ad54a9d40c2c1add14fafdffa89ac528d1f370 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Sun, 29 Mar 2026 10:18:22 +0100 Subject: [PATCH 09/13] Open active file in external app instead of repo directory --- .../components/ExternalAppsOpener.tsx | 16 +++++++-- .../task-detail/components/TaskDetail.tsx | 33 ++++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/apps/code/src/renderer/features/task-detail/components/ExternalAppsOpener.tsx b/apps/code/src/renderer/features/task-detail/components/ExternalAppsOpener.tsx index 11055e041..9725ae35d 100644 --- a/apps/code/src/renderer/features/task-detail/components/ExternalAppsOpener.tsx +++ b/apps/code/src/renderer/features/task-detail/components/ExternalAppsOpener.tsx @@ -4,7 +4,7 @@ import { ChevronDownIcon } from "@radix-ui/react-icons"; import { Button, DropdownMenu, Flex, Text } from "@radix-ui/themes"; import { SHORTCUTS } from "@renderer/constants/keyboard-shortcuts"; import { handleExternalAppAction } from "@utils/handleExternalAppAction"; -import { useCallback } from "react"; +import { useCallback, useState } from "react"; import { useHotkeys } from "react-hotkeys-hook"; const THUMBNAIL_ICON_SIZE = 20; @@ -74,6 +74,8 @@ export function ExternalAppsOpener({ [handleCopyPath], ); + const [dropdownOpen, setDropdownOpen] = useState(false); + if (!targetPath) { return null; } @@ -81,7 +83,17 @@ export function ExternalAppsOpener({ const isReady = !isLoading && detectedApps.length > 0; return ( - + + {dropdownOpen && ( +
+ )}