fix(sessions): keep chat worktree actions hidden

This commit is contained in:
mattv8
2026-08-27 18:43:37 -06:00
parent a35ff1032c
commit 13ef639479
3 changed files with 38 additions and 3 deletions
@@ -26,7 +26,7 @@ import { useGlobalSessionStatus, useSessionPermissions, useSessionQuestionCount
import { useSessionMessageRecordsForExport } from '@/sync/use-sync'; import { useSessionMessageRecordsForExport } from '@/sync/use-sync';
import { useViewportStore, viewportSessionKey } from '@/sync/viewport-store'; import { useViewportStore, viewportSessionKey } from '@/sync/viewport-store';
import { DraggableSessionRow } from '../folders/sessionFolderDnd'; import { DraggableSessionRow } from '../folders/sessionFolderDnd';
import { getSessionWorktreeMenuDisabled, nodeContainsSessionId, nodeHasPinnedMembershipChange, selectQuestionBadgeSessionScopes } from './sessionNodeItemUtils'; import { canShowSessionWorktreeMenu, getSessionWorktreeMenuDisabled, nodeContainsSessionId, nodeHasPinnedMembershipChange, selectQuestionBadgeSessionScopes } from './sessionNodeItemUtils';
import type { SessionNode } from '../types'; import type { SessionNode } from '../types';
import { formatProjectLabel, formatSessionCompactDateLabel, formatSessionDateLabel, normalizePath, renderHighlightedText } from '../utils'; import { formatProjectLabel, formatSessionCompactDateLabel, formatSessionDateLabel, normalizePath, renderHighlightedText } from '../utils';
import { useProjectsStore } from '@/stores/useProjectsStore'; import { useProjectsStore } from '@/stores/useProjectsStore';
@@ -42,7 +42,7 @@ import { getSessionGoal } from '@/lib/sessionGoalMetadata';
import { sessionGoalStatusColor, sessionGoalStatusLabelKey } from '@/lib/sessionGoalPresentation'; import { sessionGoalStatusColor, sessionGoalStatusLabelKey } from '@/lib/sessionGoalPresentation';
import { getRuntimeBearerTokenSync } from '@/lib/runtime-auth'; import { getRuntimeBearerTokenSync } from '@/lib/runtime-auth';
import { getRuntimeApiBaseUrl } from '@/lib/runtime-switch'; import { getRuntimeApiBaseUrl } from '@/lib/runtime-switch';
import { getChatsRootFromDirectory, isChatDirectoryPath } from '@/lib/chatDirectories'; import { getChatsRootFromDirectory } from '@/lib/chatDirectories';
import { parseMultiRunSessionTitle } from '@/lib/multirun/title'; import { parseMultiRunSessionTitle } from '@/lib/multirun/title';
import { MultiRunFusionDialog } from '@/components/multirun/MultiRunFusionDialog'; import { MultiRunFusionDialog } from '@/components/multirun/MultiRunFusionDialog';
import { FusionIcon } from '@/components/icons/FusionIcon'; import { FusionIcon } from '@/components/icons/FusionIcon';
@@ -991,7 +991,7 @@ function SessionNodeItemComponent(props: SessionNodeItemProps): React.ReactNode
<Icon name="download" className="mr-1 h-4 w-4" /> <Icon name="download" className="mr-1 h-4 w-4" />
{t('sessions.sidebar.session.menu.exportMarkdown')} {t('sessions.sidebar.session.menu.exportMarkdown')}
</Item> </Item>
{!isSubtaskSession && !archivedBucket && !isVSCode ? (() => { {canShowSessionWorktreeMenu({ isSubtaskSession, archivedBucket: Boolean(archivedBucket), isVSCode, sessionDirectory }) ? (() => {
const isWorktreeMenuDisabled = getSessionWorktreeMenuDisabled({ const isWorktreeMenuDisabled = getSessionWorktreeMenuDisabled({
sessionDirectory, sessionDirectory,
isStreaming, isStreaming,
@@ -4,6 +4,7 @@ import { getRuntimeKey } from '@/lib/runtime-switch';
import { getPinnedSessionKey } from '@/stores/useSessionPinnedStore'; import { getPinnedSessionKey } from '@/stores/useSessionPinnedStore';
import { import {
computeNodeStructureKey, computeNodeStructureKey,
canShowSessionWorktreeMenu,
getSessionWorktreeMenuDisabled, getSessionWorktreeMenuDisabled,
nodeHasPinnedMembershipChange, nodeHasPinnedMembershipChange,
selectFolderRootNodes, selectFolderRootNodes,
@@ -192,3 +193,21 @@ describe('getSessionWorktreeMenuDisabled', () => {
})).toBe(true); })).toBe(true);
}); });
}); });
describe('canShowSessionWorktreeMenu', () => {
test('hides worktree moves for managed Chat directories', () => {
expect(canShowSessionWorktreeMenu({
isSubtaskSession: false,
archivedBucket: false,
isVSCode: false,
sessionDirectory: '/home/test/.config/openchamber/chats/2026-08-25/session-1',
})).toBe(false);
expect(canShowSessionWorktreeMenu({
isSubtaskSession: false,
archivedBucket: false,
isVSCode: false,
sessionDirectory: '/repo',
})).toBe(true);
});
});
@@ -1,6 +1,7 @@
import { getRuntimeKey } from '@/lib/runtime-switch'; import { getRuntimeKey } from '@/lib/runtime-switch';
import { matchesRankQuery } from '@/lib/search/fuzzySearch'; import { matchesRankQuery } from '@/lib/search/fuzzySearch';
import { normalizePath } from '@/lib/pathNormalization'; import { normalizePath } from '@/lib/pathNormalization';
import { isChatDirectoryPath } from '@/lib/chatDirectories';
import { resolveGlobalSessionDirectory } from '@/stores/useGlobalSessionsStore'; import { resolveGlobalSessionDirectory } from '@/stores/useGlobalSessionsStore';
import { getPinnedSessionKey } from '@/stores/useSessionPinnedStore'; import { getPinnedSessionKey } from '@/stores/useSessionPinnedStore';
import type { SessionNode } from '../types'; import type { SessionNode } from '../types';
@@ -78,6 +79,21 @@ export type QuestionBadgeSessionScope = {
sessionIDs: string[]; sessionIDs: string[];
}; };
export const canShowSessionWorktreeMenu = ({
isSubtaskSession,
archivedBucket,
isVSCode,
sessionDirectory,
}: {
isSubtaskSession: boolean;
archivedBucket: boolean;
isVSCode: boolean;
sessionDirectory: string | null;
}): boolean => !isSubtaskSession
&& !archivedBucket
&& !isVSCode
&& !isChatDirectoryPath(sessionDirectory);
export const getSessionWorktreeMenuDisabled = ({ export const getSessionWorktreeMenuDisabled = ({
sessionDirectory, sessionDirectory,
isStreaming, isStreaming,