Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/opencode/src/cli/cmd/tui/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,10 @@ export const dict: Record<string, string> = {
// Session badges
"tui.session.badge.auto": "Auto",

// Context rebuild boundary marker (inserted by /rebuild)
"tui.session.rebuild_boundary.label": "context rebuilt",
"tui.session.rebuild_boundary.detail": "earlier messages summarized",

// Workspace trust
"trust.title": "Accessing workspace:",
"trust.safety_check": "Quick safety check: Is this a project you created or one you trust? (Like your own code, a well-known open source project, or work from your team). If not, take a moment to review what's in this folder first.",
Expand Down
4 changes: 4 additions & 0 deletions packages/opencode/src/cli/cmd/tui/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,10 @@ export const dict = {
// Session badges
"tui.session.badge.auto": "自动",

// Context rebuild boundary marker (inserted by /rebuild)
"tui.session.rebuild_boundary.label": "上下文已重建",
"tui.session.rebuild_boundary.detail": "较早消息已摘要",

// Workspace trust
"trust.title": "访问工作区:",
"trust.safety_check": "安全确认:这是你自己创建或信任的项目吗?(如你自己的代码、知名开源项目或团队内部项目)。如果不是,请先检查此目录下的内容。",
Expand Down
4 changes: 4 additions & 0 deletions packages/opencode/src/cli/cmd/tui/i18n/zht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ export const dict = {
// Session badges
"tui.session.badge.auto": "自動",

// Context rebuild boundary marker (inserted by /rebuild)
"tui.session.rebuild_boundary.label": "上下文已重建",
"tui.session.rebuild_boundary.detail": "較早訊息已摘要",

// Workspace trust
"trust.title": "存取工作區:",
"trust.safety_check": "安全確認:這是你自己建立或信任的專案嗎?(如你自己的程式碼、知名開源專案或團隊內部專案)。如果不是,請先檢查此目錄下的內容。",
Expand Down
20 changes: 20 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,16 @@ function UserMessage(props: {
return parsed ? [parsed] : []
})[0]
})
// A context rebuild (`/rebuild`) inserts a single user message carrying a
// `checkpoint` part plus `synthetic: true` text parts (the rendered context
// and index). Neither renders — `checkpoint` has no PART_MAPPING entry and
// synthetic text is excluded from `text()` above — so the boundary used to be
// completely invisible in the transcript, unlike compaction which at least
// leaves a visible summary message behind. Surface it as a one-line marker
// row so the user can see that a rebuild happened and where.
const rebuildBoundary = createMemo(() => props.parts.some((x) => x.type === "checkpoint"))
const { theme } = useTheme()
const t = useLanguage().t
const [hover, setHover] = createSignal(false)
const queued = createMemo(() => props.pending && props.message.id > props.pending)
const color = createMemo(() => local.agent.color(props.message.agent))
Expand Down Expand Up @@ -1603,6 +1612,17 @@ function UserMessage(props: {
)
}}
</Show>
<Show when={rebuildBoundary()}>
<box id={props.message.id} marginTop={props.index === 0 ? 0 : 1} paddingLeft={2} flexDirection="row" gap={1}>
<text fg={theme.textMuted}>
<span style={{ bg: theme.backgroundElement, fg: theme.primary, bold: true }}>
{" "}
⟲ {t("tui.session.rebuild_boundary.label")}{" "}
</span>
<span style={{ fg: theme.textMuted }}> {t("tui.session.rebuild_boundary.detail")}</span>
</text>
</box>
</Show>
<Show when={text() && !actorNotification()}>
<box
id={props.message.id}
Expand Down
31 changes: 31 additions & 0 deletions packages/opencode/test/cli/cmd/tui/rebuild-boundary-marker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { describe, expect, test } from "bun:test"
import { dict as en } from "../../../../src/cli/cmd/tui/i18n/en"
import { dict as zh } from "../../../../src/cli/cmd/tui/i18n/zh"
import { dict as zht } from "../../../../src/cli/cmd/tui/i18n/zht"

// A `/rebuild` inserts one user message carrying a `checkpoint` part plus
// synthetic text parts. The TUI renders it as a one-line marker row in
// UserMessage (routes/session/index.tsx) so the boundary is visible in the
// transcript. The label copy is localized; the marker row would render an empty
// badge if these keys ever went missing, so pin them here.
const KEYS = ["tui.session.rebuild_boundary.label", "tui.session.rebuild_boundary.detail"] as const

describe("rebuild boundary marker copy", () => {
test("english copy names the rebuild and what happened to earlier messages", () => {
expect(en["tui.session.rebuild_boundary.label"]).toBe("context rebuilt")
expect(en["tui.session.rebuild_boundary.detail"]).toBe("earlier messages summarized")
})

test("localized dictionaries define the marker copy", () => {
for (const key of KEYS) {
for (const [name, dict] of Object.entries({ en, zh, zht })) {
expect(dict[key], `${name} is missing ${key}`).toBeTruthy()
}
// Untranslated keys silently fall back to English via the `base` merge in
// context/language.tsx, so an English string here means a missed
// translation rather than a crash — assert it is actually translated.
expect(zh[key]).not.toBe(en[key])
expect(zht[key]).not.toBe(en[key])
}
})
})
Loading