cloudaxe-opencode/packages/tui/src/feature-plugins/session/util.tsx

54 lines
2 KiB
TypeScript

import type { Part } from "@opencode-ai/sdk/v2"
import { Locale } from "../../util/locale"
export function relativeTime(timestamp: number): string {
const diff = Date.now() - timestamp
if (diff < 0) return "just now"
const seconds = Math.floor(diff / 1000)
if (seconds < 60) return "just now"
const minutes = Math.floor(seconds / 60)
if (minutes < 60) return `${minutes}m ago`
const hours = Math.floor(minutes / 60)
if (hours < 24) return `${hours}h ago`
const days = Math.floor(hours / 24)
if (days < 7) return `${days}d ago`
const d = new Date(timestamp)
return d.toLocaleDateString(undefined, { month: "short", day: "numeric" })
}
export function extractMessageText(parts: readonly Part[], maxLength: number): string {
const joined = collectTextParts(parts).join(" ").replace(/\s+/g, " ").trim()
return Locale.truncate(joined, maxLength)
}
export function extractMessageMarkdown(parts: readonly Part[], maxLines: number, maxChars: number): string {
const joined = collectTextParts(parts).join("\n\n").trim()
if (!joined) return joined
let truncated = joined
const lines = truncated.split("\n")
if (lines.length > maxLines) {
truncated = lines.slice(0, maxLines).join("\n")
}
if (truncated.length > maxChars) {
truncated = truncated.slice(0, maxChars).trimEnd()
}
if (truncated.length === joined.length) return joined
// Close any unterminated fenced code block so the renderer doesn't keep
// the rest of the panel in "code mode".
const fences = (truncated.match(/^```/gm) ?? []).length
if (fences % 2 === 1) truncated += "\n```"
return truncated + "\n\n…"
}
function collectTextParts(parts: readonly Part[]): string[] {
const chunks: string[] = []
for (const part of parts) {
if (part.type !== "text") continue
const p = part as Part & { type: "text"; text: string; synthetic?: boolean; ignored?: boolean }
if (p.synthetic || p.ignored) continue
if (!p.text) continue
chunks.push(p.text)
}
return chunks
}