chat: rename claude_sessions → general_chat_sessions; drop dead chat_sessions

The default /chat working directory is used by both the Claude and OpenCode harnesses
now, so its Claude-specific name was misleading.

- Rename the dir + accessors: getClaudeSessionsCwd → getGeneralChatSessionsCwd,
  ensureClaudeSessionsCwd → ensureGeneralChatSessionsCwd, path segment claude_sessions
  → general_chat_sessions (data-path on disk + code + UI labels/comments). No history
  migration — the old Claude transcript slug is orphaned (intentionally).

- Remove the vestigial chat_sessions dir (leftover from the retired session store):
  it only ever held empty claude/archived/ dirs, recreated by a signin hook. Drop that
  hook (+ its dead imports) and the 4 unused data-path accessors (getUserSessionsDir,
  getClaudeDir, getSessionDir, getArchivedSessionDir), and delete the dir.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 11:50:48 +00:00
co-authored by Claude Opus 4.8
parent 9a79a76b95
commit 0c3f270419
10 changed files with 107 additions and 60 deletions
@@ -69,12 +69,18 @@ function NewChat({ resumeSummary, resumeSessionId, initialMessages }: NewChatPro
invalidateClaudeSessions();
}, [invalidateClaudeSessions]);
// context 'chat' tells the backend to run this session from the dedicated claude_sessions cwd, so
// context 'chat' tells the backend to run this session from the dedicated general_chat_sessions cwd, so
// its transcript lands in Claude's own store as an isolated project group (source of truth).
const chat = useChat(undefined, locationState?.model, { resumeSummary, resumeSessionId, initialMessages, onTurnComplete, context: 'chat' });
const chat = useChat(undefined, locationState?.model, {
resumeSummary,
resumeSessionId,
initialMessages,
onTurnComplete,
context: 'chat',
});
const sandboxed = !isSuperAdmin;
// Run the session in the pwd chosen in the Sessions panel; null → backend default (claude_sessions).
// Run the session in the pwd chosen in the Sessions panel; null → backend default (general_chat_sessions).
const [activeCwd] = usePanelChannel<string | null>('chat:active-cwd', null);
const cwd = activeCwd ? { path: activeCwd } : locationState?.cwd;
@@ -4,7 +4,7 @@ import { useChatPwds } from 'state/useClaudeSessions';
import { DirPickerModal } from './DirPickerModal';
type PwdSelectorProps = {
value: string | null; // null = the default claude_sessions dir
value: string | null; // null = the default general_chat_sessions dir
onChange: (cwd: string | null) => void;
};
@@ -19,7 +19,7 @@ export const PwdSelector = ({ value, onChange }: PwdSelectorProps) => {
const [custom, setCustom] = useState('');
const isDefaultActive = value === null || value === defaultCwd;
const label = isDefaultActive ? 'claude_sessions' : basename(value!);
const label = isDefaultActive ? 'general_chat_sessions' : basename(value!);
const pick = (cwd: string | null) => {
onChange(cwd);
@@ -35,7 +35,7 @@ export const PwdSelector = ({ value, onChange }: PwdSelectorProps) => {
<div className="relative">
<button
onClick={() => setOpen((o) => !o)}
title={isDefaultActive ? defaultCwd ?? 'Default' : value!}
title={isDefaultActive ? (defaultCwd ?? 'Default') : value!}
className="flex items-center gap-1.5 max-w-[13rem] rounded-md border border-duck-dark/10 dark:border-foreground/10 px-2 py-1 text-xs text-duck-dark/70 dark:text-foreground/70 hover:bg-duck-dark/5 dark:hover:bg-foreground/5 cursor-pointer transition-colors"
>
<FolderOpen className="h-3.5 w-3.5 shrink-0 text-duck-teal/70" />
@@ -58,7 +58,9 @@ export const PwdSelector = ({ value, onChange }: PwdSelectorProps) => {
className={`flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs cursor-pointer hover:bg-duck-dark/5 dark:hover:bg-foreground/5 ${selected ? 'text-duck-teal' : 'text-duck-dark/70 dark:text-foreground/70'}`}
>
<Check className={`h-3.5 w-3.5 shrink-0 ${selected ? 'opacity-100' : 'opacity-0'}`} />
<span className="min-w-0 flex-1 truncate">{p.isDefault ? 'Default · claude_sessions' : shorten(p.cwd)}</span>
<span className="min-w-0 flex-1 truncate">
{p.isDefault ? 'Default · general_chat_sessions' : shorten(p.cwd)}
</span>
{p.sessionCount > 0 && <span className="shrink-0 opacity-40">{p.sessionCount}</span>}
</button>
);
@@ -11,7 +11,7 @@ import { PwdSelector } from './PwdSelector';
// Clicking a session loads its transcript and continues the real Claude session via --resume.
export const SessionList = () => {
const navigate = useNavigate();
// The working directory the list operates on (null = the default claude_sessions dir).
// The working directory the list operates on (null = the default general_chat_sessions dir).
const [activeCwd, setActiveCwd] = usePanelChannel<string | null>('chat:active-cwd', null);
const { sessions, isLoading, refetch, loadSession, deleteSession, renameSession } = useClaudeSessions(activeCwd);
const [selected, setSelected] = usePanelChannel<SelectedSession>('chat:selected-session', null);
@@ -125,10 +125,20 @@ export const SessionList = () => {
onBlur={commitRename}
className="flex-1 min-w-0 bg-transparent border-b border-duck-teal/40 text-sm outline-none"
/>
<button onMouseDown={(ev) => ev.preventDefault()} onClick={commitRename} className="p-1 text-duck-teal hover:opacity-80 cursor-pointer" title="Save">
<button
onMouseDown={(ev) => ev.preventDefault()}
onClick={commitRename}
className="p-1 text-duck-teal hover:opacity-80 cursor-pointer"
title="Save"
>
<Check className="h-3.5 w-3.5" />
</button>
<button onMouseDown={(ev) => ev.preventDefault()} onClick={() => setEditingId(null)} className="p-1 opacity-50 hover:opacity-100 cursor-pointer" title="Cancel">
<button
onMouseDown={(ev) => ev.preventDefault()}
onClick={() => setEditingId(null)}
className="p-1 opacity-50 hover:opacity-100 cursor-pointer"
title="Cancel"
>
<X className="h-3.5 w-3.5" />
</button>
</div>
@@ -145,7 +155,9 @@ export const SessionList = () => {
<MessageSquare className="h-4 w-4 shrink-0 text-duck-teal/60" />
)}
<div className="min-w-0 flex-1">
<div className="text-sm font-medium text-duck-dark/80 dark:text-foreground/80 truncate">{session.title}</div>
<div className="text-sm font-medium text-duck-dark/80 dark:text-foreground/80 truncate">
{session.title}
</div>
<div className="flex items-center gap-2 text-xs text-duck-dark/40 dark:text-foreground/40">
<span>
{new Date(session.updatedAt).toLocaleDateString(undefined, {
@@ -157,7 +169,9 @@ export const SessionList = () => {
</span>
<span>·</span>
{session.harness === 'opencode' ? (
<span className="rounded bg-duck-teal/10 px-1.5 py-0.5 font-medium text-duck-teal">OpenCode</span>
<span className="rounded bg-duck-teal/10 px-1.5 py-0.5 font-medium text-duck-teal">
OpenCode
</span>
) : (
<span>
{session.messageCount} msg{session.messageCount === 1 ? '' : 's'}
@@ -170,10 +184,18 @@ export const SessionList = () => {
{isConfirming ? (
<div className="flex shrink-0 items-center gap-1 mr-2">
<span className="text-xs text-red-500">Delete?</span>
<button onClick={() => handleDelete(session.id)} className="p-1 rounded text-red-500 hover:bg-red-500/10 cursor-pointer" title="Confirm delete">
<button
onClick={() => handleDelete(session.id)}
className="p-1 rounded text-red-500 hover:bg-red-500/10 cursor-pointer"
title="Confirm delete"
>
<Check className="h-3.5 w-3.5" />
</button>
<button onClick={() => setConfirmingId(null)} className="p-1 rounded opacity-50 hover:opacity-100 cursor-pointer" title="Cancel">
<button
onClick={() => setConfirmingId(null)}
className="p-1 rounded opacity-50 hover:opacity-100 cursor-pointer"
title="Cancel"
>
<X className="h-3.5 w-3.5" />
</button>
</div>
@@ -19,13 +19,20 @@ export type ClaudeSessionSummary = {
export type ClaudeSessionMessage =
| { role: 'user'; text: string }
| { role: 'assistant'; id: string; text: string }
| { role: 'tool'; toolName: string; toolInput: Record<string, unknown>; toolCallId: string; output?: string; isError?: boolean };
| {
role: 'tool';
toolName: string;
toolInput: Record<string, unknown>;
toolCallId: string;
output?: string;
isError?: boolean;
};
export type ClaudeSessionDetail = { id: string; model: string; cwd: string; messages: ClaudeSessionMessage[] };
export type ClaudePwd = { cwd: string; sessionCount: number; updatedAt: string; isDefault: boolean };
// Query string for the selected working directory (null/undefined = the default claude_sessions dir).
// Query string for the selected working directory (null/undefined = the default general_chat_sessions dir).
const cwdQuery = (cwd?: string | null) => (cwd ? `?cwd=${encodeURIComponent(cwd)}` : '');
/** The default /chat dir plus every directory that already has Claude sessions. */