<!-- Generated by scripts/gen-docs.ts from the TSDoc in src/. Do not edit by hand. -->

# `text`

Source: [`src/text.ts`](https://github.com/AI-for-dev/combo/blob/main/src/text.ts)

Reading what a model wrote, and cutting what it is handed: shortening text,
and finding the structure in it.

One concept, not a grab-bag: every function here takes free-form assistant
text and makes something reliable out of it. They were each written three to
five times across the workflows, the reporters and the extension, and the
copies had already started to drift - one `truncate` that trimmed and one that
did not, two identical brace scanners maintained apart.

A model does not answer in a format. It answers in prose with the format
somewhere inside, decorated with whatever markdown it felt like adding, which
is why these are lenient by design.

## `head`

*function*

```typescript
export function head(text: string, max: number, what = "text"): string { /* … */ }
```

The first `max` characters, marked when something was cut.

For what goes into a prompt: the start of a diff says more than its end, and
an agent handed half a megabyte writes a worse message than one handed the
first pages and told they were cut. `what` names the thing in the marker.

## `plural`

*function*

```typescript
export function plural(count: number, word: string): string { /* … */ }
```

`1 turn`, `2 turns`, `0 turns`.

One rule in one place, because a count is shown in a widget, a notification
and a listing at once, and they have to agree. Zero takes the plural, because
English does.

## `saysWord`

*function*

```typescript
export function saysWord(output: string, word: string): boolean { /* … */ }
```

Whether `word` stands alone on one of the lines.

The convention three workflows depend on - `LGTM`, `APPROVED`, `READY` - and
the reason it is lenient: a model that has been told to answer with one word
still writes `**LGTM**`, `## APPROVED` or `READY.`, and a strict match would
loop forever waiting for a verdict already given. Decoration is stripped, case
is ignored; a line with anything else on it still does not count.

## `tail`

*function*

```typescript
export function tail(text: string, max: number, dropped = 0): string { /* … */ }
```

The last `max` characters, marked when something was cut.

For a check's output: the failure is at the end, after everything that
passed, and the end is what a reader needs. `dropped` counts what a reader
of a stream already let go before `text`, so the mark says the whole.

## `truncate`

*function*

```typescript
export function truncate(text: string, max: number): string { /* … */ }
```

One line, whitespace flattened, at most `max` characters with an ellipsis.

`max` has no default on purpose: the width belongs to whoever is drawing, and
a shared default would be the one number nobody chose.
