feat(nuxt-ui): add PreToolUse hook for component guidance#121
Conversation
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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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: withset -euo pipefail, valid.vueedits 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.shcurrently allows false positives becauseassert_emptycan 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.mdand.please/docs/tracks/active/nuxt-ui-hook-guidance-20260328/plan.mdare 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)
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- 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
Summary
U*prefix) in.vuefiles during Write/Edit operationsmcp__nuxt-ui-remote__get_component,mcp__nuxt-ui-remote__list_components)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 scriptplugins/nuxt-ui/hooks/check-vue-components.test.sh— 8 test casesTest plan
.vuewith<UButton>→ triggers guidance with MCP tool suggestions.vuewithout U* components → silent (no output).vuewithUModalin new_string → component-specific guidance.tsfile → silent (non-vue passthrough)hookSpecificOutput.additionalContextSummary by cubic
Adds a PreToolUse hook to the
nuxt-uiplugin that detectsU*components in.vuefiles during Write/Edit and injects guidance to verify v4 APIs with MCP tools. Improves reliability and safety of the hook and tests.New Features
Write|Editon.vuefiles viaplugins/nuxt-ui/hooks/hooks.json(5s timeout).check-vue-components.shdetects<U*>and returns guidance throughhookSpecificOutput.additionalContext.mcp__nuxt-ui-remote__get_componentandmcp__nuxt-ui-remote__list_components, plus common migration tips (e.g.,UFormGroup→UFormField,v-model:open)..vue, when noU*components are present, or when components only appear inold_stringduring Edit.Bug Fixes
mcp__nuxt-ui-remote__*to match runtime tool names (docs/spec updated for consistency).jqmapfile defaults, tolerate no matches withgrep ... || 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.