Skip to content

Commit 3abeb0a

Browse files
authored
feat(please-plugins): add plugin discovery and setup for pleaseai marketplace (#119)
* docs(track): nuxt-session-hook-20260328 추가 * docs(track): update spec and plan with PostToolUse hook and async SessionStart * docs(track): expand to standalone plugin-recommender plugin Repurpose nuxt-specific hook track to a general-purpose plugin recommender that covers all npm-based marketplace plugins. * chore(track): nuxt-session-hook-20260328 구현 시작 * feat(plugin-recommender): add plugin manifest * feat(plugin-recommender): add dependency detection hook with tests Implements SessionStart and PostToolUse hook that detects npm packages in package.json and recommends corresponding marketplace plugins. Supports 20 package-to-plugin mappings including nuxt, vue, pinia, vitest, prisma, supabase, and more. * feat(plugin-recommender): add hooks.json registration SessionStart (async) + PostToolUse for bun/npm/pnpm install commands. * feat(plugin-recommender): add to marketplace registry * docs(track): update progress for nuxt-session-hook-20260328 * fix(plugin-recommender): rename shadowed variable in detectPackages Rename inner loop variable from `pkg` to `pkgName` to avoid shadowing the outer function parameter. * refactor(plugin-recommender): extract plugin mappings to JSON file Move PLUGIN_MAPPINGS data to plugin-mappings.json for easier maintenance without touching TypeScript code. * chore: apply AI code review suggestions for plugin-recommender hooks - Refactor main() into detectForEvent() helper to eliminate duplication between SessionStart and PostToolUse branches - Simplify hooks.json PostToolUse config to a single Bash matcher instead of five repetitive if-filtered entries - Fix extractPackagesFromCommand to strip version/tag suffixes (e.g. pkg@latest → pkg) so PostToolUse matching works correctly; use lookbehind to preserve scoped package prefixes (@scope/pkg) - Add test cases for version suffix stripping * fix(plugin-recommender): restore install-command filter in PostToolUse hook Collapse the five per-command if-filters into a single pipe-separated if pattern so the recommender only spawns on package install commands, avoiding overhead on unrelated Bash usage. * feat(plugin-recommender): detect tooling from lock files and packageManager Add tooling-mappings.json for non-npm-package detection: - pnpm-lock.yaml or packageManager: pnpm → pnpm plugin - turbo.json → turborepo plugin Easily extensible via tooling-mappings.json. * feat(plugin-recommender): add /plugin-recommender:setup command Interactive setup that scans dependencies, shows installed vs available plugins, and lets users install all at once. * refactor(plugin-recommender): rename to please-plugins Rename plugin-recommender → please-plugins for better naming. Command: /please-plugins:setup * feat(please-plugins): add mappings for flutter, sentry, posthog, playwright, and more New plugin-mappings: sentry, posthog, playwright-cli, tosspayments, slack-agent, mcp-neo4j. Added @nuxt/content to docus mapping. New tooling-mapping: pubspec.yaml → flutter. * fix(please-plugins): rename lockFiles to files in tooling mappings The field contained indicator files (turbo.json, pubspec.yaml) that aren't lock files. Renamed to 'files' for accuracy. Also use pubspec.lock as primary Flutter indicator with pubspec.yaml fallback.
1 parent 211691e commit 3abeb0a

15 files changed

Lines changed: 1019 additions & 1 deletion

File tree

.claude-plugin/marketplace.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,14 @@
479479
"source": "github",
480480
"repo": "makenotion/claude-code-notion-plugin"
481481
}
482+
},
483+
{
484+
"name": "please-plugins",
485+
"description": "Auto-detect project dependencies and recommend matching Claude Code plugins from the pleaseai marketplace",
486+
"category": "tooling",
487+
"keywords": ["please-plugins", "discovery", "marketplace", "auto-detect", "setup"],
488+
"tags": ["tooling", "discovery"],
489+
"source": "./plugins/please-plugins"
482490
}
483491
]
484492
}

.please/config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
schema_version: 2 # Config schema version (do not edit manually)
2+
13
language: en # Output language (ko | en)
24

35
# Document path overrides (optional — defaults shown)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"track_id": "nuxt-session-hook-20260328",
3+
"type": "feature",
4+
"status": "in_progress",
5+
"created_at": "2026-03-28T22:24:12+09:00",
6+
"updated_at": "2026-03-28T22:35:00+09:00",
7+
"issue": "",
8+
"pr": "",
9+
"project": ""
10+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Plan: Plugin Recommender
2+
3+
> Track: nuxt-session-hook-20260328
4+
> Spec: [spec.md](./spec.md)
5+
6+
## Overview
7+
8+
- **Source**: [spec.md](./spec.md)
9+
- **Issue**: TBD
10+
- **Created**: 2026-03-28
11+
- **Approach**: Minimal Change
12+
13+
## Purpose
14+
15+
After this change, developers will automatically see recommendations to install relevant Claude Code plugins based on npm packages detected in their `package.json`. Recommendations appear at session start (async, non-blocking) and after running package install commands. They can verify it works by starting a Claude Code session in a project with `@nuxt/ui` and seeing the recommendation to install `nuxt-ui@pleaseai`.
16+
17+
## Context
18+
19+
The `pleaseai` marketplace offers many plugins that correspond to npm packages (nuxt, vue, pinia, vueuse, vitest, prisma, supabase, etc.), but users may not know these plugins exist. Currently there is no automatic discovery mechanism.
20+
21+
This feature creates a standalone `plugin-recommender` plugin with two complementary hooks:
22+
23+
1. **SessionStart hook** (`async: true`): Scans `package.json` at session start in the background, without blocking session initialization. Outputs `systemMessage` (user-facing) and `additionalContext` (Claude-facing).
24+
25+
2. **PostToolUse hook** (`matcher: "Bash"`): Fires after `bun add`, `npm install/add`, `pnpm add/install` commands. When a user installs a matching package during the session, immediately recommends the corresponding plugin.
26+
27+
Both hooks share detection logic in a single TypeScript file. The package-to-plugin mapping is a simple data array, making it trivial to add new mappings as plugins are added to the marketplace.
28+
29+
The existing `worktree-context.ts` hook provides the reference TypeScript pattern: stdin-based JSON input, pure functions for testability, and `import.meta.main` guard.
30+
31+
Non-goals: No auto-installation, no monorepo workspace scanning, no non-npm ecosystems.
32+
33+
## Architecture Decision
34+
35+
Standalone plugin at `plugins/plugin-recommender/` rather than embedding hooks in individual framework plugins. This centralizes the recommendation logic and avoids duplication across plugins.
36+
37+
The hook uses `hooks/hooks.json` (auto-loaded by Claude Code) rather than `plugin.json`'s `hooks` field. Pure functions are exported for unit testing, and `import.meta.main` guard separates entry point from testable logic.
38+
39+
For installed plugin detection, the hook checks `.claude/settings.json` (project-level) and `~/.claude/settings.json` (user-level) for `enabledPlugins` entries matching `pluginName@pleaseai`.
40+
41+
A single script handles both events via `hook_event_name` field from stdin JSON.
42+
43+
## Tasks
44+
45+
- [x] T001 Create plugin manifest (file: plugins/plugin-recommender/.claude-plugin/plugin.json)
46+
- [x] T002 Create dependency detection hook (file: plugins/plugin-recommender/hooks/check-dependencies.ts) (depends on T001)
47+
- [x] T003 Create hooks.json registration (file: plugins/plugin-recommender/hooks/hooks.json) (depends on T002)
48+
- [x] T004 [P] Create unit tests for hook (file: plugins/plugin-recommender/hooks/check-dependencies.test.ts) (depends on T002)
49+
- [x] T005 Add plugin-recommender to marketplace.json (file: .claude-plugin/marketplace.json) (depends on T001)
50+
51+
## Progress
52+
53+
- [x] (2026-03-28 22:35 KST) T001 Create plugin manifest
54+
- [x] (2026-03-28 22:36 KST) T002 Create dependency detection hook
55+
Evidence: `bun test` → 32 tests passed (62ms)
56+
- [x] (2026-03-28 22:37 KST) T003 Create hooks.json registration
57+
- [x] (2026-03-28 22:36 KST) T004 Create unit tests for hook
58+
Evidence: `bun test` → 32 tests passed, 93 expect() calls
59+
- [x] (2026-03-28 22:38 KST) T005 Add plugin-recommender to marketplace.json
60+
61+
## Key Files
62+
63+
### Create
64+
65+
- `plugins/plugin-recommender/.claude-plugin/plugin.json` — Plugin manifest with name, version, description
66+
- `plugins/plugin-recommender/hooks/check-dependencies.ts` — Main hook with package detection, plugin status checking, and JSON output
67+
- `plugins/plugin-recommender/hooks/hooks.json` — Hook registration: SessionStart (async) + PostToolUse (matcher: Bash)
68+
- `plugins/plugin-recommender/hooks/check-dependencies.test.ts` — Unit tests for detection/filtering functions
69+
70+
### Modify
71+
72+
- `.claude-plugin/marketplace.json` — Add `plugin-recommender` entry
73+
74+
### Reuse (Reference)
75+
76+
- `plugins/worktree/hooks/worktree-context.ts` — TypeScript hook pattern (stdin parsing, JSON output, `import.meta.main`)
77+
- `plugins/worktree/hooks/worktree-context.test.ts` — Test pattern for TypeScript hooks
78+
79+
## Verification
80+
81+
### Automated Tests
82+
83+
- [ ] Detects `@nuxt/ui` in dependencies and returns `nuxt-ui` recommendation
84+
- [ ] Detects `pinia` or `@pinia/nuxt` and returns `pinia` recommendation
85+
- [ ] Detects `vitest` in devDependencies and returns `vitest` recommendation
86+
- [ ] Detects `@prisma/client` and returns `prisma` recommendation
87+
- [ ] Detects multiple packages and returns all recommendations
88+
- [ ] Returns empty result when no matching packages found
89+
- [ ] Returns empty result when all matching plugins are already installed
90+
- [ ] Handles missing `package.json` gracefully (no error, no output)
91+
- [ ] Handles malformed `package.json` gracefully
92+
- [ ] Output JSON has valid `hookSpecificOutput` with `systemMessage` and `additionalContext`
93+
- [ ] PostToolUse: extracts package name from `bun add @nuxt/ui` command
94+
- [ ] PostToolUse: extracts package name from `npm install prisma` command
95+
- [ ] PostToolUse: extracts package name from `pnpm add @vueuse/nuxt` command
96+
- [ ] Adding a new mapping requires only a data change
97+
98+
### Observable Outcomes
99+
100+
- After starting Claude Code in a project with `@nuxt/ui` installed, the session shows a recommendation to install `nuxt-ui@pleaseai`
101+
- After running `bun add @prisma/client`, the PostToolUse hook shows the prisma recommendation
102+
103+
## Decision Log
104+
105+
- Decision: Standalone `plugin-recommender` plugin instead of per-framework hooks
106+
Rationale: Centralizes recommendation logic, avoids duplication, covers all npm-based plugins in one place
107+
Date/Author: 2026-03-28 / user + Claude
108+
- Decision: Use `hooks/hooks.json` over `plugin.json` hooks field
109+
Rationale: CLAUDE.md convention — `hooks/hooks.json` is auto-loaded
110+
Date/Author: 2026-03-28 / Claude
111+
- Decision: Check both project-level and user-level `.claude/settings.json` for installed plugins
112+
Rationale: Users may have plugins enabled at project or global scope
113+
Date/Author: 2026-03-28 / Claude
114+
- Decision: Use `async: true` for SessionStart hook
115+
Rationale: Package detection is informational and should not block session initialization
116+
Date/Author: 2026-03-28 / user + Claude
117+
- Decision: Add PostToolUse hook for package install commands
118+
Rationale: Recommend plugins immediately when a matching package is installed
119+
Date/Author: 2026-03-28 / user + Claude
120+
- Decision: Single script handles both events via `hook_event_name` field
121+
Rationale: Shared detection logic avoids code duplication
122+
Date/Author: 2026-03-28 / Claude
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Plugin Recommender
2+
3+
> Track: nuxt-session-hook-20260328
4+
5+
## Overview
6+
7+
Create a standalone `plugin-recommender` plugin that detects npm packages in the user's `package.json` and recommends installing corresponding marketplace plugins from `pleaseai`. Two hooks work together:
8+
9+
1. **SessionStart hook** (`async: true`): Scans `package.json` at session start in the background
10+
2. **PostToolUse hook**: Triggers after `bun add`, `npm install/add`, `pnpm add/install` commands to recommend plugins for newly installed packages
11+
12+
Both hooks output `systemMessage` (user-facing install recommendations) and `additionalContext` (Claude-facing context about available plugins).
13+
14+
## Requirements
15+
16+
### Functional Requirements
17+
18+
- [ ] FR-1: Create a standalone plugin at `plugins/plugin-recommender/` with `.claude-plugin/plugin.json`
19+
- [ ] FR-2: Create a TypeScript hook (`hooks/check-dependencies.ts`) with shared detection logic for both SessionStart and PostToolUse events
20+
- [ ] FR-3: Detect npm packages and map them to marketplace plugins:
21+
| npm package(s) | Marketplace plugin |
22+
|---|---|
23+
| `nuxt` | `nuxt` |
24+
| `@nuxt/ui` | `nuxt-ui` |
25+
| `@nuxtjs/seo`, `nuxt-seo-utils` | `nuxt-seo` |
26+
| `vue` | `vue` |
27+
| `pinia`, `@pinia/nuxt` | `pinia` |
28+
| `@vueuse/nuxt`, `@vueuse/core` | `vueuse` |
29+
| `vitest` | `vitest` |
30+
| `unocss`, `@unocss/nuxt` | `unocss` |
31+
| `vitepress` | `vitepress` |
32+
| `vite` | `vite` |
33+
| `firebase`, `firebase-admin` | `firebase` |
34+
| `@prisma/client`, `prisma` | `prisma` |
35+
| `@supabase/supabase-js` | `supabase` |
36+
| `better-auth` | `better-auth` |
37+
| `ai`, `@ai-sdk/openai` | `ai-sdk` |
38+
| `mastra`, `@mastra/core` | `mastra` |
39+
| `stripe`, `@stripe/stripe-js` | `stripe` |
40+
| `@slidev/cli` | `slidev` |
41+
| `tsdown` | `tsdown` |
42+
| `docus` | `docus` |
43+
- [ ] FR-4: Only recommend plugins that are **not already installed** by the user
44+
- [ ] FR-5: Output `systemMessage` (user-facing) with install commands (`/plugin install <name>@pleaseai`) for each detected-but-not-installed plugin
45+
- [ ] FR-6: Output `additionalContext` (Claude-facing) with guidance to leverage the recommended plugins for better assistance
46+
- [ ] FR-7: If no matching packages are found or all matching plugins are already installed, exit silently (no output)
47+
- [ ] FR-8: Create `hooks/hooks.json` to register both hooks:
48+
- SessionStart with `async: true` (non-blocking background execution)
49+
- PostToolUse with `matcher: "Bash"` and `if` conditions for package install commands
50+
- [ ] FR-9: Hook must handle missing `package.json` gracefully (exit silently)
51+
- [ ] FR-10: PostToolUse hook must detect `bun add`, `npm install`, `npm add`, `pnpm add`, `pnpm install` commands
52+
- [ ] FR-11: The package-to-plugin mapping must be easily extensible (simple data structure, not scattered logic)
53+
- [ ] FR-12: Add `plugin-recommender` to `marketplace.json`
54+
55+
### Non-functional Requirements
56+
57+
- [ ] NFR-1: Hook must complete within 10 seconds (timeout)
58+
- [ ] NFR-2: Hook must not fail if `package.json` is malformed (graceful error handling)
59+
- [ ] NFR-3: TypeScript implementation must be testable with Vitest
60+
61+
## Acceptance Criteria
62+
63+
- [ ] AC-1: When a project has `@nuxt/ui` in dependencies and `nuxt-ui` plugin is not installed, the hook recommends installing `nuxt-ui@pleaseai`
64+
- [ ] AC-2: When multiple matching packages are found, all corresponding plugins are recommended in a single output
65+
- [ ] AC-3: When all matching plugins are already installed, no output is produced
66+
- [ ] AC-4: When `package.json` does not exist, no output is produced and no error occurs
67+
- [ ] AC-5: The hook output contains valid JSON with both `systemMessage` and `additionalContext` fields
68+
- [ ] AC-6: After running `bun add @nuxt/ui`, the PostToolUse hook recommends installing `nuxt-ui@pleaseai`
69+
- [ ] AC-7: The SessionStart hook runs asynchronously (does not block session initialization)
70+
- [ ] AC-8: Adding a new package-to-plugin mapping requires only a data change, not logic changes
71+
72+
## Out of Scope
73+
74+
- Auto-installing plugins without user action
75+
- Checking plugin version compatibility
76+
- Detecting packages in monorepo workspaces (only checks root `package.json`)
77+
- Non-npm package detection (e.g., Flutter/Dart, Python, Go)
78+
79+
## Assumptions
80+
81+
- The hook can determine installed plugins by checking `.claude/settings.json` for `enabledPlugins`
82+
- `bun` is available in the user's environment
83+
- The `package.json` is at the working directory root

.please/docs/tracks/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
| Track | Feature | Type | Issue | Started | Status |
88
|-------|---------|------|-------|---------|--------|
99
| [nuxt-ui-hook-guidance-20260328](active/nuxt-ui-hook-guidance-20260328/plan.md) | Nuxt UI Hook Guidance | feature | TBD | 2026-03-28 | in_progress |
10+
| [nuxt-session-hook-20260328](active/nuxt-session-hook-20260328/) | Plugin Recommender | feature || 2026-03-28 | in_progress |
1011

1112
## Recently Completed
1213

.release-please-manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@
3434
"plugins/markitdown": "1.0.0",
3535
"plugins/ast-grep": "1.0.0",
3636
"plugins/chat-sdk": "1.0.0",
37-
"plugins/docus": "1.0.0"
37+
"plugins/docus": "1.0.0",
38+
"plugins/please-plugins": "1.0.0"
3839
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "please-plugins",
3+
"version": "1.0.0",
4+
"description": "Auto-detect project dependencies and recommend matching Claude Code plugins from the pleaseai marketplace",
5+
"author": {
6+
"name": "Passion Factory",
7+
"url": "https://github.com/pleaseai"
8+
},
9+
"homepage": "https://github.com/pleaseai/claude-code-plugins",
10+
"repository": "https://github.com/pleaseai/claude-code-plugins",
11+
"license": "MIT",
12+
"keywords": [
13+
"please-plugins",
14+
"discovery",
15+
"marketplace",
16+
"auto-detect",
17+
"setup"
18+
]
19+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
description: Scan project dependencies and install recommended Claude Code plugins
3+
allowed-tools: Read, Bash, Glob, Grep, AskUserQuestion
4+
---
5+
6+
# Plugin Recommender Setup
7+
8+
Scan the current project's `package.json` and tooling files to detect packages that have corresponding Claude Code plugins in the `pleaseai` marketplace, then help the user install them.
9+
10+
## Step 1: Scan Dependencies
11+
12+
Read `package.json` in the current working directory. If it doesn't exist, inform the user and stop.
13+
14+
Read the plugin mappings and tooling mappings from the plugin's data files:
15+
16+
```bash
17+
cat "${CLAUDE_PLUGIN_ROOT}/hooks/plugin-mappings.json"
18+
cat "${CLAUDE_PLUGIN_ROOT}/hooks/tooling-mappings.json"
19+
```
20+
21+
Parse the project's `dependencies` and `devDependencies` to find matches against the plugin mappings. Also check for tooling indicators:
22+
- Lock files: `pnpm-lock.yaml`, `turbo.json`
23+
- `packageManager` field in `package.json`
24+
25+
## Step 2: Check Installed Plugins
26+
27+
Read `.claude/settings.json` (project-level) to check which plugins are already installed. Look for entries in `enabledPlugins` matching `<pluginName>@pleaseai`.
28+
29+
## Step 3: Show Results
30+
31+
Present the scan results to the user, categorized:
32+
33+
```
34+
AskUserQuestion({
35+
questions: [{
36+
header: "Plugins",
37+
question: "Detected packages and their plugin status:\n\n{for each detected plugin: ✅ installed / ⬜ not installed — source package}\n\nSelect plugins to install:",
38+
multiSelect: true,
39+
options: [
40+
// Only list NOT-installed plugins as selectable options
41+
{ label: "{pluginName}", description: "Detected: {source package or tooling indicator}" },
42+
...
43+
]
44+
}]
45+
})
46+
```
47+
48+
If all detected plugins are already installed, inform the user: "All recommended plugins are already installed!"
49+
50+
If no packages match any plugin mappings, inform the user: "No matching plugins found for this project's dependencies."
51+
52+
## Step 4: Install Selected Plugins
53+
54+
For each selected plugin, run the install command:
55+
56+
```bash
57+
claude plugin install {pluginName}@pleaseai
58+
```
59+
60+
Show the result of each installation.
61+
62+
## Step 5: Summary
63+
64+
Show a summary of what was installed:
65+
66+
```
67+
Plugin Recommender Setup Complete!
68+
69+
Installed: {count} plugins
70+
- {pluginName1}
71+
- {pluginName2}
72+
73+
Already installed: {count} plugins
74+
- {pluginName3}
75+
76+
To manage plugins: /plugin list
77+
```

0 commit comments

Comments
 (0)