import type { SessionInfo } from "../types.ts"; const ANSI_SEQUENCE = /[\u001b\u009b](?:\][^\u0007]*(?:\u0007|\u001b\\)|\[[0-?]*[ -/]*[@-~]|[@-_])/g; const CONTROL_CHARACTER = /[\u0000-\u001f\u007f-\u009f]/g; /** Make untrusted presence metadata safe to place directly in a terminal UI. */ export function sanitizeDisplayText(value: string | undefined, fallback = ""): string { const sanitized = (value ?? "") .replace(ANSI_SEQUENCE, "") .replace(CONTROL_CHARACTER, " ") .replace(/\s+/g, " ") .trim(); return sanitized || fallback; } /** * Return the shortest prefix which distinguishes every ID in the collection. * A small floor keeps isolated IDs useful to humans while still expanding * automatically when UUIDv7 values share a long timestamp prefix. */ export function shortestUniqueIdPrefixes(ids: readonly string[], minimumLength = 4): Map { const uniqueIds = [...new Set(ids)]; const result = new Map(); for (const id of uniqueIds) { let length = Math.min(Math.max(1, minimumLength), id.length); while ( length < id.length && uniqueIds.some(other => other !== id && other.startsWith(id.slice(0, length))) ) { length += 1; } result.set(id, id.slice(0, length)); } return result; } export function searchableSessionText(session: SessionInfo): string { return [session.name, session.id, session.cwd, session.model, session.status] .filter((value): value is string => typeof value === "string") .join("\n") .toLocaleLowerCase(); }