Skip to content

Constrain PickerMenu description width to the terminal's real width - #987

Closed
Ref34t wants to merge 3 commits into
PostHog:mainfrom
Ref34t:fix/picker-menu-description-width-986
Closed

Constrain PickerMenu description width to the terminal's real width#987
Ref34t wants to merge 3 commits into
PostHog:mainfrom
Ref34t:fix/picker-menu-description-width-986

Conversation

@Ref34t

@Ref34t Ref34t commented Jul 27, 2026

Copy link
Copy Markdown

Fixes #986.

The bug

Multi-select options with a description wrapped that text in a Box fixed at width={56}, regardless of the actual terminal width. On a narrow terminal this let the row render wider than the physical screen. The terminal's own line-wrapping (which Ink doesn't control) then misaligned Ink's cursor bookkeeping for every row after it — producing the overlapping/corrupted text in #986: checkbox labels merging into their descriptions (No + Skip custom scouts...NoSkip custom scouts...), the Confirm button overlapping the last option's wrapped tail, and — on a second checklist in the same run — fragments of multiple different tool names bleeding together (FrillrebaseghtVM reads like "Frill" + "Firebase" + something ending "...VM" overlapping).

How I found it

Reproduced headlessly with ink-testing-library, patching its Stdout prototype to drive real widths (100 → 40 columns) since the library hardcodes 100 columns with no override. The message text reflowed correctly at every width; the description did not — identical wrap points from 100 down to 40 columns, confirming the fixed width never adapted.

The fix

descriptionWidth() in PickerMenu.tsx reads the live terminal width via Ink's useStdout() and clamps to it — floor of 20 characters, cap of 56 (the original constant, kept as an upper bound on wide terminals), accounting for the outer margin, the per-column share when the grid has more than one column, and the description's own indent.

Verified the fix directly: re-ran the same headless harness after the change — longest rendered line now tracks the terminal width exactly (100 cols → 62, 60 cols → 60, 40 cols → 40), instead of staying near-constant regardless of width.

Also found while investigating

  • The playground demo for PickerMenu (InputDemo.tsx) never exercises the description prop at all — the exact code path that broke had zero coverage in the one place built to catch this visually.
  • ink-testing-library is a real devDependency but was unused anywhere in this repo before this fix. This is the first .tsx test file — vitest.config.ts was already configured for it (esbuild: { jsx: 'automatic' }), just never exercised.

Testing

  • pnpm build — clean, including smoke + warlock security tests
  • pnpm test — 1579/1579 passing (1576 existing + 3 new)
  • pnpm lint — 0 errors
  • New test: src/ui/tui/primitives/__tests__/PickerMenu.test.tsx, using the same monkeypatch-the-Stdout-prototype technique used to find the bug, kept as a permanent regression test

Opened as a draft — background on how this surfaced (a real self-driving run against a Laravel/Vue app, not a wizard-workbench fixture) is in #986.

mokhaled-9h and others added 3 commits July 25, 2026 23:11
The wizard had no way to recognize a WordPress project, so `npx @posthog/wizard`
in a WordPress directory detected nothing and fell through to the Node fallback
whenever a theme build had left a package.json behind.

- `Integration.wordpress`, ordered after laravel and before the language
  fallbacks, so a site with a theme package.json resolves to WordPress
- `src/frameworks/wordpress/` — a FrameworkConfig following the shape in
  .claude/skills/adding-framework-support, with composer package management and
  no package.json checks
- detection covers the four real shapes: an installed site (wp-config.php,
  wp-load.php, wp-includes/version.php), unpacked core before install
  (wp-config-sample.php), a Composer-managed install where core is not in the
  root (roots/wordpress, johnpbloch/wordpress, wpackagist-*), and a standalone
  plugin or theme directory identified by its `Plugin Name:` / `Theme Name:`
  header
- context gathering reports project type, plugins directory (including
  Bedrock's web/app/plugins), and an existing plugin entry file so the agent
  extends that plugin instead of creating a second one
- prompts carry the WordPress-specific rules: plugin over functions.php,
  ABSPATH guard, esc_js on the token, client SDK for pageviews and the PHP SDK
  for server-side actions, flush after capture
- version read from $wp_version in wp-includes/version.php, bucketed as 6.4.x
- 9 detection tests, including the negative cases (a Laravel project and a
  plain Composer PHP project must not be claimed)

Depends on PostHog/context-mill#279, which adds the matching
`integration-wordpress` variant with `framework: wordpress`. The pinned
skill-menu fixture in variant-resolution.test.ts is updated to match — without
that variant released, the cross-repo contract test fails for wordpress.

pnpm build, pnpm test (1576 passing), pnpm fix — all clean.
The prompt lines about shipping a plugin instead of editing functions.php, the
ABSPATH guard, esc_js on the token, and flushing after capture are all in the
wordpress block of context-mill's commandments.yaml, which reaches the agent
with the skill. Repeating them here duplicates integration knowledge across the
boundary AGENTS.md draws between the two repos, and would drift the moment
either side is edited.

getAdditionalContextLines now carries only what the skill cannot know: the
project shape this run is pointed at.

pnpm build, pnpm test (1576 passing), pnpm fix — clean.
Multi-select options with a description wrapped that text in a Box
fixed at 56 columns, regardless of the actual terminal width. On a
narrow terminal this let the row render wider than the physical
screen, and the terminal's own line-wrapping (which Ink doesn't
control) then misaligned Ink's cursor bookkeeping for every row
after it, producing overlapping/corrupted text.

Reads the live terminal width via Ink's useStdout() and clamps the
description width to it (floor 20, cap 56 — the original constant,
kept as an upper bound), accounting for the outer margin, grid
columns, and the description's own indent.

Adds a regression test that drives real Ink renders at several
terminal widths by patching ink-testing-library's Stdout prototype,
since the library hardcodes 100 columns with no override.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Ref34t

Ref34t commented Jul 27, 2026

Copy link
Copy Markdown
Author

Closing — this branch was accidentally based on the wordpress-framework-support branch (#983) instead of main, so it dragged in unrelated files. Reopened clean at #988.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Self-driving setup: checkbox labels and Confirm button overlap wrapped description text

2 participants