feat(client-runtime): project the archive set and the archiveSession action

WorkspaceListState gains archivedSessionIds (ReadonlySet, replaced only
on membership change), installed as full snapshots from the list
baseline, the unary echo, and the changed frame. Archiving the current
session clears the selection into the New Session view state. Test
doubles (test-runtime, fake APIs, fixture client) follow the widened
IWorkspaces/IApiClient faces.
This commit is contained in:
imccyu
2026-07-31 02:40:14 +08:00
committed by imccyu
parent 53ceab53b8
commit c764ed7e64
24 changed files with 177 additions and 21 deletions

View File

@@ -128,7 +128,7 @@ async function bench(snapshot: ConversationSnapshot) {
ctx.provide('sessions', sessionsFake)
const workspaces = {
list: createSnapshotStore<WorkspaceListState>({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
}),
startSession: vi.fn(),

View File

@@ -94,7 +94,7 @@ function emptySessions() {
function emptyWorkspaces() {
const store = createSnapshotStore<WorkspaceListState>({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})
return bindSnapshotSelector(store)

View File

@@ -74,7 +74,7 @@ describe('render branch tails', () => {
const emptyList = createSnapshotStore<SessionListState>(
{ ids: [], byId: {}, current: undefined, phase: 'ready' })
const emptyWorkspaces = createSnapshotStore<WorkspaceListState>({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})
const view = render(
@@ -111,7 +111,7 @@ describe('render branch tails', () => {
const emptyList = createSnapshotStore<SessionListState>(
{ ids: [], byId: {}, current: undefined, phase: 'ready' })
const emptyWorkspaces = createSnapshotStore<WorkspaceListState>({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})
const view = render(

View File

@@ -96,7 +96,7 @@ function bench(over?: BenchOptions) {
ids: [], byId: {}, current: undefined, phase: 'ready',
})),
useWorkspaces: bindSnapshotSelector(createSnapshotStore({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})),
useProjection: ((key: string, selector?: (v: unknown) => unknown) =>

View File

@@ -39,7 +39,7 @@ function mountBar(shell: SessionInputShell, over?: { running?: boolean; disabled
ids: [], byId: {}, current: undefined, phase: 'ready',
})),
useWorkspaces: bindSnapshotSelector(createSnapshotStore({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})),
useProjection: (() => undefined),

View File

@@ -125,7 +125,7 @@ async function scopedBench(register?: (slash: SlashService) => void) {
ids: [], byId: {}, current: undefined, phase: 'ready',
})),
useWorkspaces: bindSnapshotSelector(createSnapshotStore({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})),
useProjection: (() => undefined),

View File

@@ -62,7 +62,7 @@ function workspace(id = 'w1'): WorkspaceView {
}
const workspaceState = (items: readonly WorkspaceView[]): WorkspaceListState => ({
items, state: 'idle', phase: 'ready', error: null,
items, archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})

View File

@@ -429,7 +429,7 @@ describe('DetailsPanel Output section', () => {
phase: 'ready',
})
const workspaces = createSnapshotStore<WorkspaceListState>({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
})
return render(
@@ -607,7 +607,7 @@ describe('DetailsPanel Output section', () => {
useSessions={bindSnapshotSelector(createSnapshotStore<SessionListState>(
{ ids: [], byId: {}, current: undefined, phase: 'ready' }))}
useWorkspaces={bindSnapshotSelector(createSnapshotStore<WorkspaceListState>({
items: [], state: 'idle', phase: 'ready', error: null,
items: [], archivedSessionIds: new Set(), state: 'idle', phase: 'ready', error: null,
baselinesReady: true, recentWorkspaceId: undefined,
}))}
useInput={(() => { throw new Error('unused') })}