Skip to content

[hooks] interactive arrow-key select for multi-CLI install prompt#222

Merged
NiveditJain merged 2 commits into
mainfrom
luv-223
Apr 28, 2026
Merged

[hooks] interactive arrow-key select for multi-CLI install prompt#222
NiveditJain merged 2 commits into
mainfrom
luv-223

Conversation

@NiveditJain
Copy link
Copy Markdown
Member

@NiveditJain NiveditJain commented Apr 28, 2026

Summary

  • Replace the [B]oth / [C]laude / [D]codex text prompt that fires when both Claude Code and OpenAI Codex are detected during failproofai policies --install with an arrow-key single-select.
  • Visual style mirrors the existing policy selector (cursor , dim/bold rows, footer hint line). Options: Both, Claude Code only, OpenAI Codex only. Keys: ↑↓ to move, Enter to select, ^C to quit.
  • Non-TTY behaviour unchanged (defaults to all detected CLIs); explicit --cli flag still short-circuits the prompt.

Test plan

  • bun run test:run __tests__/hooks/ — 733/733 pass
  • bunx tsc --noEmit clean on changed file
  • bun run lint clean (only pre-existing unrelated warning)
  • bun build --target=node --format=cjs --outfile=dist/index.js src/index.ts succeeds
  • Manually verify the new prompt by running bun bin/failproofai.mjs p -i in a TTY with both claude and codex on PATH

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • failproofai policies --install now uses an interactive arrow-key menu for selecting agent CLIs when multiple are detected, replacing the previous single-keypress prompt.
    • Non-interactive installations now default to all detected CLIs.
  • Documentation

    • Updated installation guide and changelog to reflect the new selection interface.

NiveditJain and others added 2 commits April 28, 2026 16:21
Replace the [B]oth/[C]laude/[D]codex text prompt that fires when both
Claude Code and OpenAI Codex are detected during `policies --install`
with an arrow-key single-select that mirrors the visual style of the
existing policy selector (pointer, dim/bold rows, footer hint line).
Non-TTY behaviour is unchanged: defaults to all detected CLIs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the "single-keypress prompt: install for [B]oth, [C]laude, or
co[D]ex" line in the multi-CLI detection section with a description of
the new arrow-key single-select. Translations will be regenerated by
.github/workflows/translate-docs.yml on the next push to main.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

This PR replaces the single-keypress B/C/D text prompt with an interactive arrow-key single-select menu for CLI selection when multiple agent CLIs are detected. Documentation and implementation are updated accordingly. Non-TTY behavior now defaults to installing all detected CLIs.

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md, docs/configuration.mdx
Updated to document the shift from B/C/D single-keypress prompt to an arrow-key single-select menu with explicit navigation and selection key bindings.
Implementation
src/hooks/install-prompt.ts
Introduced promptCliTargetSelection function implementing interactive arrow-key menu with cursor tracking, keyboard input handling (arrow keys, Enter, Ctrl+C), terminal state management, and fallback to all detected CLIs for non-TTY environments.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 twitches nose with delight
Where once stood B and C and D,
Now arrows dance through choices spree!
Up, down, select with elegant grace,
The menu flows with interactive pace! 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: replacing a text prompt with an interactive arrow-key select for multi-CLI installation.
Description check ✅ Passed The description is comprehensive and covers what changed, why it matters, and includes a detailed test plan; however, it does not follow the required template structure with explicit checkbox sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch luv-223

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/hooks/install-prompt.ts (1)

104-123: Extract duplicated ANSI-safe truncation helper.

truncateLine is duplicated in two places (Line 104 and Line 250). A single shared helper will reduce drift risk when terminal rendering logic is adjusted later.

Refactor sketch
+function truncateAnsiLine(line: string, width: number): string {
+  let visual = 0;
+  let result = "";
+  let i = 0;
+  while (i < line.length) {
+    if (line[i] === "\x1B" && line[i + 1] === "[") {
+      let j = i + 2;
+      while (j < line.length && !/[A-Za-z]/.test(line[j])) j++;
+      j++;
+      result += line.slice(i, j);
+      i = j;
+    } else {
+      if (visual >= width) break;
+      result += line[i];
+      visual++;
+      i++;
+    }
+  }
+  return result;
+}

Then replace both call sites with truncateAnsiLine(...).

Also applies to: 249-269

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/install-prompt.ts` around lines 104 - 123, The truncateLine
ANSI-aware truncation function is duplicated; extract it into a single shared
helper named truncateAnsiLine (preserving current logic: track visual width,
copy ANSI escape sequences verbatim, and stop when visual >= width) and export
it for reuse, then replace both existing implementations (the current
truncateLine and the other duplicate used elsewhere) with calls to
truncateAnsiLine so both places use the shared helper; update any
imports/exports and ensure function name references (truncateLine ->
truncateAnsiLine) at both call sites are changed accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/hooks/install-prompt.ts`:
- Around line 64-66: The current check only gates interactivity on
process.stdin.isTTY which can still allow prompts when stdout is redirected;
update the guard in the install prompt logic so both process.stdin.isTTY and
process.stdout.isTTY must be true before entering interactive prompt mode (i.e.,
return detected when either stream is not a TTY). Locate the condition in
src/hooks/install-prompt.ts around the block that reads "if
(!process.stdin.isTTY) return detected;" and change it to require both stdio
TTYs (use process.stdin.isTTY && process.stdout.isTTY) so prompting only happens
in fully interactive terminals.

---

Nitpick comments:
In `@src/hooks/install-prompt.ts`:
- Around line 104-123: The truncateLine ANSI-aware truncation function is
duplicated; extract it into a single shared helper named truncateAnsiLine
(preserving current logic: track visual width, copy ANSI escape sequences
verbatim, and stop when visual >= width) and export it for reuse, then replace
both existing implementations (the current truncateLine and the other duplicate
used elsewhere) with calls to truncateAnsiLine so both places use the shared
helper; update any imports/exports and ensure function name references
(truncateLine -> truncateAnsiLine) at both call sites are changed accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ce8734a-1b53-4a7d-a9dd-9bc8a4409779

📥 Commits

Reviewing files that changed from the base of the PR and between 50fcb60 and 61809b9.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • docs/configuration.mdx
  • src/hooks/install-prompt.ts

Comment on lines +64 to 66
// Multiple detected. Prompt or default.
if (!process.stdin.isTTY) return detected; // non-interactive: install for all detected

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Gate interactivity on both stdin and stdout TTYs.

At Line 65, checking only process.stdin.isTTY can still trigger an interactive prompt when output is redirected, causing hidden waits/escape-sequence output. Please require both streams to be TTY before entering prompt mode.

Proposed fix
-  if (!process.stdin.isTTY) return detected; // non-interactive: install for all detected
+  if (!process.stdin.isTTY || !process.stdout.isTTY) return detected; // non-interactive: install for all detected
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/install-prompt.ts` around lines 64 - 66, The current check only
gates interactivity on process.stdin.isTTY which can still allow prompts when
stdout is redirected; update the guard in the install prompt logic so both
process.stdin.isTTY and process.stdout.isTTY must be true before entering
interactive prompt mode (i.e., return detected when either stream is not a TTY).
Locate the condition in src/hooks/install-prompt.ts around the block that reads
"if (!process.stdin.isTTY) return detected;" and change it to require both stdio
TTYs (use process.stdin.isTTY && process.stdout.isTTY) so prompting only happens
in fully interactive terminals.

@NiveditJain NiveditJain merged commit ee9fc23 into main Apr 28, 2026
9 checks passed
NiveditJain added a commit that referenced this pull request Apr 29, 2026
Bumps package.json from 0.0.9-beta.2 to 0.0.9 and rolls the ## Unreleased
changelog section into ## 0.0.9 — 2026-04-28.

0.0.9 contents:

Features:
- OpenAI Codex hook integration via `failproofai policies --install --cli codex`
  (or --cli claude codex for both); supports all six Codex hook events,
  PermissionRequest wired through policy-evaluator, per-CLI telemetry tagging,
  interactive arrow-key CLI selector when both agents detected (#220, #222, #223)
- Surface Slack community link in CLI banner and Reach Us menu (#225)

Fixes:
- Trailing blank line after enabled-policies summary in install output (#224)
- Resolve hook bin via $CLAUDE_PROJECT_DIR (was relative path) (#219)
- Mintlify validation of Arabic built-in-policies docs

Docs:
- Bump built-in policy count from 32 to 39 in README and translations (#207)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
NiveditJain added a commit that referenced this pull request Apr 29, 2026
Promotes the version from 0.0.9-beta.3 to 0.0.9 stable. The
## 0.0.9 — 2026-04-28 changelog section is already up to date with the
contents below; no CHANGELOG churn required.

0.0.9 contents:

Features:
- OpenAI Codex hook integration via `failproofai policies --install --cli codex`
  (or --cli claude codex for both); supports all six Codex hook events,
  PermissionRequest wired through policy-evaluator, per-CLI telemetry tagging,
  interactive arrow-key CLI selector when both agents detected (#220, #222, #223)
- Activity dashboard CLI filter alongside event-type, policy, and session-id
  filters; Codex sessions in the activity feed are now clickable, with the
  existing log viewer rendering Codex transcripts via lib/codex-sessions.ts (#226)
- Surface Slack community link in CLI banner and Reach Us menu (#225)
- Show OpenAI Codex projects on the /projects page alongside Claude Code projects,
  with CLI badges per row and per session; /project/[name] is Codex-aware and the
  session viewer renders the CLI badge beside the Session Log header (#232)

Fixes:
- Trailing blank line after enabled-policies summary in install output (#224)
- Resolve hook bin via $CLAUDE_PROJECT_DIR (was relative path) (#219)
- Mintlify validation of Arabic built-in-policies docs
- Mintlify parse error in docs/de/dashboard.mdx (#229)
- block-read-outside-cwd false-deny on globs and -v host:/path (#230)
- Decouple hook chain from clsx/tailwind via lib/format-date.ts (#231)

Docs:
- Bump built-in policy count from 32 to 39 in README and translations (#207)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant