Skip to content

Add --accessible flag for screen reader support#16

Open
taylorarndt wants to merge 1 commit intomicrosoft:mainfrom
taylorarndt:feature/screen-reader-accessibility
Open

Add --accessible flag for screen reader support#16
taylorarndt wants to merge 1 commit intomicrosoft:mainfrom
taylorarndt:feature/screen-reader-accessibility

Conversation

@taylorarndt
Copy link

@taylorarndt taylorarndt commented Feb 23, 2026

Why

I am a blind developer. When I run the Primer TUI with a screen reader, every box-drawing border character gets read aloud individually: "box drawing light arc down and right, box drawing light horizontal, box drawing light horizontal..." over and over. The block-art ASCII banner is even worse. Unicode symbols like checkmarks and bullets also get verbose announcements instead of useful information.

This makes the TUI unusable with a screen reader.

What this does

Adds a --accessible flag that strips out all the visual decoration and replaces it with plain text that screen readers can actually read.

Borders: Removed when --accessible is on. No more box-drawing characters.

Banner: The block-art "PRIMER" banner becomes the word "PRIMER" in plain text.

Symbols: Unicode gets replaced with text:

  • becomes PASS or OK
  • becomes FAIL
  • becomes [x]
  • becomes [ ]
  • becomes >
  • becomes -

Ink integration: Passes isScreenReaderEnabled: true to Ink's render() so the framework itself also optimizes output.

Usage

# Global flag works with any subcommand
primer --accessible tui
primer --accessible batch

# Or set once via environment variable
export INK_SCREEN_READER=true
primer tui

What a screen reader hears now

Before:

box drawing light arc down and right, box drawing light horizontal, box drawing light horizontal, box drawing light horizontal, box drawing light arc down and left, full block, full block, full block...

After:

PRIMER. Prime your repo for AI. Repo: my-project. Status: ready. Keys: A Analyze, G Generate, E Eval, B Batch, Q Quit.

Files changed

  • src/cli.ts — global --accessible option
  • src/commands/tui.tsx — reads flag, passes to render and component
  • src/commands/batch.tsx — same
  • src/ui/AnimatedBanner.tsx — plain text banner in accessible mode
  • src/ui/tui.tsx — conditional borders and text symbols
  • src/ui/BatchTui.tsx — conditional borders and text symbols for all lists

Test plan

  • primer --accessible tui — no box-drawing characters in output
  • primer --accessible batch — no Unicode symbols in lists
  • INK_SCREEN_READER=true primer tui — same behavior via env var
  • primer tui without flag — normal visual output unchanged
  • Test with a screen reader (VoiceOver, NVDA, JAWS)

🤖 Generated with Claude Code

When enabled (via --accessible flag or INK_SCREEN_READER=true env var),
the TUI removes box-drawing border characters, replaces the block-art
banner with plain text, and substitutes Unicode symbols with text
equivalents (e.g. checkmark -> PASS, bullet -> [x]).

This prevents screen readers from reading every border character aloud
as "box drawing light arc down and right" etc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 23, 2026 00:33
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in accessibility mode for Primer’s Ink-based TUIs to improve screen reader output by removing box-drawing borders, replacing banner art, and substituting certain Unicode symbols with text.

Changes:

  • Introduces a global --accessible CLI flag and reads INK_SCREEN_READER=true as an alternative.
  • Updates tui and batch commands to pass accessibility settings into Ink render() and the UI components.
  • Adjusts TUI components to remove borders and replace some Unicode glyphs with text when accessible is enabled.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/cli.ts Adds global --accessible option (and touches CLI version line).
src/commands/tui.tsx Derives accessible and passes it to Ink render + PrimerTui.
src/commands/batch.tsx Derives accessible and passes it to Ink render + BatchTui.
src/ui/AnimatedBanner.tsx Makes StaticBanner render plain “PRIMER” text when accessible.
src/ui/tui.tsx Plumbs accessible through the main TUI and adjusts borders/verdict glyphs.
src/ui/BatchTui.tsx Adds accessible prop and replaces some list glyphs + borders accordingly.

Comment on lines +26 to +29
const accessible = cmd.parent?.opts().accessible || process.env.INK_SCREEN_READER === "true";
const { waitUntilExit } = render(
<BatchTui token={token} outputPath={options.output} />
<BatchTui token={token} outputPath={options.output} accessible={accessible} />,
{ isScreenReaderEnabled: accessible }
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

batchCommand dereferences cmd.parent without guarding cmd itself. If the Command instance is not passed into the action handler (depending on Commander configuration), this will crash primer batch at startup. Consider making cmd optional (cmd?.parent?.opts()) and/or enabling passCommandToAction(true) when registering commands.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +21
.version("0.1.0")
.option("--accessible", "Enable screen reader friendly output (removes box-drawing characters, replaces Unicode symbols with text)");
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI version is hardcoded as 0.1.0, but package.json is 1.0.0. This can cause confusing/mismatched primer --version output. Consider sourcing the version from package.json (or keeping these in sync).

Copilot uses AI. Check for mistakes.
.description("Prime repositories for AI-assisted development")
.version("0.1.0");
.version("0.1.0")
.option("--accessible", "Enable screen reader friendly output (removes box-drawing characters, replaces Unicode symbols with text)");
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--accessible is added only on the root command. With Commander’s default parsing rules, primer tui --accessible will be treated as an unknown option on the tui subcommand (users must write primer --accessible tui). If you want it to behave like a true global flag regardless of position, consider also adding the option to subcommands (or enabling positional/pass-through options).

Copilot uses AI. Check for mistakes.
<Text color={repo.hasInstructions ? "green" : "red"}>{repo.hasInstructions ? "✓" : "✗"} </Text>
<Text color={isCursor ? "cyan" : undefined}>{isCursor ? (accessible ? "> " : "❯ ") : " "}</Text>
<Text color={isSelected ? "green" : "gray"}>{isSelected ? (accessible ? "[x]" : "◉") : (accessible ? "[ ]" : "○")} </Text>
<Text color={repo.hasInstructions ? "green" : "red"}>{repo.hasInstructions ? (accessible ? "HAS" : "✓") : (accessible ? "NEEDS" : "✗")} </Text>
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In accessible mode, the repo status indicator uses very terse labels (HAS / NEEDS). For screen reader output this can be ambiguous (has/needs what?). Consider using more explicit text like HAS_INSTRUCTIONS / NEEDS_INSTRUCTIONS (or similar) so the meaning is clear when read aloud.

Suggested change
<Text color={repo.hasInstructions ? "green" : "red"}>{repo.hasInstructions ? (accessible ? "HAS" : "✓") : (accessible ? "NEEDS" : "✗")} </Text>
<Text color={repo.hasInstructions ? "green" : "red"}>{repo.hasInstructions ? (accessible ? "HAS_INSTRUCTIONS" : "✓") : (accessible ? "NEEDS_INSTRUCTIONS" : "✗")} </Text>

Copilot uses AI. Check for mistakes.
{evalResults.map((r) => (
<Text key={r.id} color={r.verdict === "pass" ? "green" : r.verdict === "fail" ? "red" : "yellow"}>
{r.verdict === "pass" ? "✓" : r.verdict === "fail" ? "✗" : "?"} {r.id}: {r.verdict} (score: {r.score})
{r.verdict === "pass" ? (accessible ? "PASS" : "✓") : r.verdict === "fail" ? (accessible ? "FAIL" : "✗") : "?"} {r.id}: {r.verdict} (score: {r.score})
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In accessible mode, the verdict line prints both the text label and the verdict value (e.g., PASS <id>: pass ... / FAIL <id>: fail ...), which is redundant when read aloud. Consider outputting a single normalized label (e.g., Verdict: PASS) or omitting r.verdict when the accessible label is used.

Suggested change
{r.verdict === "pass" ? (accessible ? "PASS" : "✓") : r.verdict === "fail" ? (accessible ? "FAIL" : "✗") : "?"} {r.id}: {r.verdict} (score: {r.score})
{accessible
? `Verdict: ${r.verdict === "pass" ? "PASS" : r.verdict === "fail" ? "FAIL" : "UNKNOWN"} ${r.id} (score: ${r.score})`
: `${r.verdict === "pass" ? "✓" : r.verdict === "fail" ? "✗" : "?"} ${r.id}: ${r.verdict} (score: ${r.score})`}

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +18
const accessible = cmd.parent?.opts().accessible || process.env.INK_SCREEN_READER === "true";
const { waitUntilExit } = render(
<PrimerTui repoPath={repoPath} skipAnimation={skipAnimation || accessible} accessible={accessible} />,
{ isScreenReaderEnabled: accessible }
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tuiCommand assumes Commander passes a cmd argument, but cmd is dereferenced unguarded (cmd.parent...). If Commander doesn’t pass the Command instance (depending on configuration), this will throw at runtime and break primer tui. Make cmd optional (use cmd?.parent?.opts()) and/or enable passCommandToAction(true) when wiring commands so the Command instance is reliably available.

Copilot uses AI. Check for mistakes.
digitarald added a commit that referenced this pull request Feb 24, 2026
chore: update dependencies across root and vscode-extension
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.

2 participants