# Web App

Chat input, session titles, and the skill library in the Web App.

## Chat input: positional slash, skill chips above the input, wider skill menu

The `/` command menu now opens from any caret position (like `@` mentions) and running a
command removes just the token; selected skills display as chips above the input next to
the agent chip; chip remove buttons recolor on hover instead of washing a background; the
skill dropdown widens for readable descriptions while staying inside phone screens.

## Details

- Positional slash (`slash-token.ts`, pure + unit-tested): a `/` at the start of the text
  or after whitespace opens the command menu from wherever the caret is (paths/URLs never
  trigger it), mirroring the existing positional `@` mention matching; running a command
  removes only the `start..end` token and keeps the rest of the text. Send-time `@`
  semantics are unchanged — only a leading `@` hands off.
- Selected skills render as chips above the input in the same row as the `@` handoff chip
  (skill icon + monospace name + remove x), appearing as you pick them from the dropdown;
  the toolbar count badge stays in sync.
- Chip remove buttons (agent and skill) lose the hover background — the x recolors instead.
- The skill dropdown widens (26rem, clamped to the viewport) so descriptions stay readable
  on desktop without overflowing phones.
- The models-page group speed button collapses to icon-only below the sm breakpoint (three
  labeled actions don't fit a 390px header — caught by the layout e2e).

## Start title generation after 1000 chars of body text

Session titles start generating as soon as ~1000 characters of main-session body text have
streamed, instead of waiting for the whole Task to finish — long answers no longer overrun
the title material — and the title prompt now suppresses chain-of-thought.

## Details

- Server: the output relay fires the title generator mid-run once EARLY_TITLE_BODY_CHARS
  (1000) of main-session complete body text have streamed (sub-session text doesn't count);
  the generator self-guards (NULL title, single flight), and the Task-completion trigger
  stays as the short-answer fallback. Covered by a gated mid-run test proving the early
  fire happens while the run is still in flight.
- Core: the captured assistant-side title material is capped at 1000 chars (the user side
  keeps 2000) — a title only needs the opening of the answer.
- The title prompt adds an explicit "answer immediately — do not think aloud or produce
  chain-of-thought" rule and ends with an empty `<think></think>` block, which many
  reasoning models treat as an already-closed thinking phase (same trick as the model
  probe), keeping the one-off request's budget on the title itself.

## Skill library: update reminder, borderless groups, accent icons

The skill library reminds you when an Agent's installed copy of a skill is older than the
library's version — an accent rotate button on the card updates every outdated Agent in one
click, and the manage-installs dialog marks outdated rows with an Update button. Group
sections lose their border, and card icons sit on a theme-accent background.

## Details

- The installed-skills snapshot now tracks each installed copy's `version` (the read API
  already returns it — the installed SKILL.md frontmatter is the source). A pure
  `outdatedAgentIds` helper (unit-tested) flags Agents whose copy is strictly older than
  the library's; not-installed Agents and locally *newer* copies never trigger it.
- Card footer: when any Agent is outdated, an accent rotate button appears
  ("有新版本：更新 N 个 Agent 的安装" / "Update available"); clicking reinstalls the current
  library copy on every outdated Agent (install-again-is-update semantics) with one batch
  success toast; partial failures keep the succeeded Agents and toast the first error.
- Manage-installs dialog: outdated rows show an accent "更新"/"Update" button next to
  "已安装"/"Installed", updating just that Agent.
- Styling: group sections are borderless (header background alone carries the grouping);
  card icons use the theme accent (`--accent-bg`/`--accent-fg`, following the theme-color
  setting) instead of the gray bordered tile.

## Titles strip skill-invocation markers; Agent cards show the installed skill count

Two Web App additions: generated titles no longer leak the `<use_skills>` block, and Agent cards display how many Skills are installed.

- Session titles strip machine markers before generation and in the fallback path: `stripConversationMarkers` (core, exported) removes `<use_skills>…</use_skills>` and the handoff / scheduled-task marker blocks from the material sent to the model, from the model output (via `sanitizeTitle`), and from the server's first-line fallback — so a skill invocation's marker can never become the title. Ordinary angle-bracket text (e.g. `<div>`) is left untouched.
- The Agent card's stats line gains an installed-skill count (open-book icon): the agents API/service compute `skillCount` from the `agent_state/skills/<name>/SKILL.md` directories, alongside the existing session / tool / vault-key / schedule counts.

## Slash menu stays on screen; skill card buttons go horizontal and light

Two Web App polish fixes: the slash command menu could grow past the top of the viewport, and the skill card actions change arrangement again.

- The slash menu (which lists /compact plus every installed skill) now caps its height at min(20rem, 40vh) with internal scrolling, so its top edge never leaves the screen; the active row keeps itself scrolled into view for keyboard navigation.
- Skill card actions return to a single horizontal row (still equal squares, vertically centered at the card's right edge), and all three buttons now wear the light secondary background.

## Password field polish, model-key visibility, and borderless skill cards

Several small UX fixes across the password fields, the model key input, and the skill library cards, plus a redrawn penguin game shot.

- The change-password dialog's current-password field now shows a hint naming the built-in admin's default initial password (penguin-2026), so a user who forgot it can still get in.
- The password show/hide toggle is removed from the tab order (tabIndex -1): Tab now moves between fields instead of landing on the reveal button.
- The model API key input gains the same show/hide toggle (it reuses PasswordInput), so a pasted key can be verified before saving.
- Skill library cards drop their border; hover now tints the whole card with a light gray background instead.
- The penguin sled game mockup is redrawn so the penguin stays a single connected cartoon shape (it had looked fragmented), and the game example is emphasized as 2D with a smoother, gentler difficulty ramp in the draft-screen card, its prompt, and the landing tab label.

## The admin initial password becomes penguin-2026

`admin123` sits in every breach corpus, so Chrome flags the first login as a compromised password; the seeded admin now starts as `penguin-2026` — unflagged, brand-related, all lowercase plus a hyphen so it stays easy to type.

The value swaps everywhere it appears: the server seed (`ADMIN_INITIAL_PASSWORD`), the release installer's first-login hint, READMEs, docs (quickstart / web-app / server-api), blog posts, landing quickstart copy, the screenshot capture scripts, and the e2e auth helper. The change-it-soon banner semantics are unchanged.
