# @aliaksei-raketski/pi-statusline

A Pi extension that replaces the footer statusline with a configurable, multi-line layout.

## Install

```bash
pi install npm:@aliaksei-raketski/pi-statusline
# or project-local
pi install -l npm:@aliaksei-raketski/pi-statusline
```

## Features

- Runtime TypeScript extension loaded directly by Pi; no package build step is required.
- Published package includes the `extensions/statusline` source tree used by Pi at runtime.
- Custom footer layout with spacer tokens.
- Single-line and multi-line layouts.
- Automatic narrow-terminal fallback to one status item per line.
- Per-token and per-state color control (`muted`, theme names, hex, or 256-color numbers).
- Optional extension statuses from `ctx.ui.setStatus()`:
  - Use explicit `statuses` token to show all extension statuses.
  - Or reference any status key name directly in `layout` to show that extension status only.
- Live updates for model, thinking level, branch, changes, PR, and session usage/cost.
- Project-local config is loaded only when the project is trusted.

## Configuration

Configuration is loaded from two files and merged in order:

1. **User config**: `~/.pi/statusline.json`
2. **Project config**: `<project>/.pi/statusline.json` (only when project is trusted)

Invalid config values are ignored and fall back to defaults, with warnings emitted in the UI.

If no user config exists, statusline will create `~/.pi/statusline.json` with the default configuration on first launch for easy editing.

### Default config

```json
{
  "layout": [
    ["branch", "changes", "pr", "spacer", "project"],
    ["context", "cache", "cost", "spacer", "model", "thinking", "caffeinate"],
    ["title"],
    ["cwd"]
  ],
  "separator": " • ",
  "separatorColor": "dim",
  "prefix": {
    "cwd": "⌂",
    "branch": "↳ ",
    "project": "◯",
    "title": "✎",
    "model": "◉",
    "thinking": "◐",
    "caffeinate": "☕",
    "context": "◔",
    "tokens": "◈",
    "cache": "↻",
    "statuses": "◍"
  },
  "colors": {
    "cwd": "muted",
    "branch": {
      "clean": "success",
      "dirty": "muted",
      "default": "accent"
    },
    "title": "muted",
    "project": "muted",
    "model": "toolTitle",
    "changes": "dim",
    "pr": "muted",
    "thinking": {
      "off": "thinkingOff",
      "minimal": "thinkingMinimal",
      "low": "thinkingLow",
      "medium": "thinkingMedium",
      "high": "thinkingHigh",
      "xhigh": "thinkingXhigh"
    },
    "context": {
      "normal": "muted",
      "warning": "warning",
      "full": "error",
      "default": "muted"
    },
    "tokens": "muted",
    "cache": "muted",
    "cost": "muted",
    "caffeinate": {
      "active": "accent",
      "waiting": "warning",
      "error": "error",
      "default": "muted"
    }
  }
}
```

### Layout

`layout` is either:

- a single array of tokens (single line), or
- an array of arrays (multi-line).

A line can include the reserved token `spacer` to allocate flexible spacing. Note: `separator` is only inserted between tokens inside the same segment, so if you put `spacer` between every token, separators may not be visible.

On narrow terminals, the renderer falls back to one item per line (ordered by layout), using all available width and without segment separators/spacers.
Lines that render to no visible content are omitted automatically (for example an empty `title` line).

Examples:

```json
{ "layout": ["cwd", "branch", "model"] }
```

```json
{
  "layout": [
    ["cwd", "model", "thinking"],
    ["changes", "title", "context"]
  ]
}
```

### Status items

The `layout` array uses the following token names:

- `cwd` — current working directory, shortened with `~` for your home directory.
- `model` — current model name (model id only, e.g. `gpt-4.1`), or `unknown` if unavailable.
- `thinking` — current thinking level from Pi: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`.
- `branch` — current git branch from footer context. It is stateful: `clean` when working tree has no changes and `dirty` when there are staged/unstaged/untracked changes.
- `changes` — git changes summary with counts: `!<conflicts> +<staged> ~<unstaged> ?<untracked> ↑<ahead> ↓<behind>` (only non-zero parts are shown; untracked files are counted per-file).
- `pr` — current pull request number for current branch, shown as `PR #<number>` when `gh pr view` returns a number.
- `title` — current session name (`ctx.sessionManager.getSessionName()`) if set.
- `project` — project name from `package.json` when available, otherwise directory name.
- `tokens` — total message tokens seen so far as `<input>↑ <output>↓`.
- `context` — context usage: `<percent>%/<contextWindow>` (for example `52.5%/128k`) and optional state (`normal`, `warning`, `full`) based on percent.
- `cache` — cache usage: `<cacheRead>/<cacheWrite> <percent>%` using branch history assistant usage.
- `cost` — accumulated usage cost shown as `$<value>`.

`statuses` is rendered when `statuses` is explicitly in `layout`.

Caffeinate is included in the fresh default layout as the direct `caffeinate` token. Existing custom layouts are unchanged; add `caffeinate` directly or use the aggregate `statuses` token to display it.

You can also include any status key directly (for example `my_extension`); if another extension sets it via `ctx.ui.setStatus("my_extension", "...")`, it will be rendered in that slot.

### Colors

- `colors` values can be theme tokens (e.g. `muted`, `warning`, `accent`),
  hex colors (e.g. `#8aadf4`), 256 colors (`0`-`255`), or `""` for no color.
- For stateful items (`branch`, `thinking`, `context`) you can pass an object keyed by state:

```json
{
  "colors": {
    "thinking": {
      "off": "dim",
      "minimal": "muted",
      "low": "warning",
      "medium": "accent",
      "high": "error",
      "xhigh": "error"
    },
    "context": {
      "normal": "muted",
      "warning": "warning",
      "full": "error",
      "default": "muted"
    }
  }
}
```

For unknown states, `default` is used as fallback, then built-in defaults are used.

For `separator`, use `separator` or `separatorColor` to control token separators and their color.

## Development

Tests live in `packages/statusline/extensions/statusline/test`. From the repository root:

```bash
pnpm nx run @aliaksei-raketski/pi-statusline:test
```

To try locally from the repository root:

```bash
pi -e ./packages/statusline
```
