From c7e9851826380316f73d439ffddb532dceac78d7 Mon Sep 17 00:00:00 2001 From: Alex Yaroshuk Date: Thu, 26 Feb 2026 03:26:47 +0800 Subject: [PATCH 1/4] wip: unarchive --- .../app/src/components/dialog-settings.tsx | 14 ++ .../app/src/components/settings-archive.tsx | 185 ++++++++++++++++++ packages/app/src/i18n/ar.ts | 5 + packages/app/src/i18n/br.ts | 5 + packages/app/src/i18n/bs.ts | 5 + packages/app/src/i18n/da.ts | 5 + packages/app/src/i18n/de.ts | 6 + packages/app/src/i18n/en.ts | 8 + packages/app/src/i18n/es.ts | 6 + packages/app/src/i18n/fr.ts | 5 + packages/app/src/i18n/ja.ts | 6 + packages/app/src/i18n/ko.ts | 6 + packages/app/src/i18n/no.ts | 6 + packages/app/src/i18n/pl.ts | 5 + packages/app/src/i18n/ru.ts | 5 + packages/app/src/i18n/th.ts | 6 + packages/app/src/i18n/zh.ts | 6 + packages/app/src/i18n/zht.ts | 6 + .../opencode/src/server/routes/session.ts | 12 +- packages/opencode/src/session/index.ts | 8 +- 20 files changed, 304 insertions(+), 6 deletions(-) create mode 100644 packages/app/src/components/settings-archive.tsx diff --git a/packages/app/src/components/dialog-settings.tsx b/packages/app/src/components/dialog-settings.tsx index 83cea131f5d..f63e2c339ac 100644 --- a/packages/app/src/components/dialog-settings.tsx +++ b/packages/app/src/components/dialog-settings.tsx @@ -8,6 +8,7 @@ import { SettingsGeneral } from "./settings-general" import { SettingsKeybinds } from "./settings-keybinds" import { SettingsProviders } from "./settings-providers" import { SettingsModels } from "./settings-models" +import { SettingsArchive } from "./settings-archive" export const DialogSettings: Component = () => { const language = useLanguage() @@ -47,6 +48,16 @@ export const DialogSettings: Component = () => { + +
+ {language.t("settings.section.data")} +
+ + + {language.t("settings.archive.title")} + +
+
@@ -67,6 +78,9 @@ export const DialogSettings: Component = () => { + + + ) diff --git a/packages/app/src/components/settings-archive.tsx b/packages/app/src/components/settings-archive.tsx new file mode 100644 index 00000000000..25e9e38ac61 --- /dev/null +++ b/packages/app/src/components/settings-archive.tsx @@ -0,0 +1,185 @@ +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { RadioGroup } from "@opencode-ai/ui/radio-group" +import { getFilename } from "@opencode-ai/util/path" +import { Component, For, Show, createMemo, createResource, createSignal } from "solid-js" +import { useParams } from "@solidjs/router" +import { useGlobalSDK } from "@/context/global-sdk" +import { useGlobalSync } from "@/context/global-sync" +import { useLanguage } from "@/context/language" +import { getRelativeTime } from "@/utils/time" +import { decode64 } from "@/utils/base64" +import type { Session } from "@opencode-ai/sdk/v2/client" +import { SessionSkeleton } from "@/pages/layout/sidebar-items" + +type FilterScope = "all" | "current" + +type ScopeOption = { value: FilterScope; label: "settings.archive.scope.all" | "settings.archive.scope.current" } + +const scopeOptions: ScopeOption[] = [ + { value: "all", label: "settings.archive.scope.all" }, + { value: "current", label: "settings.archive.scope.current" }, +] + +export const SettingsArchive: Component = () => { + const language = useLanguage() + const globalSDK = useGlobalSDK() + const globalSync = useGlobalSync() + const params = useParams() + const [removedIds, setRemovedIds] = createSignal>(new Set()) + + const projects = createMemo(() => globalSync.data.project) + const hasMultipleProjects = createMemo(() => projects().length > 1) + const homedir = createMemo(() => globalSync.data.path.home) + + const defaultScope = () => (hasMultipleProjects() ? "current" : "all") + const [filterScope, setFilterScope] = createSignal(defaultScope()) + + const currentDirectory = createMemo(() => decode64(params.dir) ?? "") + + const currentProject = createMemo(() => { + const dir = currentDirectory() + if (!dir) return null + return projects().find((p) => p.worktree === dir || p.sandboxes?.includes(dir)) ?? null + }) + + const filteredProjects = createMemo(() => { + if (filterScope() === "current" && currentProject()) { + return [currentProject()!] + } + return projects() + }) + + const getSessionLabel = (session: Session) => { + const directory = session.directory + const home = homedir() + const path = home ? directory.replace(home, "~") : directory + + if (filterScope() === "current" && currentProject()) { + const current = currentProject() + const kind = + current && directory === current.worktree + ? language.t("workspace.type.local") + : language.t("workspace.type.sandbox") + const [store] = globalSync.child(directory, { bootstrap: false }) + const name = store.vcs?.branch ?? getFilename(directory) + return `${kind} : ${name || path}` + } + + return path + } + + const [archivedSessions] = createResource( + () => ({ scope: filterScope(), projects: filteredProjects() }), + async ({ projects }) => { + const allSessions: Session[] = [] + for (const project of projects) { + const directories = [project.worktree, ...(project.sandboxes ?? [])] + for (const directory of directories) { + const result = await globalSDK.client.experimental.session.list({ directory, archived: true }) + const sessions = result.data ?? [] + for (const session of sessions) { + allSessions.push(session) + } + } + } + return allSessions.sort((a, b) => (b.time?.updated ?? 0) - (a.time?.updated ?? 0)) + }, + { initialValue: [] }, + ) + + const displayedSessions = () => { + const sessions = archivedSessions() ?? [] + const removed = removedIds() + return sessions.filter((s) => !removed.has(s.id)) + } + + const currentScopeOption = () => scopeOptions.find((o) => o.value === filterScope()) + + const unarchiveSession = async (session: Session) => { + setRemovedIds((prev) => new Set(prev).add(session.id)) + await globalSDK.client.session.update({ + directory: session.directory, + sessionID: session.id, + time: { archived: null as any }, + }) + } + + const handleScopeChange = (option: ScopeOption | undefined) => { + if (!option) return + setRemovedIds(new Set()) + setFilterScope(option.value) + } + + return ( +
+
+
+

{language.t("settings.archive.title")}

+

{language.t("settings.archive.description")}

+
+
+ +
+ + o.value} + size="small" + label={(o) => language.t(o.label)} + onSelect={handleScopeChange} + /> + + + +
+ } + > + +
{language.t("settings.archive.none")}
+
+ } + > +
+ + {(session) => ( +
+
+
+ {session.title} + {getSessionLabel(session)} +
+
+
+ + {(updated) => ( + + {getRelativeTime(new Date(updated()).toISOString())} + + )} + + +
+
+ )} +
+
+ + +
+ + ) +} diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index 91a16b3b853..24f54beaf76 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -732,4 +732,9 @@ export const dict = { "workspace.reset.archived.one": "ستتم أرشفة جلسة واحدة.", "workspace.reset.archived.many": "ستتم أرشفة {{count}} جلسات.", "workspace.reset.note": "سيؤدي هذا إلى إعادة تعيين مساحة العمل لتتطابق مع الفرع الافتراضي.", + "settings.archive.title": "الجلسات المؤرشفة", + "settings.archive.description": "استعادة الجلسات المؤرشفة لجعلها مرئية في الشريط الجانبي.", + "settings.archive.none": "لا توجد جلسات مؤرشفة.", + "settings.archive.scope.all": "جميع المشاريع", + "settings.archive.scope.current": "المشروع الحالي", } diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 7682a12b697..f06296647dd 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -740,4 +740,9 @@ export const dict = { "workspace.reset.archived.one": "1 sessão será arquivada.", "workspace.reset.archived.many": "{{count}} sessões serão arquivadas.", "workspace.reset.note": "Isso redefinirá o espaço de trabalho para corresponder ao branch padrão.", + "settings.archive.title": "Sessões arquivadas", + "settings.archive.description": "Restaure sessões arquivadas para torná-las visíveis na barra lateral.", + "settings.archive.none": "Nenhuma sessão arquivada.", + "settings.archive.scope.all": "Todos os projetos", + "settings.archive.scope.current": "Projeto atual", } diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index d658926268e..b5af8a81ce3 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -817,4 +817,9 @@ export const dict = { "workspace.reset.archived.one": "1 sesija će biti arhivirana.", "workspace.reset.archived.many": "Biće arhivirano {{count}} sesija.", "workspace.reset.note": "Ovo će resetovati radni prostor da odgovara podrazumijevanoj grani.", + "settings.archive.title": "Arhivirane sesije", + "settings.archive.description": "Vrati arhivirane sesije da bi bile vidljive u bočnoj traci.", + "settings.archive.none": "Nema arhiviranih sesija.", + "settings.archive.scope.all": "Svi projekti", + "settings.archive.scope.current": "Trenutni projekt", } diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index fabefcab756..cf0fc99b65a 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -811,4 +811,9 @@ export const dict = { "workspace.reset.archived.one": "1 session vil blive arkiveret.", "workspace.reset.archived.many": "{{count}} sessioner vil blive arkiveret.", "workspace.reset.note": "Dette vil nulstille arbejdsområdet til at matche hovedgrenen.", + "settings.archive.title": "Arkiverede sessioner", + "settings.archive.description": "Gendan arkiverede sessioner for at gøre dem synlige i sidebjælken.", + "settings.archive.none": "Ingen arkiverede sessioner.", + "settings.archive.scope.all": "Alle projekter", + "settings.archive.scope.current": "Nuværende projekt", } diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index 3a7bbe92772..3705b94723c 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -749,4 +749,10 @@ export const dict = { "workspace.reset.archived.one": "1 Sitzung wird archiviert.", "workspace.reset.archived.many": "{{count}} Sitzungen werden archiviert.", "workspace.reset.note": "Dadurch wird der Arbeitsbereich auf den Standard-Branch zurückgesetzt.", + + "settings.archive.title": "Archivierte Sitzungen", + "settings.archive.description": "Archivierte Sitzungen wiederherstellen, um sie in der Seitenleiste anzuzeigen.", + "settings.archive.none": "Keine archivierten Sitzungen.", + "settings.archive.scope.all": "Alle Projekte", + "settings.archive.scope.current": "Aktuelles Projekt", } satisfies Partial> diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 992509fcfa4..18310757b9f 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -568,6 +568,7 @@ export const dict = { "common.rename": "Rename", "common.reset": "Reset", "common.archive": "Archive", + "common.unarchive": "Unarchive", "common.delete": "Delete", "common.close": "Close", "common.edit": "Edit", @@ -591,6 +592,7 @@ export const dict = { "settings.section.desktop": "Desktop", "settings.section.server": "Server", + "settings.section.data": "Data", "settings.tab.general": "General", "settings.tab.shortcuts": "Shortcuts", "settings.desktop.section.wsl": "WSL", @@ -820,4 +822,10 @@ export const dict = { "workspace.reset.archived.one": "1 session will be archived.", "workspace.reset.archived.many": "{{count}} sessions will be archived.", "workspace.reset.note": "This will reset the workspace to match the default branch.", + + "settings.archive.title": "Archived Sessions", + "settings.archive.description": "Restore archived sessions to make them visible in the sidebar.", + "settings.archive.none": "No archived sessions.", + "settings.archive.scope.all": "All projects", + "settings.archive.scope.current": "Current project", } diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index b55d54c0ca5..4e8d5a0cc8a 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -823,4 +823,10 @@ export const dict = { "workspace.reset.archived.one": "1 sesión será archivada.", "workspace.reset.archived.many": "{{count}} sesiones serán archivadas.", "workspace.reset.note": "Esto restablecerá el espacio de trabajo para coincidir con la rama predeterminada.", + + "settings.archive.title": "Sesiones archivadas", + "settings.archive.description": "Restaura las sesiones archivadas para hacerlas visibles en la barra lateral.", + "settings.archive.none": "No hay sesiones archivadas.", + "settings.archive.scope.all": "Todos los proyectos", + "settings.archive.scope.current": "Proyecto actual", } diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index c961f060e1f..49753bc45eb 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -749,4 +749,9 @@ export const dict = { "workspace.reset.archived.one": "1 session sera archivée.", "workspace.reset.archived.many": "{{count}} sessions seront archivées.", "workspace.reset.note": "Cela réinitialisera l'espace de travail pour correspondre à la branche par défaut.", + "settings.archive.title": "Sessions archivées", + "settings.archive.description": "Restaurez les sessions archivées pour les rendre visibles dans la barre latérale.", + "settings.archive.none": "Aucune session archivée.", + "settings.archive.scope.all": "Tous les Projets", + "settings.archive.scope.current": "Projet actuel", } diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index 7a62c9de271..06f9364cace 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -736,4 +736,10 @@ export const dict = { "workspace.reset.archived.one": "1つのセッションがアーカイブされます。", "workspace.reset.archived.many": "{{count}}個のセッションがアーカイブされます。", "workspace.reset.note": "これにより、ワークスペースはデフォルトブランチと一致するようにリセットされます。", + + "settings.archive.title": "アーカイブされたセッション", + "settings.archive.description": "アーカイブされたセッションを復元してサイドバーに表示します。", + "settings.archive.none": "アーカイブされたセッションはありません。", + "settings.archive.scope.all": "すべてのプロジェクト", + "settings.archive.scope.current": "現在のプロジェクト", } diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index 8967c71cff7..fcb3ed0b999 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -736,4 +736,10 @@ export const dict = { "workspace.reset.archived.one": "1개의 세션이 보관됩니다.", "workspace.reset.archived.many": "{{count}}개의 세션이 보관됩니다.", "workspace.reset.note": "이 작업은 작업 공간을 기본 브랜치와 일치하도록 재설정합니다.", + + "settings.archive.title": "보관된 세션", + "settings.archive.description": "보관된 세션을 복원하여 사이드바에 표시합니다.", + "settings.archive.none": "보관된 세션이 없습니다.", + "settings.archive.scope.all": "모든 프로젝트", + "settings.archive.scope.current": "현재 프로젝트", } diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index 8e1b1ce629d..ed56fd9dd7b 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -819,4 +819,10 @@ export const dict = { "workspace.reset.archived.one": "1 sesjon vil bli arkivert.", "workspace.reset.archived.many": "{{count}} sesjoner vil bli arkivert.", "workspace.reset.note": "Dette vil tilbakestille arbeidsområdet til å samsvare med standardgrenen.", + + "settings.archive.title": "Arkiverte økter", + "settings.archive.description": "Gjenopprett arkiverte økter for å gjøre dem synlige i sidefeltet.", + "settings.archive.none": "Ingen arkiverte økter.", + "settings.archive.scope.all": "Alle prosjekter", + "settings.archive.scope.current": "Nåværende prosjekt", } satisfies Partial> diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index 9b924fd642e..ea308107c23 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -738,4 +738,9 @@ export const dict = { "workspace.reset.archived.one": "1 sesja zostanie zarchiwizowana.", "workspace.reset.archived.many": "{{count}} sesji zostanie zarchiwizowanych.", "workspace.reset.note": "To zresetuje przestrzeń roboczą, aby odpowiadała domyślnej gałęzi.", + "settings.archive.title": "Zarchiwizowane sesje", + "settings.archive.description": "Przywróć zarchiwizowane sesje, aby były widoczne na pasku bocznym.", + "settings.archive.none": "Brak zarchiwizowanych sesji.", + "settings.archive.scope.all": "Wszystkie projekty", + "settings.archive.scope.current": "Bieżący projekt", } diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index cf02285821e..8928a3f8f41 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -819,4 +819,9 @@ export const dict = { "workspace.reset.archived.one": "1 сессия будет архивирована.", "workspace.reset.archived.many": "{{count}} сессий будет архивировано.", "workspace.reset.note": "Рабочее пространство будет сброшено в соответствие с веткой по умолчанию.", + "settings.archive.title": "Архивированные сессии", + "settings.archive.description": "Восстановите архивированные сессии, чтобы они отображались на боковой панели.", + "settings.archive.none": "Нет архивированных сессий.", + "settings.archive.scope.all": "Все проекты", + "settings.archive.scope.current": "Текущий проект", } diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index 1b8abe953b7..6db0e07c5d8 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -809,4 +809,10 @@ export const dict = { "workspace.reset.archived.one": "1 เซสชันจะถูกจัดเก็บ", "workspace.reset.archived.many": "{{count}} เซสชันจะถูกจัดเก็บ", "workspace.reset.note": "สิ่งนี้จะรีเซ็ตพื้นที่ทำงานให้ตรงกับสาขาเริ่มต้น", + + "settings.archive.title": "เซสชันที่จัดเก็บ", + "settings.archive.description": "กู้คืนเซสชันที่จัดเก็บเพื่อให้แสดงในแถบด้านข้าง", + "settings.archive.none": "ไม่มีเซสชันที่จัดเก็บ", + "settings.archive.scope.all": "โปรเจกต์ทั้งหมด", + "settings.archive.scope.current": "โปรเจกต์ปัจจุบัน", } diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index 62c7bb9ff23..1c2c721fdb2 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -807,4 +807,10 @@ export const dict = { "workspace.reset.archived.one": "将归档 1 个会话。", "workspace.reset.archived.many": "将归档 {{count}} 个会话。", "workspace.reset.note": "这将把工作区重置为与默认分支一致。", + + "settings.archive.title": "归档会话", + "settings.archive.description": "恢复归档会话以使其在侧边栏中可见。", + "settings.archive.none": "没有归档会话。", + "settings.archive.scope.all": "所有项目", + "settings.archive.scope.current": "当前项目", } satisfies Partial> diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index cb8f068f63b..f803845bd60 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -802,4 +802,10 @@ export const dict = { "workspace.reset.archived.one": "將封存 1 個工作階段。", "workspace.reset.archived.many": "將封存 {{count}} 個工作階段。", "workspace.reset.note": "這將把工作區重設為與預設分支一致。", + + "settings.archive.title": "封存工作階段", + "settings.archive.description": "恢復封存的工作階段以使其在側邊欄中可見。", + "settings.archive.none": "沒有封存的工作階段。", + "settings.archive.scope.all": "所有專案", + "settings.archive.scope.current": "目前專案", } satisfies Partial> diff --git a/packages/opencode/src/server/routes/session.ts b/packages/opencode/src/server/routes/session.ts index 1195529e06a..be452ff56ee 100644 --- a/packages/opencode/src/server/routes/session.ts +++ b/packages/opencode/src/server/routes/session.ts @@ -261,13 +261,19 @@ export const SessionRoutes = lazy(() => sessionID: z.string(), }), ), + validator( + "query", + z.object({ + directory: z.string().optional(), + }), + ), validator( "json", z.object({ title: z.string().optional(), time: z .object({ - archived: z.number().optional(), + archived: z.number().nullable().optional(), }) .optional(), }), @@ -280,8 +286,8 @@ export const SessionRoutes = lazy(() => if (updates.title !== undefined) { session = await Session.setTitle({ sessionID, title: updates.title }) } - if (updates.time?.archived !== undefined) { - session = await Session.setArchived({ sessionID, time: updates.time.archived }) + if (updates.time !== undefined && "archived" in updates.time) { + session = await Session.setArchived({ sessionID, time: updates.time.archived ?? undefined }) } return c.json(session) diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index 8454a9c3e97..3f4d03f0d3b 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -10,7 +10,7 @@ import { Flag } from "../flag/flag" import { Identifier } from "../id/id" import { Installation } from "../installation" -import { Database, NotFoundError, eq, and, or, gte, isNull, desc, like, inArray, lt } from "../storage/db" +import { Database, NotFoundError, eq, and, or, gte, isNull, isNotNull, desc, like, inArray, lt } from "../storage/db" import type { SQL } from "../storage/db" import { SessionTable, MessageTable, PartTable } from "./session.sql" import { ProjectTable } from "../project/project.sql" @@ -396,7 +396,7 @@ export namespace Session { return Database.use((db) => { const row = db .update(SessionTable) - .set({ time_archived: input.time }) + .set({ time_archived: input.time ?? null }) .where(eq(SessionTable.id, input.sessionID)) .returning() .get() @@ -590,7 +590,9 @@ export namespace Session { if (input?.search) { conditions.push(like(SessionTable.title, `%${input.search}%`)) } - if (!input?.archived) { + if (input?.archived) { + conditions.push(isNotNull(SessionTable.time_archived)) + } else { conditions.push(isNull(SessionTable.time_archived)) } From 4f740306f06271d7ddc0b6d6d9d47104e6dc3de2 Mon Sep 17 00:00:00 2001 From: Alex Yaroshuk Date: Thu, 26 Feb 2026 23:47:23 +0800 Subject: [PATCH 2/4] fix layout --- packages/app/src/components/settings-archive.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/app/src/components/settings-archive.tsx b/packages/app/src/components/settings-archive.tsx index 25e9e38ac61..9d7699bb827 100644 --- a/packages/app/src/components/settings-archive.tsx +++ b/packages/app/src/components/settings-archive.tsx @@ -7,6 +7,7 @@ import { useParams } from "@solidjs/router" import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSync } from "@/context/global-sync" import { useLanguage } from "@/context/language" +import { useLayout } from "@/context/layout" import { getRelativeTime } from "@/utils/time" import { decode64 } from "@/utils/base64" import type { Session } from "@opencode-ai/sdk/v2/client" @@ -25,10 +26,12 @@ export const SettingsArchive: Component = () => { const language = useLanguage() const globalSDK = useGlobalSDK() const globalSync = useGlobalSync() + const layout = useLayout() const params = useParams() const [removedIds, setRemovedIds] = createSignal>(new Set()) const projects = createMemo(() => globalSync.data.project) + const layoutProjects = createMemo(() => layout.projects.list()) const hasMultipleProjects = createMemo(() => projects().length > 1) const homedir = createMemo(() => globalSync.data.path.home) @@ -40,14 +43,14 @@ export const SettingsArchive: Component = () => { const currentProject = createMemo(() => { const dir = currentDirectory() if (!dir) return null - return projects().find((p) => p.worktree === dir || p.sandboxes?.includes(dir)) ?? null + return layoutProjects().find((p) => p.worktree === dir || p.sandboxes?.includes(dir)) ?? null }) const filteredProjects = createMemo(() => { if (filterScope() === "current" && currentProject()) { return [currentProject()!] } - return projects() + return layoutProjects() }) const getSessionLabel = (session: Session) => { @@ -147,7 +150,7 @@ export const SettingsArchive: Component = () => { } > -
+
{(session) => (
From 76cda308968fdc3694766e2a7c959cbb957e3294 Mon Sep 17 00:00:00 2001 From: Alex Yaroshuk Date: Fri, 27 Feb 2026 00:36:50 +0800 Subject: [PATCH 3/4] use early return instead of 'else' in index.ts --- packages/opencode/src/session/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index 3f4d03f0d3b..8b2b4cf0321 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -592,7 +592,8 @@ export namespace Session { } if (input?.archived) { conditions.push(isNotNull(SessionTable.time_archived)) - } else { + } + if (!input?.archived) { conditions.push(isNull(SessionTable.time_archived)) } From 323e7a36daf9403f6a1ddd041db57f2470348b09 Mon Sep 17 00:00:00 2001 From: Alex Yaroshuk Date: Sat, 28 Feb 2026 10:30:46 +0800 Subject: [PATCH 4/4] (sync) update getRealtiveTime call to use the new language arg --- packages/app/src/components/settings-archive.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/settings-archive.tsx b/packages/app/src/components/settings-archive.tsx index 9d7699bb827..28ace7bad9b 100644 --- a/packages/app/src/components/settings-archive.tsx +++ b/packages/app/src/components/settings-archive.tsx @@ -164,7 +164,7 @@ export const SettingsArchive: Component = () => { {(updated) => ( - {getRelativeTime(new Date(updated()).toISOString())} + {getRelativeTime(new Date(updated()).toISOString(), language.t)} )}