import { formatDurationPrecise } from "../infra/format-time/format-duration.ts" ;
import { formatRuntimeStatusWithDetails } from "../infra/runtime-status.ts" ;
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js" ;
import type { SessionStatus } from "./status.types.js" ;
export { shortenText } from "./text-format.js" ;
export const formatKTokens = (value: number) =>
`${(value / 1000 ).toFixed(value >= 10 _000 ? 0 : 1 )}k`;
export const formatDuration = (ms: number | null | undefined) => {
if (ms == null || !Number.isFinite(ms)) {
return "unknown" ;
}
return formatDurationPrecise(ms, { decimals: 1 });
};
export const formatTokensCompact = (
sess: Pick<
SessionStatus,
"inputTokens" | "totalTokens" | "contextTokens" | "percentUsed" | "cacheRead" | "cacheWrite"
>,
) => {
const used = sess.totalTokens;
const ctx = sess.contextTokens;
let result = "" ;
if (used == null ) {
result = ctx ? `unknown/${formatKTokens(ctx)} (?%)` : "unknown used" ;
} else if (!ctx) {
result = `${formatKTokens(used)} used`;
} else {
const pctLabel = sess.percentUsed != null ? `${sess.percentUsed}%` : "?%" ;
result = `${formatKTokens(used)}/${formatKTokens(ctx)} (${pctLabel})`;
}
const cacheStats = resolvePromptCacheStats(sess);
if (cacheStats && cacheStats.cacheRead > 0 ) {
result += ` · ️ ${cacheStats.hitRate}% cached`;
}
return result;
};
export const formatPromptCacheCompact = (
sess: Pick<SessionStatus, "inputTokens" | "totalTokens" | "cacheRead" | "cacheWrite" >,
) => {
const cacheStats = resolvePromptCacheStats(sess);
if (!cacheStats) {
return "" ;
}
const parts = [`${cacheStats.hitRate}% hit`];
if (cacheStats.cacheRead > 0 ) {
parts.push(`read ${formatKTokens(cacheStats.cacheRead)}`);
}
if (cacheStats.cacheWrite > 0 ) {
parts.push(`write ${formatKTokens(cacheStats.cacheWrite)}`);
}
return parts.join(" · " );
};
function resolvePromptCacheStats(
sess: Pick<SessionStatus, "inputTokens" | "totalTokens" | "cacheRead" | "cacheWrite" >,
) {
const cacheRead =
typeof sess.cacheRead === "number" && Number.isFinite(sess.cacheRead) && sess.cacheRead >= 0
? sess.cacheRead
: 0 ;
const cacheWrite =
typeof sess.cacheWrite === "number" && Number.isFinite(sess.cacheWrite) && sess.cacheWrite >= 0
? sess.cacheWrite
: 0 ;
if (cacheRead <= 0 && cacheWrite <= 0 ) {
return null ;
}
const inputTokens =
typeof sess.inputTokens === "number" &&
Number.isFinite(sess.inputTokens) &&
sess.inputTokens >= 0
? sess.inputTokens
: undefined;
const promptTokensFromParts =
inputTokens != null ? inputTokens + cacheRead + cacheWrite : undefined;
const used = sess.totalTokens;
// Legacy entries can carry an undersized totalTokens value. Keep the cache
// denominator aligned with the prompt-side token fields when available, and
// never let the fallback denominator drop below the known cached prompt
// tokens.
const total =
promptTokensFromParts ??
(typeof used === "number" && Number.isFinite(used) && used > 0
? Math.max(used, cacheRead + cacheWrite)
: cacheRead + cacheWrite);
return {
cacheRead,
cacheWrite,
hitRate: total > 0 ? Math.round((cacheRead / total) * 100 ) : 0 ,
};
}
export const formatDaemonRuntimeShort = (runtime?: {
status?: string;
pid?: number;
state?: string;
detail?: string;
missingUnit?: boolean ;
}) => {
if (!runtime) {
return null ;
}
const details: string[] = [];
const detail = runtime.detail?.replace(/\s+/g, " " ).trim() || "" ;
const noisyLaunchctlDetail =
runtime.missingUnit === true &&
normalizeLowercaseStringOrEmpty(detail).includes("could not find service" );
if (detail && !noisyLaunchctlDetail) {
details.push(detail);
}
return formatRuntimeStatusWithDetails({
status: runtime.status,
pid: runtime.pid,
state: runtime.state,
details,
});
};
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland