Skip to content

feat(nuxt-ui): add PreToolUse hook for component guidance#121

Merged
amondnet merged 9 commits intomainfrom
amondnet/fuchsia-grill
Mar 28, 2026
Merged

feat(nuxt-ui): add PreToolUse hook for component guidance#121
amondnet merged 9 commits intomainfrom
amondnet/fuchsia-grill

Conversation

@amondnet
Copy link
Copy Markdown
Contributor

@amondnet amondnet commented Mar 28, 2026

Summary

  • Add a PreToolUse hook to the nuxt-ui plugin that detects Nuxt UI components (U* prefix) in .vue files during Write/Edit operations
  • Injects guidance message reminding LLMs to verify v4 API usage via MCP tools (mcp__nuxt-ui-remote__get_component, mcp__nuxt-ui-remote__list_components)
  • Includes common v3→v4 migration warnings (UFormGroup→UFormField, USelectMenu→USelect, v-model:open, etc.)
  • Silent pass-through when no Nuxt UI components are detected

Files

  • plugins/nuxt-ui/hooks/hooks.json — Hook configuration (PreToolUse on Write|Edit)
  • plugins/nuxt-ui/hooks/check-vue-components.sh — Component detection + MCP guidance script
  • plugins/nuxt-ui/hooks/check-vue-components.test.sh — 8 test cases

Test plan

  • Write .vue with <UButton> → triggers guidance with MCP tool suggestions
  • Write .vue without U* components → silent (no output)
  • Edit .vue with UModal in new_string → component-specific guidance
  • Write .ts file → silent (non-vue passthrough)
  • Multiple U* components → all listed in guidance
  • Read tool → silent (only Write/Edit matched)
  • Edit removing U* component (only in old_string) → silent
  • Output is valid JSON with hookSpecificOutput.additionalContext

Summary by cubic

Adds a PreToolUse hook to the nuxt-ui plugin that detects U* components in .vue files during Write/Edit and injects guidance to verify v4 APIs with MCP tools. Improves reliability and safety of the hook and tests.

  • New Features

    • PreToolUse hook for Write|Edit on .vue files via plugins/nuxt-ui/hooks/hooks.json (5s timeout).
    • check-vue-components.sh detects <U*> and returns guidance through hookSpecificOutput.additionalContext.
    • Guidance suggests mcp__nuxt-ui-remote__get_component and mcp__nuxt-ui-remote__list_components, plus common migration tips (e.g., UFormGroupUFormField, v-model:open).
    • No output for non-.vue, when no U* components are present, or when components only appear in old_string during Edit.
  • Bug Fixes

    • Correct MCP tool prefix to mcp__nuxt-ui-remote__* to match runtime tool names (docs/spec updated for consistency).
    • Hardening: null-safe jq mapfile defaults, tolerate no matches with grep ... || true, safer component list/loop, <component> wrapping, and tests that fail on non-zero exits.

Written for commit a56f415. Summary will update on new commits.

Add track for PreToolUse hook in nuxt-ui plugin that guides LLMs
to use Nuxt UI MCP tools when writing Vue files with U* components.
Shell script that detects Nuxt UI components (U* prefix) in .vue files
during Write/Edit operations and injects MCP tool guidance to prevent
common v3→v4 migration mistakes from stale LLM training data.
Configure Write|Edit matcher to trigger component detection hook
with 5s timeout using CLAUDE_PLUGIN_ROOT for portable paths.
HTTP-type MCP servers in Claude Code get a -remote suffix appended
to their key name. Updated tool references from mcp__nuxt-ui__ to
mcp__nuxt-ui-remote__ to match actual runtime tool names.
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
claude-code-plugins Ready Ready Preview, Comment Mar 28, 2026 2:02pm

Request Review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a PreToolUse hook for the Nuxt UI plugin to provide guidance when LLMs use Nuxt UI components in .vue files. The hook detects component usage and suggests using MCP tools to verify correct v4 API patterns, helping to avoid common migration mistakes from v3. Feedback focuses on improving the robustness of the shell script, specifically addressing a bug in string manipulation for the component list, enhancing efficiency by reducing redundant jq calls, and implementing security best practices by wrapping untrusted component names in delimiters to mitigate prompt injection.

Comment thread plugins/nuxt-ui/hooks/check-vue-components.sh Outdated
Comment thread plugins/nuxt-ui/hooks/check-vue-components.sh Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 7 files

Confidence score: 2/5

  • There is a clear regression risk in plugins/nuxt-ui/hooks/check-vue-components.sh: with set -euo pipefail, valid .vue edits that produce no matches can still terminate the hook, which is likely to block normal developer workflows.
  • plugins/nuxt-ui/hooks/check-vue-components.test.sh currently allows false positives because assert_empty can ignore non-zero exit status, so failing hook behavior may slip through tests instead of being caught.
  • The docs mismatches in .please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/spec.md and .please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/plan.md are lower severity, but they can still mislead users toward incorrect MCP tool names.
  • Pay close attention to plugins/nuxt-ui/hooks/check-vue-components.sh, plugins/nuxt-ui/hooks/check-vue-components.test.sh, .please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/spec.md, .please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/plan.md - prevent hook false failures, tighten test assertions, and align MCP namespaces.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="plugins/nuxt-ui/hooks/check-vue-components.sh">

<violation number="1" location="plugins/nuxt-ui/hooks/check-vue-components.sh:37">
P1: The component-detection pipeline can terminate the hook on valid input with no matches due to `set -euo pipefail`. Handle the no-match case explicitly so non-Nuxt-UI `.vue` edits pass through cleanly.</violation>
</file>

<file name=".please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/spec.md">

<violation number="1" location=".please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/spec.md:27">
P2: FR-4 specifies MCP tool names that are inconsistent with the rest of this PR (`mcp__nuxt-ui-remote__*`), which can cause the hook guidance to suggest incorrect tool calls.</violation>
</file>

<file name=".please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/plan.md">

<violation number="1" location=".please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/plan.md:66">
P2: Use a single MCP tool namespace consistently; this line uses `mcp__nuxt-ui__get_component` while the rest of the change describes `mcp__nuxt-ui-remote__get_component`.</violation>
</file>

<file name="plugins/nuxt-ui/hooks/check-vue-components.test.sh">

<violation number="1" location="plugins/nuxt-ui/hooks/check-vue-components.test.sh:18">
P1: `assert_empty` can report false positives by ignoring non-zero hook exit codes. Treat non-zero status as test failure so silent-mode tests don't pass when the hook errors.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant LLM as Claude (LLM)
    participant HM as Hook Manager
    participant Script as check-vue-components.sh
    participant MCP as Nuxt UI Remote MCP
    participant FS as Filesystem (Write/Edit)

    Note over LLM,FS: Triggered during Write or Edit tool execution on .vue files

    LLM->>HM: Call Write/Edit tool
    HM->>Script: NEW: Trigger PreToolUse hook (stdin JSON)
    
    Script->>Script: Parse tool_input (file_path & content)
    
    alt NEW: File is .vue AND content matches <U[A-Z]*
        Script->>Script: Extract component list (e.g. UButton, UModal)
        Script->>Script: NEW: Construct v3→v4 migration guidance
        Script-->>HM: Return JSON with hookSpecificOutput.additionalContext
        HM-->>LLM: Injected guidance (reminders for v4 API + MCP suggestions)
        
        opt LLM decides to verify component API
            LLM->>MCP: CHANGED: mcp__nuxt-ui-remote__get_component()
            MCP-->>LLM: Return component schema & props
        end
    else No Nuxt UI components OR non-vue file
        Script-->>HM: Silent exit (no additionalContext)
    end

    HM->>FS: Proceed with original Write/Edit operation
    FS-->>LLM: Return tool result (Success/Error)
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread plugins/nuxt-ui/hooks/check-vue-components.sh Outdated
Comment thread plugins/nuxt-ui/hooks/check-vue-components.test.sh
Comment thread .please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/spec.md Outdated
Comment thread .please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/plan.md Outdated
- Use single jq call with mapfile for efficiency (avoid multiple cat/echo/jq)
- Fix trailing comma+space bug in component list string construction
- Use while read loop directly on newline-separated list (more robust)
- Wrap component names in <component> delimiters for prompt injection mitigation
- fix: add || true to grep pipeline in check-vue-components.sh to prevent premature exit under set -euo pipefail when no Nuxt UI components are detected
- fix: correct null handling in jq mapfile to always emit 4 lines (use explicit // "" per field, not .[] // "")
- fix: assert_empty in test now captures exit code and treats non-zero as test failure instead of || true masking
- fix: update spec.md FR-4 and plan.md observable outcomes to use consistent mcp__nuxt-ui-remote__ namespace
@amondnet amondnet self-assigned this Mar 28, 2026
@amondnet amondnet merged commit 211691e into main Mar 28, 2026
7 checks passed
@amondnet amondnet deleted the amondnet/fuchsia-grill branch March 28, 2026 14:05
@pleaeai-bot pleaeai-bot Bot mentioned this pull request Mar 28, 2026
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