summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--nix/hashes.json2
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/index.tsx33
-rw-r--r--packages/opencode/src/util/locale.ts24
3 files changed, 54 insertions, 5 deletions
diff --git a/nix/hashes.json b/nix/hashes.json
index c91afa86e..7f089c7e0 100644
--- a/nix/hashes.json
+++ b/nix/hashes.json
@@ -1,3 +1,3 @@
{
- "nodeModules": "sha256-krj85tYW0P/YOnsXnO1cD5XkLtfWZzdXzj7CTNvsPPk="
+ "nodeModules": "sha256-N33FQyKF6IgGIRZ8NFd9o1/sjHMwbQ6KQcnMFyN0WmI="
}
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
index 43b8cc9de..f5224b2f9 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
@@ -79,6 +79,7 @@ const context = createContext<{
width: number
conceal: () => boolean
showThinking: () => boolean
+ showTimestamps: () => boolean
}>()
function use() {
@@ -109,6 +110,7 @@ export function Session() {
const [sidebar, setSidebar] = createSignal<"show" | "hide" | "auto">(kv.get("sidebar", "auto"))
const [conceal, setConceal] = createSignal(true)
const [showThinking, setShowThinking] = createSignal(true)
+ const [showTimestamps, setShowTimestamps] = createSignal(kv.get("timestamps", "hide") === "show")
const wide = createMemo(() => dimensions().width > 120)
const sidebarVisible = createMemo(() => sidebar() === "show" || (sidebar() === "auto" && wide()))
@@ -404,6 +406,19 @@ export function Session() {
},
},
{
+ title: "Toggle timestamps",
+ value: "session.toggle.timestamps",
+ category: "Session",
+ onSelect: (dialog) => {
+ setShowTimestamps((prev) => {
+ const next = !prev
+ kv.set("timestamps", next ? "show" : "hide")
+ return next
+ })
+ dialog.clear()
+ },
+ },
+ {
title: "Toggle thinking blocks",
value: "session.toggle.thinking",
category: "Session",
@@ -712,6 +727,7 @@ export function Session() {
},
conceal,
showThinking,
+ showTimestamps,
}}
>
<box flexDirection="row" paddingBottom={1} paddingTop={1} paddingLeft={2} paddingRight={2} gap={2}>
@@ -891,6 +907,7 @@ function UserMessage(props: {
index: number
pending?: string
}) {
+ const ctx = use()
const text = createMemo(() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0])
const files = createMemo(() => props.parts.flatMap((x) => (x.type === "file" ? [x] : [])))
const sync = useSync()
@@ -949,7 +966,13 @@ function UserMessage(props: {
{sync.data.config.username ?? "You"}{" "}
<Show
when={queued()}
- fallback={<span style={{ fg: theme.textMuted }}>{Locale.time(props.message.time.created)}</span>}
+ fallback={
+ <span style={{ fg: theme.textMuted }}>
+ {ctx.showTimestamps()
+ ? `· ${Locale.todayTimeOrDateTime(props.message.time.created)}`
+ : `· ${Locale.time(props.message.time.created)}`}
+ </span>
+ }
>
<span style={{ bg: theme.accent, fg: theme.backgroundPanel, bold: true }}> QUEUED </span>
</Show>
@@ -973,6 +996,7 @@ function UserMessage(props: {
function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; last: boolean }) {
const local = useLocal()
const { theme } = useTheme()
+ const ctx = use()
return (
<>
<For each={props.parts}>
@@ -1015,7 +1039,12 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
<box paddingLeft={3}>
<text marginTop={1}>
<span style={{ fg: local.agent.color(props.message.mode) }}>{Locale.titlecase(props.message.mode)}</span>{" "}
- <span style={{ fg: theme.textMuted }}>{props.message.modelID}</span>
+ <span style={{ fg: theme.textMuted }}>
+ {props.message.modelID}
+ {ctx.showTimestamps() &&
+ props.message.time.completed &&
+ ` · ${Locale.todayTimeOrDateTime(props.message.time.completed)}`}
+ </span>
</text>
</box>
</Match>
diff --git a/packages/opencode/src/util/locale.ts b/packages/opencode/src/util/locale.ts
index ab2623271..e567d5763 100644
--- a/packages/opencode/src/util/locale.ts
+++ b/packages/opencode/src/util/locale.ts
@@ -3,9 +3,29 @@ export namespace Locale {
return str.replace(/\b\w/g, (c) => c.toUpperCase())
}
- export function time(input: number) {
+ export function time(input: number): string {
const date = new Date(input)
- return date.toLocaleTimeString()
+ return date.toLocaleTimeString(undefined, { timeStyle: "short" })
+ }
+
+ export function datetime(input: number): string {
+ const date = new Date(input)
+ const localTime = time(input)
+ const localDate = date.toLocaleDateString()
+ return `${localTime} · ${localDate}`
+ }
+
+ export function todayTimeOrDateTime(input: number): string {
+ const date = new Date(input)
+ const now = new Date()
+ const isToday =
+ date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate()
+
+ if (isToday) {
+ return time(input)
+ } else {
+ return datetime(input)
+ }
}
export function number(num: number): string {