/** * Shared formatting primitives for `--human` CLI renderers. * * Replaces the hand-rolled `padEnd` columns and Markdown-pipe pseudo-tables * that the renderer audit (T9393-followup) flagged as misaligned, lossy, and * inconsistent across the 65-renderer surface. * * Design goals: * - Terminal-width aware (truncate cells instead of overflowing) * - Zero new runtime dependencies (no `cli-table` etc.) — uses only ANSI * escapes from {@link ./ansi.ts}. * - Pure: every helper returns a string; no stdout writes. * - LAFS-aware: {@link metaFooter} surfaces decorator-stamped * `meta._nexus`, `meta.deprecated`, and `meta.duration_ms` chrome that * would otherwise vanish in human mode. * - Pagination-aware: {@link pagerFooter} formats the `page.{limit,offset, * hasMore,total}` block so users know a list is windowed. * * Originally lived under `packages/cleo/src/cli/renderers/format-helpers.ts`. * Migrated to `@cleocode/core/render` per AGENTS.md Package-Boundary Check — * rendering logic belongs in core, not the CLI thin shell. * * @task T9393 * @task T10129 */ /** * Best-effort terminal width. Falls back to 100 columns when stdout is not a * TTY (CI logs, pipes) so output remains readable. Never returns < 40. */ export declare function terminalWidth(): number; /** Length of a string ignoring ANSI escape codes. */ export declare function visibleLength(s: string): number; /** Right-pad a string to `width` visible columns, ignoring embedded ANSI. */ export declare function padVisible(s: string, width: number): string; /** * Truncate a string to at most `max` visible columns, appending `…` when * truncation occurs. ANSI escape codes are preserved (no mid-escape splits). */ export declare function truncateVisible(s: string, max: number): string; /** * Render a key/value list with colons aligned to the longest key. * * @example * kvBlock([['Status', 'pending'], ['Priority', 'high']]) * // Status: pending * // Priority: high */ export declare function kvBlock(rows: Array<[string, string]>, indent?: number): string; /** * Render a section header line like `Acceptance Criteria (4)`. * Used to break up long task-show / nexus-context blocks. */ export declare function sectionHeader(label: string, count?: number): string; export interface DataTableColumn> { /** Column header label. */ header: string; /** Accessor: row -> cell string (already formatted; may contain ANSI). */ get: (row: T, index: number) => string; /** Optional max width for this column (cell + header). Defaults to no cap. */ maxWidth?: number; /** Optional minimum width (header is always at least its own length). */ minWidth?: number; } export interface DataTableOptions { /** Top-line indent in spaces. Defaults to 2. */ indent?: number; /** Maximum total table width. Defaults to terminal width. */ totalWidth?: number; /** Column separator. Defaults to two spaces. */ separator?: string; /** Show header row. Defaults to true. */ showHeader?: boolean; } /** * Render an aligned ASCII table. Each column auto-sizes to its widest cell, * capped by `maxWidth` and the overall terminal width. Cells too wide for * their column are truncated with an ellipsis. * * @example * dataTable(tasks, [ * { header: 'ID', get: (t) => String(t.id), maxWidth: 12 }, * { header: 'Status', get: (t) => String(t.status), maxWidth: 10 }, * { header: 'Title', get: (t) => String(t.title) }, * ]) */ export declare function dataTable(rows: ReadonlyArray, columns: ReadonlyArray>, opts?: DataTableOptions): string; export interface PagerInput { /** Number of items in the current response payload. */ shown: number; /** LAFS `page` block from envelope, if present. */ page?: { mode?: string; limit?: number; offset?: number; hasMore?: boolean; total?: number; } | null; /** Top-level `total` field on the data payload (alternative to page.total). */ total?: number; /** Top-level `filtered` field (e.g. tasks.list emits both total + filtered). */ filtered?: number; } /** * Render a one-line "... 3 of 227 results (offset 0, --limit 3) ..." footer * sourced from the LAFS pagination block. Empty string when the payload is * complete (`shown >= total` and `hasMore` is false-y). */ export declare function pagerFooter(input: PagerInput): string; /** * Render a dim trailing line summarising decorator-stamped envelope meta. * * Surfaces: * - `meta.duration_ms` — useful for perf-sensitive commands * - `meta._nexus.{scope, projectId, canonicalCommand, indexFreshness}` — * orchestration scope info the audit found dropped in every renderer * - `meta.deprecated.{since, removeIn, replacement}` — alias-shim warnings * that were silently lost in human output * * Returns empty string when no surfaceable fields are present. */ export declare function metaFooter(meta?: Record): string; /** * Slice an array and return both the slice and a footer line summarising the * truncation. Use instead of bare `.slice(0, N)` so users always see the * total when output is windowed. * * @example * const { items, footer } = truncated(allCallers, 10); * for (const c of items) lines.push(` ${c}`); * if (footer) lines.push(` ${footer}`); */ export declare function truncated(arr: ReadonlyArray, max: number): { items: ReadonlyArray; footer: string; }; /** * Truncate a plain (non-ANSI) string to at most `max` characters, appending an * ellipsis when truncation occurs. * * This is the single SSoT for scalar-string truncation — it replaces the 6+ * ad-hoc `truncate(str, max)` helpers that were copy-pasted across * `output-mode.ts`, `briefing.ts`, `memory/public-api.ts`, `gate-runner.ts`, * and friends. The result length never exceeds `max`: the ellipsis is counted * against the budget, so `truncateString('abcdef', 4)` returns `'abc…'`. * * For ANSI-colored content use {@link truncateVisible} (which counts visible * columns and never splits an escape sequence); for windowing an *array* use * {@link truncated}. * * @param value - The string to truncate. `null` / `undefined` collapse to `''`. * @param max - Maximum length of the returned string (including the ellipsis). * @param ellipsis - The suffix appended when truncated. Defaults to `'…'`. * Pass `'...'` for ASCII contexts. * @returns The original string when it fits, otherwise a truncated string of * length ≤ `max`. * * @example * ```ts * truncateString('a very long title', 8); // 'a very…' * truncateString('a very long title', 8, '...'); // 'a ve...' * truncateString(null, 10); // '' * ``` * * @task T11353 * @epic T11285 */ export declare function truncateString(value: string | null | undefined, max: number, ellipsis?: string): string; //# sourceMappingURL=helpers.d.ts.map