Skip to content
Open
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
26 changes: 26 additions & 0 deletions packages/opencode/src/altimate/observability/tracing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,32 @@ export class Trace {
}
}

/**
* List traces with pagination support.
* Returns a page of traces plus total count for building pagination UI.
*/
static async listTracesPaginated(
dir?: string,
options?: { offset?: number; limit?: number },
): Promise<{
traces: Array<{ sessionId: string; file: string; trace: TraceFile }>
total: number
offset: number
limit: number
}> {
const all = await Trace.listTraces(dir)
const rawOffset = options?.offset ?? 0
const rawLimit = options?.limit ?? 20
const offset = Number.isFinite(rawOffset) ? Math.max(0, Math.trunc(rawOffset)) : 0
const limit = Number.isFinite(rawLimit) ? Math.max(1, Math.trunc(rawLimit)) : 20
return {
traces: all.slice(offset, offset + limit),
total: all.length,
offset,
limit,
}
}

static async loadTrace(sessionId: string, dir?: string): Promise<TraceFile | null> {
const tracesDir = dir ?? DEFAULT_TRACES_DIR
try {
Expand Down
37 changes: 30 additions & 7 deletions packages/opencode/src/cli/cmd/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,23 @@ function truncate(str: string, len: number): string {
}

// altimate_change start — trace: list session traces (recordings/recaps of agent sessions)
function listTraces(traces: Array<{ sessionId: string; trace: TraceFile }>, tracesDir?: string) {
if (traces.length === 0) {
function listTraces(
traces: Array<{ sessionId: string; trace: TraceFile }>,
pagination: { total: number; offset: number; limit: number },
tracesDir?: string,
) {
if (traces.length === 0 && pagination.total === 0) {
UI.println("No traces found. Run a command with tracing enabled:")
UI.println(" altimate-code run \"your prompt here\"")
return
}

if (traces.length === 0 && pagination.total > 0) {
UI.println(`No traces on this page (offset ${pagination.offset} past end of ${pagination.total} traces).`)
UI.println(UI.Style.TEXT_DIM + `Try: altimate-code trace list --offset 0 --limit ${pagination.limit}` + UI.Style.TEXT_NORMAL)
return
}

// Header
const header = [
"DATE".padEnd(13),
Expand Down Expand Up @@ -97,8 +107,13 @@ function listTraces(traces: Array<{ sessionId: string; trace: TraceFile }>, trac
}

UI.empty()
// altimate_change start — trace: session trace messages
UI.println(UI.Style.TEXT_DIM + `${traces.length} trace(s) in ${Trace.getTracesDir(tracesDir)}` + UI.Style.TEXT_NORMAL)
// altimate_change start — trace: session trace messages with pagination footer
const rangeStart = pagination.offset + 1
const rangeEnd = pagination.offset + traces.length
UI.println(UI.Style.TEXT_DIM + `Showing ${rangeStart}-${rangeEnd} of ${pagination.total} trace(s) in ${Trace.getTracesDir(tracesDir)}` + UI.Style.TEXT_NORMAL)
if (rangeEnd < pagination.total) {
UI.println(UI.Style.TEXT_DIM + `Next page: altimate-code trace list --offset ${rangeEnd} --limit ${pagination.limit}` + UI.Style.TEXT_NORMAL)
}
UI.println(UI.Style.TEXT_DIM + "View a trace: altimate-code trace view <session-id>" + UI.Style.TEXT_NORMAL)
// altimate_change end
}
Expand Down Expand Up @@ -134,6 +149,11 @@ export const TraceCommand = cmd({
describe: "number of traces to show",
default: 20,
})
.option("offset", {
type: "number",
describe: "number of traces to skip (for pagination)",
default: 0,
})
.option("live", {
type: "boolean",
describe: "auto-refresh the viewer as the trace updates (for in-progress sessions)",
Expand All @@ -148,8 +168,11 @@ export const TraceCommand = cmd({
const tracesDir = (cfg as any).tracing?.dir as string | undefined

if (action === "list") {
const traces = await Trace.listTraces(tracesDir)
listTraces(traces.slice(0, args.limit || 20), tracesDir)
const page = await Trace.listTracesPaginated(tracesDir, {
offset: args.offset || 0,
limit: args.limit || 20,
})
listTraces(page.traces, page, tracesDir)
return
}

Expand All @@ -168,7 +191,7 @@ export const TraceCommand = cmd({
if (!match) {
UI.error(`Trace not found: ${args.id}`)
UI.println("Available traces:")
listTraces(traces.slice(0, 10), tracesDir)
listTraces(traces.slice(0, 10), { total: traces.length, offset: 0, limit: 10 }, tracesDir)
process.exit(1)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function DialogTraceList(props: {
})
}

result.push(...items.slice(0, 50).map((item) => {
result.push(...items.map((item) => {
const rawStartedAt = item.trace.startedAt
const parsedDate = typeof rawStartedAt === "string" || typeof rawStartedAt === "number"
? new Date(rawStartedAt)
Expand Down
Loading