Files
claude-code-haha/desktop/src/lib/trace/formatters.ts
T
程序员阿江-Relakkes 3754d1f2a5 feat(desktop): replace the settings trace list with an in-session trajectory view (#1443)
Sessions get a Chat / Trajectory switch in the header. The trajectory is a
dense one-line-per-event ledger (system prompt, user, injected context such
as skills and system reminders, assistant responses, tool calls) with a
three-lane minimap, turn folding, search, and a detail panel per row.

- CLI: record a deduplicated prompt snapshot sidecar for desktop sessions
  (system prompt, tool catalog, user context) without touching the transcript.
- Server: project transcript records into trajectory rows with bounded,
  cursor-paged reads, live appends, a turn index, row detail by byte range,
  snapshot blobs, and a time-window lookup into the raw trace capture.
- Desktop: windowed ledger, minimap, detail panel with a raw request summary,
  chat <-> trajectory navigation, subagent drill-in.
- Remove the Settings trace list, trace tabs and the standalone trace
  window; migrate persisted trace tabs to session tabs.
2026-10-04 17:14:07 +08:00

52 lines
1.8 KiB
TypeScript

import type { TraceCallUsage } from '../../types/trace'
import { formatTokenCount } from '../formatTokenCount'
import type { NormalizedUsage } from './types'
export { formatTokenCount }
export function formatDurationMs(ms?: number): string {
if (typeof ms !== 'number' || !Number.isFinite(ms) || ms < 0) return '--'
if (ms < 1000) return `${Math.round(ms)}ms`
if (ms < 10_000) return `${(ms / 1000).toFixed(2)}s`
if (ms < 60_000) return `${Math.round(ms / 1000)}s`
const totalSeconds = Math.round(ms / 1000)
const minutes = Math.floor(totalSeconds / 60)
const seconds = totalSeconds % 60
return `${minutes}m ${String(seconds).padStart(2, '0')}s`
}
export function formatUsageBrief(u?: NormalizedUsage | TraceCallUsage): string {
if (!u) return '--'
return `${formatTokenCount(u.inputTokens)} → ${formatTokenCount(u.outputTokens)}`
}
export function formatClockTime(iso: string): string {
const date = new Date(iso)
if (Number.isNaN(date.getTime())) return iso
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })
}
/** Pretty-print a JSON string or value; a non-JSON string passes through unchanged. */
export function formatTraceJson(value: unknown): string {
if (typeof value === 'string') {
const parsed = parseJsonText(value)
return parsed === null ? value : JSON.stringify(parsed, null, 2)
}
try {
// JSON.stringify(undefined) yields undefined, not a string.
return JSON.stringify(value, null, 2) ?? String(value)
} catch {
return String(value)
}
}
function parseJsonText(value: string): unknown | null {
const trimmed = value.trim()
if (!trimmed || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) return null
try {
return JSON.parse(trimmed)
} catch {
return null
}
}