UNPKG

relay-companion

Version:

Install Relay for Claude Code, Cowork, and Codex, then sign in from the Relay pill.

45 lines (42 loc) • 2.27 kB
function timestampMs(value) { const ms = Date.parse(String(value || "")); return Number.isFinite(ms) ? ms : null; } /** * Return only the provider's current turn from a newest-first transcript. * Task receipts can be hours older than a retried/follow-up native turn, * so they are deliberately not accepted as timing inputs here. */ export function nativeTurn(records, { terminalAt = null } = {}) { const rows = Array.isArray(records) ? records.filter(Boolean) : []; // Claude writes Monitor/background-task notifications as synthetic `user` // messages. They are events inside the current turn, not a new human turn. // Cutting at the newest one hid every preceding tool call and assistant // update, leaving the live runner with only “Reading the request.” const newestUser = rows.findIndex((row) => { if (row.type !== "message" || row.role !== "user") return false; return !/^\s*<task-notification\b/i.test(String(row.text || "")); }); const current = newestUser >= 0 ? rows.slice(0, newestUser + 1) : rows; const startAt = newestUser >= 0 ? current[newestUser]?.at || null : null; const startMs = timestampMs(startAt); const nativeTimes = current.map((row) => timestampMs(row.at)).filter((ms) => ms !== null); const terminalMs = timestampMs(terminalAt); const endMs = terminalMs !== null && (startMs === null || terminalMs >= startMs) ? terminalMs : nativeTimes.length ? Math.max(...nativeTimes) : null; const endAt = endMs === null ? null : new Date(endMs).toISOString(); const durationMs = startMs !== null && endMs !== null && endMs >= startMs ? endMs - startMs : null; return { records: current, startedAt: startAt, completedAt: endAt, durationMs }; } export function humanDuration(durationMs) { if (!Number.isFinite(durationMs) || durationMs < 0) return ""; const seconds = Math.max(1, Math.round(durationMs / 1000)); if (seconds < 60) return `${seconds} sec`; const minutes = Math.floor(seconds / 60); const remainder = seconds % 60; if (minutes < 60) return remainder ? `${minutes} min ${remainder} sec` : `${minutes} min`; const hours = Math.floor(minutes / 60); const minuteRemainder = minutes % 60; return minuteRemainder ? `${hours} h ${minuteRemainder} min` : `${hours} h`; }