Compare commits

..

4 Commits

Author SHA1 Message Date
Simon Klee 6fbfd8e229 build: bump opentui to 0.4.5
Embed the tree-sitter worker via import.meta.resolve so the
binary build no longer depends on node_modules layout.
2026-07-18 08:21:04 +02:00
opencode-agent[bot] 901c9e7329 fix(app): disable unavailable file navigation (#37595)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2026-07-18 15:39:15 +10:00
opencode-agent[bot] 3476e6baa5 chore: update nix node_modules hashes 2026-07-18 03:05:17 +00:00
opencode-agent[bot] 86e04d4174 revert(tui): downgrade opentui to 0.4.3 (#37582)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-07-17 21:51:48 -05:00
31 changed files with 60 additions and 169 deletions
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-zAftZieWR0hWQQVkhEa826iueHaRnKxtyRodhNb+Apc=",
"aarch64-linux": "sha256-cTG+gB7CuiFgaYHSFbzXaXUI1C2kiugV3B9rUDRUwlg=",
"aarch64-darwin": "sha256-ap4Xv5ZliourkI4mcD0ktbzSI88jb4oVBv5mMK3WdUs=",
"x86_64-darwin": "sha256-NGRJMMnaMNrf3FkcYwr5PcfVm5thhlNLGIeMmAK0MeE="
"x86_64-linux": "sha256-XWoSYsV18a5uvjM3KuyGQWiFAtcCV0ij8brOLuFOW+g=",
"aarch64-linux": "sha256-50cI0CuzzMRO8vznPxTHRhgHirE7siOg6AmyKLhZ2oo=",
"aarch64-darwin": "sha256-5JpSBNyKqiB+gOrkxMNWyWGWLdNlbEiirA56GDhAS4E=",
"x86_64-darwin": "sha256-X1r9aOSEdMUqWtqa4a/tBK2nRSwIWfKOwqJfpFknhII="
}
}
-1
View File
@@ -75,7 +75,6 @@ export const dict = {
"command.workspace.toggle.description": "تمكين أو تعطيل مساحات العمل المتعددة في الشريط الجانبي",
"command.session.undo": "تراجع",
"command.session.undo.description": "تراجع عن الرسالة الأخيرة",
"command.session.undo.gitRequired": "لم يتم اكتشاف مستودع Git",
"command.session.redo": "إعادة",
"command.session.redo.description": "إعادة الرسالة التي تم التراجع عنها",
"command.session.compact": "ضغط الجلسة",
-1
View File
@@ -75,7 +75,6 @@ export const dict = {
"command.workspace.toggle.description": "Habilitar ou desabilitar múltiplos espaços de trabalho na barra lateral",
"command.session.undo": "Desfazer",
"command.session.undo.description": "Desfazer a última mensagem",
"command.session.undo.gitRequired": "Nenhum repositório Git detectado",
"command.session.redo": "Refazer",
"command.session.redo.description": "Refazer a última mensagem desfeita",
"command.session.compact": "Compactar sessão",
-1
View File
@@ -81,7 +81,6 @@ export const dict = {
"command.workspace.toggle.description": "Omogući ili onemogući više radnih prostora u bočnoj traci",
"command.session.undo": "Poništi",
"command.session.undo.description": "Poništi posljednju poruku",
"command.session.undo.gitRequired": "Git repozitorij nije otkriven",
"command.session.redo": "Vrati",
"command.session.redo.description": "Vrati posljednju poništenu poruku",
"command.session.compact": "Sažmi sesiju",
-1
View File
@@ -81,7 +81,6 @@ export const dict = {
"command.workspace.toggle.description": "Aktiver eller deaktiver flere arbejdsområder i sidebjælken",
"command.session.undo": "Fortryd",
"command.session.undo.description": "Fortryd den sidste besked",
"command.session.undo.gitRequired": "Intet Git-repository fundet",
"command.session.redo": "Omgør",
"command.session.redo.description": "Omgør den sidste fortrudte besked",
"command.session.compact": "Komprimér session",
-1
View File
@@ -79,7 +79,6 @@ export const dict = {
"command.workspace.toggle.description": "Mehrere Arbeitsbereiche in der Seitenleiste aktivieren oder deaktivieren",
"command.session.undo": "Rückgängig",
"command.session.undo.description": "Letzte Nachricht rückgängig machen",
"command.session.undo.gitRequired": "Kein Git-Repository erkannt",
"command.session.redo": "Wiederherstellen",
"command.session.redo.description": "Letzte rückgängig gemachte Nachricht wiederherstellen",
"command.session.compact": "Sitzung komprimieren",
-1
View File
@@ -81,7 +81,6 @@ export const dict = {
"command.workspace.toggle.description": "Enable or disable multiple workspaces in the sidebar",
"command.session.undo": "Undo",
"command.session.undo.description": "Undo the last message",
"command.session.undo.gitRequired": "No Git repository detected",
"command.session.redo": "Redo",
"command.session.redo.description": "Redo the last undone message",
"command.session.compact": "Compact session",
-1
View File
@@ -81,7 +81,6 @@ export const dict = {
"command.workspace.toggle.description": "Habilitar o deshabilitar múltiples espacios de trabajo en la barra lateral",
"command.session.undo": "Deshacer",
"command.session.undo.description": "Deshacer el último mensaje",
"command.session.undo.gitRequired": "No se detectó ningún repositorio Git",
"command.session.redo": "Rehacer",
"command.session.redo.description": "Rehacer el último mensaje deshecho",
"command.session.compact": "Compactar sesión",
-1
View File
@@ -75,7 +75,6 @@ export const dict = {
"command.workspace.toggle.description": "Activer ou désactiver plusieurs espaces de travail dans la barre latérale",
"command.session.undo": "Annuler",
"command.session.undo.description": "Annuler le dernier message",
"command.session.undo.gitRequired": "Aucun dépôt Git détecté",
"command.session.redo": "Rétablir",
"command.session.redo.description": "Rétablir le dernier message annulé",
"command.session.compact": "Compacter la session",
-1
View File
@@ -75,7 +75,6 @@ export const dict = {
"command.workspace.toggle.description": "サイドバーでの複数のワークスペースの有効化・無効化",
"command.session.undo": "元に戻す",
"command.session.undo.description": "最後のメッセージを元に戻す",
"command.session.undo.gitRequired": "Git リポジトリが検出されませんでした",
"command.session.redo": "やり直す",
"command.session.redo.description": "元に戻したメッセージをやり直す",
"command.session.compact": "セッションを圧縮",
-1
View File
@@ -71,7 +71,6 @@ export const dict = {
"command.workspace.toggle.description": "사이드바에서 다중 작업 공간 활성화 또는 비활성화",
"command.session.undo": "실행 취소",
"command.session.undo.description": "마지막 메시지 실행 취소",
"command.session.undo.gitRequired": "Git 저장소가 감지되지 않았습니다",
"command.session.redo": "다시 실행",
"command.session.redo.description": "마지막 실행 취소된 메시지 다시 실행",
"command.session.compact": "세션 압축",
-1
View File
@@ -80,7 +80,6 @@ export const dict = {
"command.workspace.toggle.description": "Aktiver eller deaktiver flere arbeidsområder i sidefeltet",
"command.session.undo": "Angre",
"command.session.undo.description": "Angre siste melding",
"command.session.undo.gitRequired": "Fant ikke noe Git-repositorium",
"command.session.redo": "Gjør om",
"command.session.redo.description": "Gjør om siste angrede melding",
"command.session.compact": "Komprimer sesjon",
-1
View File
@@ -75,7 +75,6 @@ export const dict = {
"command.workspace.toggle.description": "Włącz lub wyłącz wiele przestrzeni roboczych na pasku bocznym",
"command.session.undo": "Cofnij",
"command.session.undo.description": "Cofnij ostatnią wiadomość",
"command.session.undo.gitRequired": "Nie wykryto repozytorium Git",
"command.session.redo": "Ponów",
"command.session.redo.description": "Ponów ostatnią cofniętą wiadomość",
"command.session.compact": "Kompaktuj sesję",
-1
View File
@@ -81,7 +81,6 @@ export const dict = {
"command.workspace.toggle.description": "Включить или отключить несколько рабочих пространств в боковой панели",
"command.session.undo": "Отменить",
"command.session.undo.description": "Отменить последнее сообщение",
"command.session.undo.gitRequired": "Репозиторий Git не обнаружен",
"command.session.redo": "Повторить",
"command.session.redo.description": "Повторить отменённое сообщение",
"command.session.compact": "Сжать сессию",
-1
View File
@@ -81,7 +81,6 @@ export const dict = {
"command.workspace.toggle.description": "เปิดหรือปิดใช้งานพื้นที่ทำงานหลายรายการในแถบด้านข้าง",
"command.session.undo": "ยกเลิก",
"command.session.undo.description": "ยกเลิกข้อความล่าสุด",
"command.session.undo.gitRequired": "ไม่พบที่เก็บ Git",
"command.session.redo": "ทำซ้ำ",
"command.session.redo.description": "ทำซ้ำข้อความที่ถูกยกเลิกล่าสุด",
"command.session.compact": "บีบอัดเซสชัน",
-1
View File
@@ -85,7 +85,6 @@ export const dict = {
"command.workspace.toggle.description": "Kenar çubuğunda birden fazla çalışma alanını göster veya gizle",
"command.session.undo": "Geri al",
"command.session.undo.description": "Son mesajı geri al",
"command.session.undo.gitRequired": "Git deposu algılanmadı",
"command.session.redo": "Yinele",
"command.session.redo.description": "Son geri alınan mesajı yinele",
"command.session.compact": "Oturumu sıkıştır",
-1
View File
@@ -81,7 +81,6 @@ export const dict = {
"command.workspace.toggle.description": "Увімкнути або вимкнути декілька робочих областей на бічній панелі",
"command.session.undo": "Скасувати",
"command.session.undo.description": "Скасувати останнє повідомлення",
"command.session.undo.gitRequired": "Репозиторій Git не виявлено",
"command.session.redo": "Повторити",
"command.session.redo.description": "Повторити останнє скасоване повідомлення",
"command.session.compact": "Стиснути сесію",
-1
View File
@@ -108,7 +108,6 @@ export const dict = {
"command.session.undo": "撤销",
"command.session.undo.description": "撤销上一条消息",
"command.session.undo.gitRequired": "未检测到 Git 仓库",
"command.session.redo": "重做",
"command.session.redo.description": "重做上一条撤销的消息",
"command.session.compact": "精简会话",
-1
View File
@@ -85,7 +85,6 @@ export const dict = {
"command.workspace.toggle.description": "在側邊欄啟用或停用多個工作區",
"command.session.undo": "復原",
"command.session.undo.description": "復原上一則訊息",
"command.session.undo.gitRequired": "未偵測到 Git 儲存庫",
"command.session.redo": "重做",
"command.session.redo.description": "重做上一則復原的訊息",
"command.session.compact": "精簡工作階段",
+4 -16
View File
@@ -92,7 +92,6 @@ import { TerminalPanel } from "@/pages/session/terminal-panel"
import { TerminalPanelV2 } from "@/pages/session/terminal-panel-v2"
import { useComposerCommands } from "@/pages/session/use-composer-commands"
import { useSessionCommands } from "@/pages/session/use-session-commands"
import { supportsSessionHistory } from "@/pages/session/session-history-actions"
import { useSessionHashScroll } from "@/pages/session/use-session-hash-scroll"
import { Identifier } from "@/utils/id"
import { diffs as list } from "@/utils/diffs"
@@ -651,7 +650,6 @@ export default function Page() {
}, desktopReviewOpen())
const turnDiffs = createMemo(() => list(lastUserMessage()?.summary?.diffs))
const git = createMemo(() => supportsSessionHistory(sync().project?.vcs))
const nogit = createMemo(() => {
const project = sync().project
return !!project && project.vcs !== "git"
@@ -1917,12 +1915,12 @@ export default function Page() {
const restoring = createMemo(() => (restoreMutation.isPending ? restoreMutation.variables : undefined))
const revert = (input: { sessionID: string; messageID: string }) => {
if (reverting() || !git()) return
if (reverting()) return
return revertMutation.mutateAsync(input)
}
const restore = (id: string) => {
if (!params.id || reverting() || !git()) return
if (!params.id || reverting()) return
return restoreMutation.mutateAsync(id)
}
@@ -1957,16 +1955,7 @@ export default function Page() {
download()
}
const actions = {
revert,
get revertDisabled() {
return !git()
},
get revertDisabledReason() {
return nogit() ? language.t("command.session.undo.gitRequired") : undefined
},
openAttachment,
}
const actions = { revert, openAttachment }
createEffect(() => {
const sessionID = params.id
@@ -2198,8 +2187,7 @@ export default function Page() {
? {
items: rolled(),
restoring: restoring(),
disabled: reverting() || !git(),
disabledReason: nogit() ? language.t("command.session.undo.gitRequired") : undefined,
disabled: reverting(),
onRestore: restore,
}
: undefined,
@@ -18,7 +18,6 @@ export type SessionComposerRevertDock = {
items: { id: string; text: string }[]
restoring?: string
disabled?: boolean
disabledReason?: string
onRestore: (id: string) => void
}
@@ -93,7 +93,6 @@ export function SessionComposerRegion(props: {
items={revert.items}
restoring={revert.restoring}
disabled={revert.disabled}
disabledReason={revert.disabledReason}
onRestore={revert.onRestore}
/>
</div>
@@ -119,7 +118,6 @@ export function SessionComposerRegion(props: {
items={revert.items}
restoring={revert.restoring}
disabled={revert.disabled}
disabledReason={revert.disabledReason}
onRestore={revert.onRestore}
/>
</div>
@@ -6,8 +6,6 @@ import { IconButton } from "@opencode-ai/ui/icon-button"
import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2"
import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon"
import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
import { Tooltip } from "@opencode-ai/ui/tooltip"
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
import { useLanguage } from "@/context/language"
import { useSettings } from "@/context/settings"
@@ -15,7 +13,6 @@ export function SessionRevertDock(props: {
items: { id: string; text: string }[]
restoring?: string
disabled?: boolean
disabledReason?: string
onRestore: (id: string) => void
}) {
const language = useLanguage()
@@ -92,17 +89,15 @@ export function SessionRevertDock(props: {
{(item) => (
<div class="flex items-center gap-2 min-w-0 py-1">
<span class="min-w-0 flex-1 truncate text-13-regular text-text-strong">{item.text}</span>
<Tooltip inactive={!props.disabledReason} value={props.disabledReason} placement="top">
<Button
size="small"
variant="secondary"
class="shrink-0"
disabled={props.disabled || !!props.restoring}
onClick={() => props.onRestore(item.id)}
>
{language.t("session.revertDock.restore")}
</Button>
</Tooltip>
<Button
size="small"
variant="secondary"
class="shrink-0"
disabled={props.disabled || !!props.restoring}
onClick={() => props.onRestore(item.id)}
>
{language.t("session.revertDock.restore")}
</Button>
</div>
)}
</For>
@@ -172,17 +167,15 @@ export function SessionRevertDock(props: {
<span class="min-w-0 flex-1 truncate text-[13px] font-[400] leading-5 tracking-[-0.04px] text-v2-text-text-muted">
{item.text}
</span>
<TooltipV2 inactive={!props.disabledReason} value={props.disabledReason} placement="top">
<ButtonV2
size="small"
variant="neutral"
class="shrink-0"
disabled={props.disabled || !!props.restoring}
onClick={() => props.onRestore(item.id)}
>
{language.t("session.revertDock.restore")}
</ButtonV2>
</TooltipV2>
<ButtonV2
size="small"
variant="neutral"
class="shrink-0"
disabled={props.disabled || !!props.restoring}
onClick={() => props.onRestore(item.id)}
>
{language.t("session.revertDock.restore")}
</ButtonV2>
</div>
)}
</For>
@@ -1,28 +0,0 @@
import { describe, expect, test } from "bun:test"
import { commandPaletteOptions } from "@/context/command"
import { sessionHistoryActions } from "./session-history-actions"
describe("sessionHistoryActions", () => {
test("enables session history actions for Git projects", () => {
expect(
sessionHistoryActions({
vcs: "git",
sessionID: "session-1",
hasVisibleUserMessage: true,
hasRevert: true,
}),
).toEqual({ undo: true, redo: true, revert: true })
})
test("disables session history actions for non-Git projects", () => {
const actions = sessionHistoryActions({
vcs: undefined,
sessionID: "session-1",
hasVisibleUserMessage: true,
hasRevert: true,
})
expect(actions).toEqual({ undo: false, redo: false, revert: false })
expect(commandPaletteOptions([{ id: "session.undo", title: "Undo", disabled: !actions.undo }])).toEqual([])
})
})
@@ -1,17 +0,0 @@
export function supportsSessionHistory(vcs?: string) {
return vcs === "git"
}
export function sessionHistoryActions(input: {
vcs?: string
sessionID?: string
hasVisibleUserMessage: boolean
hasRevert: boolean
}) {
const git = supportsSessionHistory(input.vcs)
return {
undo: git && !!input.sessionID && input.hasVisibleUserMessage,
redo: git && !!input.sessionID && input.hasRevert,
revert: git,
}
}
@@ -19,7 +19,6 @@ import { extractPromptFromParts } from "@/utils/prompt"
import { UserMessage } from "@opencode-ai/sdk/v2"
import { useSessionLayout } from "@/pages/session/session-layout"
import { createSessionOwnership } from "./session-ownership"
import { sessionHistoryActions } from "./session-history-actions"
export type SessionCommandContext = {
navigateMessageByOffset: (offset: number) => void
@@ -102,13 +101,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
if (!revert) return userMessages()
return userMessages().filter((m) => m.id < revert)
}
const historyActions = () =>
sessionHistoryActions({
vcs: sync().project?.vcs,
sessionID: params.id,
hasVisibleUserMessage: visibleUserMessages().length > 0,
hasRevert: !!info()?.revert?.messageID,
})
const showAllFiles = () => {
if (layout.fileTree.tab() !== "changes") return
@@ -311,7 +303,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
}
const undo = async () => {
if (!historyActions().undo) return
const sessionID = params.id
if (!sessionID) return
const owner = sessionOwnership.capture()
@@ -340,7 +331,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
}
const redo = async () => {
if (!historyActions().redo) return
const sessionID = params.id
if (!sessionID) return
const owner = sessionOwnership.capture()
@@ -440,12 +430,9 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
sessionCommand({
id: "session.undo",
title: language.t("command.session.undo"),
description:
sync().project && sync().project?.vcs !== "git"
? language.t("command.session.undo.gitRequired")
: language.t("command.session.undo.description"),
description: language.t("command.session.undo.description"),
slash: "undo",
disabled: !historyActions().undo,
disabled: !params.id || visibleUserMessages().length === 0,
onSelect: undo,
}),
sessionCommand({
@@ -453,7 +440,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
title: language.t("command.session.redo"),
description: language.t("command.session.redo.description"),
slash: "redo",
disabled: !historyActions().redo,
disabled: !params.id || !info()?.revert?.messageID,
onSelect: redo,
}),
sessionCommand({
+1 -10
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env bun
import { $ } from "bun"
import fs from "fs"
import { rm } from "fs/promises"
import path from "path"
import { Script } from "@opencode-ai/script"
@@ -51,10 +50,6 @@ const targets = singleFlag
if (!skipInstall) await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}`
const localParserWorker = path.resolve(dir, "node_modules/@opentui/core/parser.worker.js")
const rootParserWorker = path.resolve(dir, "../../node_modules/@opentui/core/parser.worker.js")
const parserWorker = fs.realpathSync(fs.existsSync(localParserWorker) ? localParserWorker : rootParserWorker)
for (const item of targets) {
const target = [
binary,
@@ -68,7 +63,7 @@ for (const item of targets) {
const name = target.replace(binary, "cli")
console.log(`building ${name}`)
const result = await Bun.build({
entrypoints: ["./src/index.ts", parserWorker],
entrypoints: ["./src/index.ts"],
tsconfig: "./tsconfig.json",
plugins: [plugin],
external: ["node-gyp"],
@@ -94,10 +89,6 @@ for (const item of targets) {
OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "undefined",
// FFF_LIBC selects the fff native lib variant: "musl" or "gnu".
FFF_LIBC: item.os === "linux" ? `'${item.abi ?? "gnu"}'` : "undefined",
OTUI_TREE_SITTER_WORKER_PATH:
(item.os === "win32" ? '"B:/~BUN/root/' : '"/$bunfs/root/') +
path.relative(dir, parserWorker).replaceAll("\\", "/") +
'"',
...(item.os === "linux" ? { "process.env.OPENTUI_LIBC": JSON.stringify(item.abi ?? "glibc") } : {}),
},
})
+13 -10
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env bun
import { $ } from "bun"
import fs from "fs"
import path from "path"
import { fileURLToPath } from "url"
import { createSolidTransformPlugin } from "@opentui/solid/bun-plugin"
@@ -49,6 +48,7 @@ const createEmbeddedWebUIBundle = async () => {
}
const embeddedFileMap = skipEmbedWebUi ? null : await createEmbeddedWebUIBundle()
const treeSitterWorker = await Bun.file(fileURLToPath(import.meta.resolve("@opentui/core/parser.worker"))).text()
const allTargets: {
os: string
@@ -156,14 +156,9 @@ for (const item of targets) {
console.log(`building ${name}`)
await $`mkdir -p dist/${name}/bin`
const localPath = path.resolve(dir, "node_modules/@opentui/core/parser.worker.js")
const rootPath = path.resolve(dir, "../../node_modules/@opentui/core/parser.worker.js")
const parserWorker = fs.realpathSync(fs.existsSync(localPath) ? localPath : rootPath)
const workerPath = "./src/cli/tui/worker.ts"
// Use platform-specific bunfs root path based on target OS
const treeSitterWorkerPath = "opentui-tree-sitter-worker.js"
const bunfsRoot = item.os === "win32" ? "B:/~BUN/root/" : "/$bunfs/root/"
const workerRelativePath = path.relative(dir, parserWorker).replaceAll("\\", "/")
await Bun.build({
conditions: ["bun", "node"],
@@ -184,13 +179,21 @@ for (const item of targets) {
execArgv: [`--user-agent=opencode/${Script.version}`, "--use-system-ca", "--"],
windows: {},
},
files: embeddedFileMap ? { "opencode-web-ui.gen.ts": embeddedFileMap } : {},
entrypoints: ["./src/index.ts", parserWorker, workerPath, ...(embeddedFileMap ? ["opencode-web-ui.gen.ts"] : [])],
files: {
[treeSitterWorkerPath]: treeSitterWorker,
...(embeddedFileMap ? { "opencode-web-ui.gen.ts": embeddedFileMap } : {}),
},
entrypoints: [
"./src/index.ts",
workerPath,
treeSitterWorkerPath,
...(embeddedFileMap ? ["opencode-web-ui.gen.ts"] : []),
],
define: {
FFF_LIBC: JSON.stringify(item.abi === "musl" ? "musl" : "gnu"),
OPENCODE_VERSION: `'${Script.version}'`,
OPENCODE_MODELS_DEV: generated.modelsData,
OTUI_TREE_SITTER_WORKER_PATH: bunfsRoot + workerRelativePath,
OTUI_TREE_SITTER_WORKER_PATH: bunfsRoot + treeSitterWorkerPath,
OPENCODE_WORKER_PATH: workerPath,
OPENCODE_CHANNEL: `'${Script.channel}'`,
OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "",
@@ -178,8 +178,6 @@ export type SessionAction = (input: { sessionID: string; messageID: string }) =>
export type UserActions = {
fork?: SessionAction
revert?: SessionAction
revertDisabled?: boolean
revertDisabledReason?: JSX.Element
openAttachment?: (file: FilePart) => void
}
@@ -1382,9 +1380,9 @@ export function UserMessageDisplay(props: {
<Show when={props.actions?.revert}>
<MessageActionButton
icon="reset"
label={props.actions?.revertDisabledReason ?? i18n.t("ui.message.revertMessage")}
label={i18n.t("ui.message.revertMessage")}
useV2={props.useV2Actions}
disabled={!!busy() || props.actions?.revertDisabled}
disabled={!!busy()}
onMouseDown={(event) => event.preventDefault()}
onClick={(event) => {
event.stopPropagation()
@@ -165,15 +165,11 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
}
const prev = () => {
const files = props.files
if (files.length === 0) return
return files[(fileIndex() - 1 + files.length) % files.length]
return props.files[fileIndex() - 1]
}
const next = () => {
const files = props.files
if (files.length === 0) return
return files[(fileIndex() + 1) % files.length]
return props.files[fileIndex() + 1]
}
const canCycle = () => props.files.length > 0
@@ -195,8 +191,10 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
const target = event.target
if (target instanceof HTMLElement && (target.isContentEditable || target.closest("input, textarea, select"))) return
if (!props.hasDiffs || !canCycle()) return
const file = event.key === "<" ? prev() : next()
if (!file) return
event.preventDefault()
cycle(event.key === "<" ? prev() : next())
cycle(file)
})
const toolbarStart = () => (
@@ -217,6 +215,7 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
<div class="flex items-center">
<TooltipV2
openDelay={2000}
inactive={!prev()}
value={
<>
{i18n.t("ui.sessionReviewV2.previousFile")}
@@ -229,13 +228,14 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
variant="ghost"
size="small"
class="session-review-v2-file-nav-button"
disabled={!canCycle()}
disabled={!prev()}
onClick={() => cycle(prev())}
aria-label={i18n.t("ui.sessionReviewV2.previousFile")}
/>
</TooltipV2>
<TooltipV2
openDelay={2000}
inactive={!next()}
value={
<>
{i18n.t("ui.sessionReviewV2.nextFile")}
@@ -248,7 +248,7 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
variant="ghost"
size="small"
class="session-review-v2-file-nav-button"
disabled={!canCycle()}
disabled={!next()}
onClick={() => cycle(next())}
aria-label={i18n.t("ui.sessionReviewV2.nextFile")}
/>
+6 -9
View File
@@ -160,21 +160,18 @@ async function fixKnownLockfileIssues() {
if (stale.length === 0) return []
if (stale.some((item) => !item.entry.startsWith("opentui-spinner/@opentui/"))) return []
const lines = txt.split("\n")
const spinnerEntry = /^ "(opentui-spinner\/@opentui\/[^"]+)": \[.*\],\r?$/
const removed = lines
.map((line) => line.match(spinnerEntry)?.[1])
const removed = txt
.split("\n")
.map((line) => line.match(/^ "(opentui-spinner\/@opentui\/[^\"]+)": /)?.[1])
.filter((item): item is string => item !== undefined)
if (removed.length === 0) return []
// Bun separates package records with a blank line, so remove each record's separator with it.
await Bun.write(
lockfile,
lines
.filter(
(line, index) => !spinnerEntry.test(line) && !(line.trim() === "" && spinnerEntry.test(lines[index - 1] ?? "")),
)
txt
.split("\n")
.filter((line) => !line.match(/^ "opentui-spinner\/@opentui\//))
.join("\n"),
)
return removed