diff --git a/README.md b/README.md index edc82630a..d8ca48654 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ > [!IMPORTANT] -> PostHog Code is pre-alpha and not production-ready. Interested? Email jonathan@posthog.com +> PostHog Code is pre-alpha and not production-ready. Interested? Join our [Discord](https://discord.gg/posthog) **[Download the latest version](https://github.com/PostHog/code/releases/latest)** diff --git a/apps/code/src/main/platform-adapters/electron-notifier.ts b/apps/code/src/main/platform-adapters/electron-notifier.ts index 744b828bd..25749f459 100644 --- a/apps/code/src/main/platform-adapters/electron-notifier.ts +++ b/apps/code/src/main/platform-adapters/electron-notifier.ts @@ -30,7 +30,6 @@ export class ElectronNotifier implements INotifier { public setUnreadIndicator(on: boolean): void { if (on) { app.dock?.setBadge("•"); - this.mainWindow.getBrowserWindow()?.flashFrame(true); } else { app.dock?.setBadge(""); this.mainWindow.getBrowserWindow()?.flashFrame(false); diff --git a/apps/code/src/renderer/components/HeaderRow.tsx b/apps/code/src/renderer/components/HeaderRow.tsx index cdfa8da1a..713003eb8 100644 --- a/apps/code/src/renderer/components/HeaderRow.tsx +++ b/apps/code/src/renderer/components/HeaderRow.tsx @@ -101,7 +101,7 @@ export function HeaderRow() { align="center" justify="end" gap="2" - pr="1" + pr="3" pl="2" style={{ height: "100%", diff --git a/apps/code/src/renderer/features/inbox/components/detail/ReportTaskLogs.tsx b/apps/code/src/renderer/features/inbox/components/detail/ReportTaskLogs.tsx index 9750abc76..1e5ec6556 100644 --- a/apps/code/src/renderer/features/inbox/components/detail/ReportTaskLogs.tsx +++ b/apps/code/src/renderer/features/inbox/components/detail/ReportTaskLogs.tsx @@ -408,8 +408,6 @@ export function ReportTaskLogs({ const row = isInteractive ? ( showRunAction ? ( // biome-ignore lint/a11y/useSemanticElements: a - - - )} - {/* Local folder picker */} + {alternativeConnectedProject && selectedProject && ( + + + GitHub is already connected on{" "} + + {alternativeConnectedProject.name} + {" "} + ({alternativeConnectedProject.organization.name}). Switch to + that project, or click{" "} + Connect GitHub below to install a + new integration on{" "} + {selectedProject.name}. + + + + + + )} + {/* GitHub integration */} = ({ align="center" gap="1" pl="3" - pr={onClose ? "1" : "3"} + pr={onClose ? "2" : "3"} className={`group relative flex-shrink-0 select-none border-r border-b-2 transition-colors ${draggable ? "cursor-grab" : "cursor-pointer"}`} style={{ borderRightColor: "var(--gray-6)", @@ -178,6 +178,7 @@ export const DraggableTab: React.FC = ({ - - {isSuspended ? ( - <> - {showRawLogs ? ( - - ) : ( + {showRawLogs ? ( + + setShowRawLogs(false)} + /> + + ) : ( + + {isSuspended ? ( + <> - )} - - - - - - - Worktree suspended - - - Worktree was removed to save disk space - + + + + + + + Worktree suspended + + + Worktree was removed to save disk space + + + {onRestoreWorktree && ( + + )} - {onRestoreWorktree && ( - - )} - + - - - ) : isInitializing ? ( - isCloud ? ( - - ) : ( - - - - ) - ) : ( - <> - - {showRawLogs ? ( - + + ) : isInitializing ? ( + isCloud ? ( + ) : ( + + + + ) + ) : ( + <> + - )} - + - {hasError ? ( - - - {errorTitle && ( - - {errorTitle} - - )} - - {errorMessage} - - - {onRetry && ( - - )} - {onNewSession && ( - + + {errorTitle && ( + + {errorTitle} + )} - - - ) : hideInput ? null : firstPendingPermission ? ( - - - - - - ) : ( - - - - - Connecting to agent... + + {errorMessage} + + {onRetry && ( + + )} + {onNewSession && ( + + )} + + + ) : hideInput ? null : firstPendingPermission ? ( + + + + - + ) : ( + - + + + Connecting to agent... + + + + + > + + } + onBeforeSubmit={onBeforeSubmit} + onSubmit={handleSubmit} + onBashCommand={onBashCommand} + onCancel={onCancelPrompt} + /> + - - )} - - )} - + )} + + )} + + )} - { + const text = window.getSelection()?.toString(); + if (text) { + navigator.clipboard.writeText(text); + } + }} > - Show raw logs - + Copy + + + setShowRawLogs(!showRawLogs)}> + {showRawLogs ? "Back to conversation" : "Show raw logs"} + ); diff --git a/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsHeader.tsx b/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsHeader.tsx index 835ae0892..f51e0f94a 100644 --- a/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsHeader.tsx +++ b/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsHeader.tsx @@ -1,4 +1,4 @@ -import { Copy, MagnifyingGlass } from "@phosphor-icons/react"; +import { Copy, MagnifyingGlass, X } from "@phosphor-icons/react"; import { Box, Flex, IconButton, Text, TextField } from "@radix-ui/themes"; import type { RefObject } from "react"; @@ -9,6 +9,7 @@ interface RawLogsHeaderProps { showSearch: boolean; onToggleSearch: () => void; onCopyAll: () => void; + onClose: () => void; onSearchChange: (query: string) => void; searchInputRef: RefObject; } @@ -20,6 +21,7 @@ export function RawLogsHeader({ showSearch, onToggleSearch, onCopyAll, + onClose, onSearchChange, searchInputRef, }: RawLogsHeaderProps) { @@ -27,13 +29,13 @@ export function RawLogsHeader({ - + Raw Logs ({filteredCount} {searchQuery && ` of ${totalCount}`} events) - + { @@ -42,16 +44,27 @@ export function RawLogsHeader({ setTimeout(() => searchInputRef.current?.focus(), 0); } }} + title="Search logs" > - + + + + - + diff --git a/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsView.tsx b/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsView.tsx index 09a79086b..77325cee6 100644 --- a/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsView.tsx +++ b/apps/code/src/renderer/features/sessions/components/raw-logs/RawLogsView.tsx @@ -13,6 +13,7 @@ import { RawLogsHeader } from "./RawLogsHeader"; interface RawLogsViewProps { events: AcpMessage[]; + onClose: () => void; } interface FilteredEvent { @@ -20,7 +21,7 @@ interface FilteredEvent { originalIndex: number; } -export function RawLogsView({ events }: RawLogsViewProps) { +export function RawLogsView({ events, onClose }: RawLogsViewProps) { const searchInputRef = useRef(null); const searchQuery = useSearchQuery(); const showSearch = useShowSearch(); @@ -71,6 +72,7 @@ export function RawLogsView({ events }: RawLogsViewProps) { showSearch={showSearch} onToggleSearch={toggleSearch} onCopyAll={copyAllLogs} + onClose={onClose} onSearchChange={setSearchQuery} searchInputRef={searchInputRef} /> diff --git a/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx b/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx index 572852549..3429cdeda 100644 --- a/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx +++ b/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx @@ -63,6 +63,7 @@ function TaskHoverToolbar({ e.stopPropagation(); onTogglePin(); }} + onDoubleClick={(e) => e.stopPropagation()} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); @@ -86,6 +87,7 @@ function TaskHoverToolbar({ e.stopPropagation(); onArchive(); }} + onDoubleClick={(e) => e.stopPropagation()} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); diff --git a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts index 162356b88..1c5c5f242 100644 --- a/apps/code/src/renderer/features/terminal/services/TerminalManager.ts +++ b/apps/code/src/renderer/features/terminal/services/TerminalManager.ts @@ -86,7 +86,7 @@ function getTerminalTheme(isDarkMode: boolean) { foreground: "#0d0d0d", cursor: "#f54d00", cursorAccent: "#f2f3ee", - selectionBackground: "rgba(245, 77, 0, 0.2)", + selectionBackground: "rgba(245, 77, 0, 0.95)", selectionForeground: "#0d0d0d", }; } diff --git a/apps/code/src/renderer/features/tour/components/TourOverlay.tsx b/apps/code/src/renderer/features/tour/components/TourOverlay.tsx index 4bce14c95..e9eee97c0 100644 --- a/apps/code/src/renderer/features/tour/components/TourOverlay.tsx +++ b/apps/code/src/renderer/features/tour/components/TourOverlay.tsx @@ -112,13 +112,17 @@ export function TourOverlay() { const el = document.querySelector(selector); if (el) { + if (el.getAttribute("data-tour-ready") === "true") { + tryAdvance(); + return; + } + observer.observe(el, { subtree: true, childList: true, characterData: true, attributes: true, }); - resetTimer(); } return () => { @@ -132,6 +136,13 @@ export function TourOverlay() { const overlayBlocked = settingsOpen || commandMenuOpen; const isActive = !!(tour && step && targetRect && !overlayBlocked); + const handleNext = () => { + if (activeTourId && step) { + advancedRef.current = true; + advance(activeTourId, step.id); + } + }; + return ( <> @@ -141,6 +152,7 @@ export function TourOverlay() { stepNumber={activeStepIndex + 1} totalSteps={tour.steps.length} onDismiss={dismiss} + onNext={handleNext} targetRect={targetRect} /> )} diff --git a/apps/code/src/renderer/features/tour/components/TourTooltip.tsx b/apps/code/src/renderer/features/tour/components/TourTooltip.tsx index 12f6a74fb..334168664 100644 --- a/apps/code/src/renderer/features/tour/components/TourTooltip.tsx +++ b/apps/code/src/renderer/features/tour/components/TourTooltip.tsx @@ -11,6 +11,7 @@ interface TourTooltipProps { stepNumber: number; totalSteps: number; onDismiss: () => void; + onNext: () => void; targetRect: DOMRect; } @@ -150,6 +151,7 @@ export function TourTooltip({ stepNumber, totalSteps, onDismiss, + onNext, targetRect, }: TourTooltipProps) { const isDarkMode = useThemeStore((s) => s.isDarkMode); @@ -259,15 +261,20 @@ export function TourTooltip({ {stepNumber}/{totalSteps} - + + + + diff --git a/apps/code/src/renderer/features/workspace/hooks/useBranchMismatchDialog.test.ts b/apps/code/src/renderer/features/workspace/hooks/useBranchMismatchDialog.test.ts index ebcbc0a9f..621f666af 100644 --- a/apps/code/src/renderer/features/workspace/hooks/useBranchMismatchDialog.test.ts +++ b/apps/code/src/renderer/features/workspace/hooks/useBranchMismatchDialog.test.ts @@ -109,12 +109,12 @@ describe("useBranchMismatchDialog", () => { const { result } = renderDialog({ shouldWarn: true }); const clearEditor = vi.fn(); - let allowed: boolean; + let allowed = true; act(() => { allowed = result.current.handleBeforeSubmit("hello", clearEditor); }); - expect(allowed!).toBe(false); + expect(allowed).toBe(false); expect(result.current.dialogProps?.open).toBe(true); expect(clearEditor).not.toHaveBeenCalled(); expect(mockTrack).toHaveBeenCalledWith( diff --git a/packages/agent/src/adapters/claude/hooks.ts b/packages/agent/src/adapters/claude/hooks.ts index d896fb9d6..a9a3073f1 100644 --- a/packages/agent/src/adapters/claude/hooks.ts +++ b/packages/agent/src/adapters/claude/hooks.ts @@ -127,11 +127,10 @@ export type OnModeChange = (mode: CodeExecutionMode) => Promise; interface CreatePostToolUseHookParams { onModeChange?: OnModeChange; - logger?: Logger; } export const createPostToolUseHook = - ({ onModeChange, logger }: CreatePostToolUseHookParams): HookCallback => + ({ onModeChange }: CreatePostToolUseHookParams): HookCallback => async ( input: HookInput, toolUseID: string | undefined, diff --git a/packages/agent/src/adapters/claude/session/options.ts b/packages/agent/src/adapters/claude/session/options.ts index 56ce6a3eb..88a245556 100644 --- a/packages/agent/src/adapters/claude/session/options.ts +++ b/packages/agent/src/adapters/claude/session/options.ts @@ -119,7 +119,7 @@ function buildHooks( enrichedReadCache: EnrichedReadCache | undefined, registeredAgents: ReadonlySet, ): Options["hooks"] { - const postToolUseHooks = [createPostToolUseHook({ onModeChange, logger })]; + const postToolUseHooks = [createPostToolUseHook({ onModeChange })]; if (enrichmentDeps && enrichedReadCache) { postToolUseHooks.push( createReadEnrichmentHook(enrichmentDeps, enrichedReadCache),