chat: retire the old saved-session store (Stage 4a)

Deletes all session persistence that isn't Claude's native transcript store, per
the "only harness-native session management survives" rule.

Backend: delete api/pi/storage.ts (meta.json+messages.json file store), the
api/saved-sessions router (+ unmount), the /pi/sessions REST endpoints, and the
storage.save/loadSession calls in the chat WS handler (in-memory session-manager
stays for live turns; no disk persistence — Claude's transcript is the record).
Also drops the Postgres saved_sessions layer: schema/chat.ts, queries/saved-sessions.ts,
its types and re-exports.

Frontend: delete state/useSavedSessions, ChatList, and the ChatHistory Widget
(all pure saved-session UI); slim ChatHeader to a label; strip the auto-load-latest
+ Save wiring from ChatPanelWrapper and ChatDetailPanel; drop the old resume path
from useChat and SessionListPage; remove the /chat/saved/:id route and the
useInitialData prefetch.

Behavior removed (intended): the Save-session button, email/project panels
auto-resuming the last chat, and /chat/saved/:id. /chat itself is unchanged —
already fully on Claude transcripts. The orphaned saved_sessions Postgres table
is dropped on the next `bun db:push`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 15:29:26 +00:00
co-authored by Claude Opus 4.8
parent 2e3c45ddfb
commit 70555c8d71
23 changed files with 31 additions and 1813 deletions
-7
View File
@@ -64,13 +64,6 @@ export {
upsertDefaults,
} from './queries/dashboards';
export {
listSavedSessions,
getSavedSession,
createSavedSession,
updateSavedSessionMessages,
deleteSavedSession,
} from './queries/saved-sessions';
export {
createPipelineJob,
@@ -1,59 +0,0 @@
import { eq, and, desc } from 'drizzle-orm';
import { db } from '../db';
import { savedSessions } from '../schema';
import type { SavedSessionInsert, SavedSessionSelect } from '../types';
export async function listSavedSessions(userId: number): Promise<Omit<SavedSessionSelect, 'rawMessages'>[]> {
const rows = await db
.select({
id: savedSessions.id,
userId: savedSessions.userId,
provider: savedSessions.provider,
context: savedSessions.context,
contextId: savedSessions.contextId,
title: savedSessions.title,
summary: savedSessions.summary,
cwd: savedSessions.cwd,
cost: savedSessions.cost,
createdAt: savedSessions.createdAt,
})
.from(savedSessions)
.where(eq(savedSessions.userId, userId))
.orderBy(desc(savedSessions.createdAt));
return rows;
}
export async function getSavedSession(id: number, userId: number): Promise<SavedSessionSelect | undefined> {
const rows = await db
.select()
.from(savedSessions)
.where(and(eq(savedSessions.id, id), eq(savedSessions.userId, userId)));
return rows[0];
}
export async function createSavedSession(data: SavedSessionInsert): Promise<SavedSessionSelect> {
const rows = await db.insert(savedSessions).values(data).returning();
return rows[0]!;
}
export async function updateSavedSessionMessages(
id: number,
userId: number,
rawMessages: unknown,
cost: unknown,
): Promise<boolean> {
const result = await db
.update(savedSessions)
.set({ rawMessages, cost })
.where(and(eq(savedSessions.id, id), eq(savedSessions.userId, userId)))
.returning({ id: savedSessions.id });
return result.length > 0;
}
export async function deleteSavedSession(id: number, userId: number): Promise<boolean> {
const result = await db
.delete(savedSessions)
.where(and(eq(savedSessions.id, id), eq(savedSessions.userId, userId)))
.returning({ id: savedSessions.id });
return result.length > 0;
}
@@ -1,22 +0,0 @@
import { pgTable, serial, text, integer, timestamp, jsonb, index } from 'drizzle-orm/pg-core';
import { users } from './auth';
export const savedSessions = pgTable(
'saved_sessions',
{
id: serial('id').primaryKey(),
userId: integer('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
provider: text('provider').notNull(),
context: text('context'),
contextId: text('context_id'),
title: text('title').notNull(),
summary: text('summary').notNull(),
rawMessages: jsonb('raw_messages').notNull(),
cwd: text('cwd').notNull(),
cost: jsonb('cost').notNull(),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
},
(table) => [index('idx_saved_sessions_user_created').on(table.userId, table.createdAt)],
);
@@ -1,6 +1,5 @@
export * from './auth';
export * from './user-data';
export * from './chat';
export * from './dashboards';
export * from './operations';
export * from './server';
-2
View File
@@ -36,8 +36,6 @@ export type DockConfigInsert = typeof Schema.dockConfigs.$inferInsert;
// ── Saved Sessions ──
export type SavedSessionSelect = typeof Schema.savedSessions.$inferSelect;
export type SavedSessionInsert = typeof Schema.savedSessions.$inferInsert;
// ── Dashboards ──