Initial commit
This commit is contained in:
14
.claude-plugin/plugin.json
Normal file
14
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "essentials",
|
||||||
|
"description": "Essential MCP servers, requirements management, and intelligent instruction analysis for enhanced Claude Code development workflow",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"author": {
|
||||||
|
"name": "bandofai"
|
||||||
|
},
|
||||||
|
"commands": [
|
||||||
|
"./commands"
|
||||||
|
],
|
||||||
|
"hooks": [
|
||||||
|
"./hooks"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# essentials
|
||||||
|
|
||||||
|
Essential MCP servers, requirements management, and intelligent instruction analysis for enhanced Claude Code development workflow
|
||||||
662
commands/brainstorm.md
Normal file
662
commands/brainstorm.md
Normal file
@@ -0,0 +1,662 @@
|
|||||||
|
# Interactive Requirements Brainstorming with Intelligent Analysis v2.0
|
||||||
|
|
||||||
|
Start an interactive Q&A session with deep codebase analysis and dynamically generated questions.
|
||||||
|
|
||||||
|
**⚠️ CRITICAL: THIS COMMAND ONLY GATHERS REQUIREMENTS - NEVER IMPLEMENTS CODE ⚠️**
|
||||||
|
|
||||||
|
## STRICT OPERATING MODE: READ-ONLY ANALYSIS
|
||||||
|
|
||||||
|
**YOU MUST NEVER:**
|
||||||
|
- Write, edit, or modify any code files
|
||||||
|
- Create new source code files (except in `.requirements/` folder)
|
||||||
|
- Execute implementation commands
|
||||||
|
- Make code changes of any kind
|
||||||
|
- Use Edit, Write, or code modification tools
|
||||||
|
- Suggest or execute implementation during this workflow
|
||||||
|
|
||||||
|
**YOU MAY ONLY:**
|
||||||
|
- Read and analyze existing code
|
||||||
|
- Search and explore the codebase
|
||||||
|
- Research best practices
|
||||||
|
- Ask questions
|
||||||
|
- Create requirement documents in `.requirements/` folder
|
||||||
|
- Generate specifications and recommendations
|
||||||
|
|
||||||
|
**GOAL:** Gather complete, actionable requirements so implementation can happen later with `/implement` command.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Full Workflow
|
||||||
|
|
||||||
|
### Phase 1: Setup & Initialization
|
||||||
|
|
||||||
|
When user runs `/brainstorm <description>`:
|
||||||
|
|
||||||
|
1. **Parse the request**
|
||||||
|
- Extract feature description from arguments
|
||||||
|
- Generate slug: kebab-case version (e.g., "add user logging" → "user-logging")
|
||||||
|
|
||||||
|
2. **Create timestamped requirement folder**
|
||||||
|
- Format: `.requirements/YYYY-MM-DD-HHMM-[slug]/`
|
||||||
|
- Example: `.requirements/2025-10-25-1430-user-logging/`
|
||||||
|
|
||||||
|
3. **Initialize files**
|
||||||
|
- `01-initial-request.md` - Save user's original request verbatim
|
||||||
|
- `metadata.json` - Initialize tracking structure
|
||||||
|
- Update `.requirements/_current-requirement` with folder name
|
||||||
|
|
||||||
|
4. **Initialize metadata.json**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "user-logging",
|
||||||
|
"slug": "user-logging",
|
||||||
|
"started": "2025-10-25T14:30:00Z",
|
||||||
|
"lastUpdated": "2025-10-25T14:30:00Z",
|
||||||
|
"status": "active",
|
||||||
|
"phase": "discovery",
|
||||||
|
"originalRequest": "add user logging",
|
||||||
|
"progress": {
|
||||||
|
"discovery": { "generated": false, "answered": 0, "total": 0 },
|
||||||
|
"analysis": { "status": "pending" },
|
||||||
|
"expert": { "generated": false, "answered": 0, "total": 0 }
|
||||||
|
},
|
||||||
|
"contextFiles": [],
|
||||||
|
"relatedFeatures": [],
|
||||||
|
"toolsAvailable": ["serena", "context7", "WebSearch"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Announce**: "Starting requirements gathering for: [description]"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 2: Generate & Ask Discovery Questions
|
||||||
|
|
||||||
|
**IMPORTANT: Questions are NOT hardcoded - they are generated dynamically based on the user's request!**
|
||||||
|
|
||||||
|
#### Step 2.1: Generate Discovery Questions
|
||||||
|
|
||||||
|
Use **sequential thinking** to generate contextual questions:
|
||||||
|
|
||||||
|
```
|
||||||
|
Task: Generate 5-7 discovery questions to gather requirements for: "[user's request]"
|
||||||
|
|
||||||
|
Guidelines:
|
||||||
|
- Analyze what's ambiguous or unclear in the request
|
||||||
|
- Focus on WHAT the user wants, not HOW to implement
|
||||||
|
- Questions should clarify scope, behavior, and expectations
|
||||||
|
- Each question needs 2-5 numbered options with smart defaults
|
||||||
|
- Mark one option as [default - brief reason why]
|
||||||
|
- Include "Other (please specify)" for flexibility
|
||||||
|
- Mix yes/no with multiple choice appropriately
|
||||||
|
|
||||||
|
Focus areas based on request context:
|
||||||
|
- Scope and boundaries of the feature
|
||||||
|
- User interactions and workflows
|
||||||
|
- Data/content being worked with
|
||||||
|
- Performance or scale expectations
|
||||||
|
- Security/privacy considerations
|
||||||
|
- Integration with existing systems
|
||||||
|
|
||||||
|
Output format for each question:
|
||||||
|
## Q[N]: [Question Title]
|
||||||
|
```
|
||||||
|
[Question text that makes sense for THIS request]
|
||||||
|
|
||||||
|
1. [Option 1] [default - reason based on request context]
|
||||||
|
2. [Option 2]
|
||||||
|
3. [Option 3]
|
||||||
|
4. Other (please specify)
|
||||||
|
```
|
||||||
|
|
||||||
|
Available tools: serena (code analysis), context7 (library docs), WebSearch (best practices)
|
||||||
|
|
||||||
|
Save all generated questions to: 02-discovery-questions.md
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example output for "add user logging":**
|
||||||
|
```markdown
|
||||||
|
## Q1: What should be logged?
|
||||||
|
```
|
||||||
|
What information should the logging system capture?
|
||||||
|
|
||||||
|
1. Error details and stack traces [default - most common use case]
|
||||||
|
2. User actions and events
|
||||||
|
3. Both errors and user actions
|
||||||
|
4. Other (please specify)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Q2: Where should logs be stored?
|
||||||
|
```
|
||||||
|
What's the preferred log storage solution?
|
||||||
|
|
||||||
|
1. Local files (rotating logs) [default - simplest approach]
|
||||||
|
2. Database (queryable logs)
|
||||||
|
3. External service (e.g., Datadog, LogRocket)
|
||||||
|
4. Other (please specify)
|
||||||
|
```
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example output for "build user dashboard":**
|
||||||
|
```markdown
|
||||||
|
## Q1: What data should the dashboard display?
|
||||||
|
```
|
||||||
|
What key metrics or information will users see?
|
||||||
|
|
||||||
|
1. User activity and engagement [default - common dashboard need]
|
||||||
|
2. System metrics and performance
|
||||||
|
3. Business analytics and reports
|
||||||
|
4. Other (please specify)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Q2: Should the dashboard update in real-time?
|
||||||
|
```
|
||||||
|
How current should the dashboard data be?
|
||||||
|
|
||||||
|
1. Static/on-page-load [default - simplest implementation]
|
||||||
|
2. Real-time updates (WebSocket/polling)
|
||||||
|
3. Refresh on user action
|
||||||
|
4. Other (please specify)
|
||||||
|
```
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2.2: Ask Questions One at a Time
|
||||||
|
|
||||||
|
**UX Rules:**
|
||||||
|
- Present ONE question at a time
|
||||||
|
- Wait for user response before next question
|
||||||
|
- Accept numbered responses (e.g., "1", "2") or free text for "Other"
|
||||||
|
- Support revisions: user can say "back", "change Q2", or "restart"
|
||||||
|
- Show progress after every 2-3 questions: "So far: [brief summary]..."
|
||||||
|
- If user provides just number, auto-select that option
|
||||||
|
|
||||||
|
**After all discovery questions answered:**
|
||||||
|
- Save answers to `03-discovery-answers.md`
|
||||||
|
- Update `metadata.json` progress
|
||||||
|
- Announce: "Discovery complete. Starting intelligent codebase analysis..."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 3: Intelligent Codebase Analysis (Autonomous)
|
||||||
|
|
||||||
|
**NO USER INTERACTION - Fully autonomous**
|
||||||
|
|
||||||
|
**⚠️ CRITICAL REMINDER: READ-ONLY ANALYSIS ONLY - DO NOT IMPLEMENT ANYTHING ⚠️**
|
||||||
|
|
||||||
|
Use **sequential thinking** for intelligent analysis:
|
||||||
|
|
||||||
|
```
|
||||||
|
Task: Analyze codebase to support implementing: "[user's request]"
|
||||||
|
|
||||||
|
**CRITICAL CONSTRAINTS:**
|
||||||
|
- DO NOT write, edit, or modify any code files
|
||||||
|
- DO NOT create new source code files
|
||||||
|
- DO NOT use Edit, Write, or any code modification tools
|
||||||
|
- ONLY read, search, and analyze existing code
|
||||||
|
- ONLY create requirement documents in .requirements/ folder
|
||||||
|
- Your role is RESEARCH and SPECIFICATION, not implementation
|
||||||
|
|
||||||
|
Context from discovery phase:
|
||||||
|
[Include summary of all discovery answers]
|
||||||
|
|
||||||
|
Your objectives:
|
||||||
|
1. Understand current architecture and technology stack (READ-ONLY)
|
||||||
|
2. Find similar features or related implementations (READ-ONLY)
|
||||||
|
3. Identify specific files that will need modification (DOCUMENT, don't modify)
|
||||||
|
4. Research best practices for this type of feature (RESEARCH ONLY)
|
||||||
|
5. Determine integration points with existing code (ANALYZE, don't implement)
|
||||||
|
6. Generate implementation recommendations with rationale (RECOMMEND, don't execute)
|
||||||
|
|
||||||
|
Available tools (READ-ONLY usage):
|
||||||
|
- serena: For finding symbols, searching patterns, analyzing code structure
|
||||||
|
* Use find_symbol to locate classes/functions
|
||||||
|
* Use search_for_pattern for code patterns
|
||||||
|
* Use find_referencing_symbols for dependencies
|
||||||
|
* Use get_symbols_overview for file structure
|
||||||
|
* DO NOT use replace_symbol_body, insert_after_symbol, insert_before_symbol
|
||||||
|
|
||||||
|
- context7: For library/framework documentation
|
||||||
|
* Research best practices for libraries used in codebase
|
||||||
|
|
||||||
|
- WebSearch: For industry best practices
|
||||||
|
* Search for implementation patterns
|
||||||
|
* Find security considerations
|
||||||
|
* Discover performance optimization techniques
|
||||||
|
|
||||||
|
Output required in 04-context-findings.md:
|
||||||
|
|
||||||
|
# Codebase Analysis Findings
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
[High-level structure - technology stack, patterns used]
|
||||||
|
|
||||||
|
## Similar Features Found
|
||||||
|
- `[file-path]` - [what it does, why similar]
|
||||||
|
- [Include code snippets showing patterns]
|
||||||
|
|
||||||
|
## Patterns to Follow
|
||||||
|
```[language]
|
||||||
|
// Example from [file-path]:[line-number]
|
||||||
|
[relevant code snippet]
|
||||||
|
```
|
||||||
|
[Explanation of pattern and why it's relevant]
|
||||||
|
|
||||||
|
## Files to Modify/Create
|
||||||
|
- `[path]` - [what changes needed]
|
||||||
|
- `[path]` - [what to add]
|
||||||
|
|
||||||
|
## Integration Points
|
||||||
|
[How this feature connects to existing code]
|
||||||
|
|
||||||
|
## Best Practices Research
|
||||||
|
[External best practices found via context7/WebSearch]
|
||||||
|
|
||||||
|
## Recommended Approach
|
||||||
|
[Specific implementation strategy with rationale]
|
||||||
|
|
||||||
|
## Technical Constraints
|
||||||
|
[Limitations, dependencies, considerations]
|
||||||
|
```
|
||||||
|
|
||||||
|
**After Phase 3:**
|
||||||
|
- Save findings to `04-context-findings.md`
|
||||||
|
- Update `metadata.json` with `contextFiles` and `relatedFeatures`
|
||||||
|
- Announce: "✅ Read-only analysis complete. Found [N] related features and [N] files to modify (documentation only - no code was changed). Generating expert questions..."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 4: Generate & Ask Expert Questions
|
||||||
|
|
||||||
|
**Again, questions are dynamically generated based on findings!**
|
||||||
|
|
||||||
|
#### Step 4.1: Generate Expert Questions
|
||||||
|
|
||||||
|
Use **sequential thinking** to generate implementation questions:
|
||||||
|
|
||||||
|
```
|
||||||
|
Task: Generate 5-7 expert implementation questions
|
||||||
|
|
||||||
|
Input context:
|
||||||
|
- Original request: "[user's request]"
|
||||||
|
- Discovery answers: [summary from Phase 2]
|
||||||
|
- Codebase findings: [summary from 04-context-findings.md]
|
||||||
|
|
||||||
|
Guidelines:
|
||||||
|
- Reference ACTUAL files and patterns found in Phase 3
|
||||||
|
- Questions should finalize implementation approach
|
||||||
|
- Include numbered options with defaults based on codebase patterns
|
||||||
|
- Explain WHY each default makes sense (cite specific findings)
|
||||||
|
- Focus on HOW to implement, not WHAT to build
|
||||||
|
|
||||||
|
Question types to consider:
|
||||||
|
- Architecture decisions (extend existing vs create new)
|
||||||
|
- File/component organization
|
||||||
|
- Library/framework usage patterns
|
||||||
|
- Code pattern consistency
|
||||||
|
- Integration approach
|
||||||
|
- Testing strategy
|
||||||
|
|
||||||
|
Output format for each question:
|
||||||
|
## Q[N]: [Question Title]
|
||||||
|
```
|
||||||
|
[Question text referencing actual findings]
|
||||||
|
|
||||||
|
1. [Option 1] [default - reason citing analysis]
|
||||||
|
2. [Option 2]
|
||||||
|
3. [Option 3]
|
||||||
|
|
||||||
|
**Why this matters:**
|
||||||
|
[Explanation based on Phase 3 findings - cite files, patterns discovered]
|
||||||
|
```
|
||||||
|
|
||||||
|
Save all generated questions to: 05-expert-questions.md
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example output for "add user logging" after finding existing Logger:**
|
||||||
|
```markdown
|
||||||
|
## Q6: Should we extend the existing Logger?
|
||||||
|
```
|
||||||
|
Found Logger class at `src/utils/logger.ts`. How should we implement user logging?
|
||||||
|
|
||||||
|
1. Extend existing Logger class [default - maintains consistency]
|
||||||
|
2. Create separate UserLogger class
|
||||||
|
3. Add logging as middleware
|
||||||
|
|
||||||
|
**Why this matters:**
|
||||||
|
Analysis found that `AuthService` and `PaymentService` both use the
|
||||||
|
existing Logger at src/utils/logger.ts:15. The Logger already supports
|
||||||
|
Winston with rotating file transport. Extending it maintains architectural
|
||||||
|
consistency and reuses existing log rotation configuration.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Q7: Which log format should we use?
|
||||||
|
```
|
||||||
|
The existing Logger uses JSON format. Should user logging follow this pattern?
|
||||||
|
|
||||||
|
1. Yes, use JSON format [default - matches existing pattern]
|
||||||
|
2. Plain text format
|
||||||
|
3. Structured format (custom)
|
||||||
|
|
||||||
|
**Why this matters:**
|
||||||
|
Found 47 log statements across the codebase all using JSON format via
|
||||||
|
`logger.info({...})` pattern. The log aggregator at scripts/analyze-logs.ts
|
||||||
|
parses JSON format. Consistency enables easier log analysis.
|
||||||
|
```
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 4.2: Ask Expert Questions One at a Time
|
||||||
|
|
||||||
|
Same UX rules as Phase 2:
|
||||||
|
- ONE question at a time
|
||||||
|
- Accept numbered responses
|
||||||
|
- Support revisions
|
||||||
|
- Show progress summaries
|
||||||
|
|
||||||
|
**After all expert questions answered:**
|
||||||
|
- Save answers to `06-expert-answers.md`
|
||||||
|
- Update `metadata.json`
|
||||||
|
- Announce: "Expert questions complete. Generating comprehensive requirements specification..."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 5: Generate Comprehensive Requirements Spec
|
||||||
|
|
||||||
|
Create `07-requirements-spec.md` synthesizing all information:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# [Feature Name from Request]
|
||||||
|
|
||||||
|
**Created:** [ISO-8601 timestamp]
|
||||||
|
**Status:** draft
|
||||||
|
**Last Updated:** [ISO-8601 timestamp]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
[2-3 paragraph summary combining:
|
||||||
|
- Original request
|
||||||
|
- Discovery answers (what user wants)
|
||||||
|
- Analysis findings (current state)
|
||||||
|
- Implementation approach (expert decisions)]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Functional Requirements
|
||||||
|
[From discovery answers - what the feature must do]
|
||||||
|
|
||||||
|
1. [Requirement based on discovery Q&A]
|
||||||
|
2. [Requirement based on discovery Q&A]
|
||||||
|
3. [Additional requirements inferred]
|
||||||
|
|
||||||
|
### User Interactions
|
||||||
|
[Detailed workflow based on discovery answers]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technical Implementation
|
||||||
|
|
||||||
|
### Architecture Decision
|
||||||
|
[Based on expert Q&A - chosen approach with rationale]
|
||||||
|
|
||||||
|
### Files to Modify
|
||||||
|
[From Phase 3 analysis and Phase 4 decisions]
|
||||||
|
|
||||||
|
- **`[file-path]`**
|
||||||
|
- What to change: [description]
|
||||||
|
- Pattern to follow: [reference to similar code]
|
||||||
|
|
||||||
|
- **`[file-path]`**
|
||||||
|
- What to create: [description]
|
||||||
|
|
||||||
|
### Technology Stack
|
||||||
|
[Libraries/frameworks from analysis and decisions]
|
||||||
|
|
||||||
|
### Integration Points
|
||||||
|
[From Phase 3 analysis - how it connects]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Guide
|
||||||
|
|
||||||
|
### Patterns to Follow
|
||||||
|
|
||||||
|
```[language]
|
||||||
|
// From [similar-feature-file]:[line-number]
|
||||||
|
[code snippet showing pattern to follow]
|
||||||
|
```
|
||||||
|
**Apply this pattern for:** [explanation]
|
||||||
|
|
||||||
|
### Similar Features for Reference
|
||||||
|
- **`[file-path]`** - [what it does similarly, line numbers]
|
||||||
|
- **`[file-path]`** - [pattern to emulate]
|
||||||
|
|
||||||
|
### Step-by-Step Approach
|
||||||
|
1. [Concrete step from expert decisions]
|
||||||
|
2. [Concrete step referencing files]
|
||||||
|
3. [Concrete step with pattern reference]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
[Based on how similar features are tested]
|
||||||
|
|
||||||
|
- Unit tests: [approach based on codebase patterns]
|
||||||
|
- Integration tests: [if needed]
|
||||||
|
- Test files: [where to add tests, following existing structure]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Edge Cases & Constraints
|
||||||
|
|
||||||
|
### Edge Cases to Handle
|
||||||
|
[From discovery phase and analysis]
|
||||||
|
|
||||||
|
### Technical Constraints
|
||||||
|
[From Phase 3 analysis]
|
||||||
|
|
||||||
|
### Performance Considerations
|
||||||
|
[From discovery answers if applicable]
|
||||||
|
|
||||||
|
### Security Considerations
|
||||||
|
[From discovery answers and analysis]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] [Functional criterion from requirements]
|
||||||
|
- [ ] [Implementation criterion from expert decisions]
|
||||||
|
- [ ] [Integration criterion from analysis]
|
||||||
|
- [ ] [Testing criterion]
|
||||||
|
- [ ] [Documentation criterion]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Checklist
|
||||||
|
|
||||||
|
- [ ] Review similar implementation at `[file-path]:[line]`
|
||||||
|
- [ ] [Specific action from expert Q&A]
|
||||||
|
- [ ] Modify `[file-path]` following pattern from `[reference-file]`
|
||||||
|
- [ ] Add tests in `[test-file-path]` (follow existing test structure)
|
||||||
|
- [ ] Update documentation at `[doc-path]`
|
||||||
|
- [ ] [Any security/performance tasks]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- **Codebase Analysis:** `04-context-findings.md`
|
||||||
|
- **Similar Features:**
|
||||||
|
- `[file-path]` - [what to learn from it]
|
||||||
|
- **Best Practices:** [links from WebSearch/context7]
|
||||||
|
- **Dependencies:** [libraries mentioned in analysis]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
[Any assumptions made, open questions, or alternative approaches considered]
|
||||||
|
```
|
||||||
|
|
||||||
|
**After Phase 5:**
|
||||||
|
- Update `.requirements/_index.json`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user-logging": {
|
||||||
|
"created": "2025-10-25T14:30:00Z",
|
||||||
|
"status": "draft",
|
||||||
|
"lastModified": "2025-10-25T15:15:00Z",
|
||||||
|
"lastWorked": null,
|
||||||
|
"folder": ".requirements/2025-10-25-1430-user-logging/",
|
||||||
|
"relatedFeatures": ["auth-service", "payment-logging"],
|
||||||
|
"filesInvolved": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Show completion summary with **explicit reminder**:
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ Requirements gathering complete!
|
||||||
|
|
||||||
|
📁 All documentation saved to: .requirements/[folder]/
|
||||||
|
|
||||||
|
⚠️ IMPORTANT: NO CODE WAS MODIFIED
|
||||||
|
- This was a READ-ONLY analysis phase
|
||||||
|
- All findings are documented in requirement files
|
||||||
|
- No source code files were changed
|
||||||
|
|
||||||
|
📋 Next Steps:
|
||||||
|
1. Review requirements: .requirements/[folder]/07-requirements-spec.md
|
||||||
|
2. When ready to implement: /implement [slug]
|
||||||
|
|
||||||
|
This brainstorm session ONLY gathered requirements.
|
||||||
|
Implementation is a separate step that you control.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Question Flow
|
||||||
|
- **One at a time** - Never ask multiple questions simultaneously
|
||||||
|
- **Accept shorthand** - User can respond with just number (e.g., "1")
|
||||||
|
- **Auto-select defaults** - If user presses enter, use [default]
|
||||||
|
- **Follow-up intelligently** - Ask clarifying questions based on answers
|
||||||
|
- **Show progress** - Every 2-3 questions, show summary: "So far we have..."
|
||||||
|
- **Allow revisions** - User can say "back", "change Q3", or "restart from Q5"
|
||||||
|
|
||||||
|
### Analysis Phase
|
||||||
|
- **CRITICAL: READ-ONLY MODE** - Never use Edit, Write, or code modification tools
|
||||||
|
- Use sequential thinking for intelligent tool coordination
|
||||||
|
- Document file paths and line numbers in findings
|
||||||
|
- Capture code snippets from similar features (for documentation, not implementation)
|
||||||
|
- Research external best practices
|
||||||
|
- Generate hypotheses and verify them (through reading, not implementing)
|
||||||
|
- Track confidence in recommendations
|
||||||
|
- **STOP if you find yourself about to modify code** - This is requirements gathering only!
|
||||||
|
|
||||||
|
### Expert Questions
|
||||||
|
- Always reference actual files found in analysis
|
||||||
|
- Explain rationale for defaults using findings
|
||||||
|
- Give user flexibility to choose different approach
|
||||||
|
- Use numbered format for consistency
|
||||||
|
- Include "Why this matters" explanations
|
||||||
|
|
||||||
|
### Tool Usage
|
||||||
|
|
||||||
|
**ALLOWED TOOLS (Read-Only):**
|
||||||
|
- ✅ Read - Read existing files
|
||||||
|
- ✅ Glob - Find files by pattern
|
||||||
|
- ✅ Grep - Search code content
|
||||||
|
- ✅ serena (read-only): find_symbol, search_for_pattern, get_symbols_overview, find_referencing_symbols
|
||||||
|
- ✅ context7 - Research library documentation
|
||||||
|
- ✅ WebSearch - Research best practices
|
||||||
|
- ✅ Bash (read-only commands): ls, cat, find, grep, git log, etc.
|
||||||
|
|
||||||
|
**FORBIDDEN TOOLS (Implementation):**
|
||||||
|
- ❌ Edit - NEVER use
|
||||||
|
- ❌ Write - NEVER use (EXCEPT for creating files in `.requirements/` folder ONLY)
|
||||||
|
- ❌ NotebookEdit - NEVER use
|
||||||
|
- ❌ serena (write operations): replace_symbol_body, insert_after_symbol, insert_before_symbol, rename_symbol - NEVER use
|
||||||
|
- ❌ Bash (write commands): touch, cp, mv (except in `.requirements/`), git commit, npm install - NEVER use
|
||||||
|
- ❌ Task - NEVER use for implementation agents
|
||||||
|
- ❌ Any code generation or modification tool
|
||||||
|
|
||||||
|
**EXCEPTION:** Write tool is allowed ONLY for creating requirement documents in `.requirements/[timestamp-slug]/` folder. Never write to source code files.
|
||||||
|
|
||||||
|
**Guidelines:**
|
||||||
|
- Check which tools are available before use
|
||||||
|
- Prefer serena for symbol-level code analysis (READ-ONLY)
|
||||||
|
- Use context7 for library documentation
|
||||||
|
- Use WebSearch for industry best practices
|
||||||
|
- Always document which tools were used in metadata
|
||||||
|
- **IF YOU CATCH YOURSELF ABOUT TO USE A FORBIDDEN TOOL, STOP IMMEDIATELY**
|
||||||
|
|
||||||
|
### User Experience
|
||||||
|
- Announce phase transitions clearly
|
||||||
|
- Provide rich context for decisions
|
||||||
|
- Save progress after each phase
|
||||||
|
- Support interruption and resumption
|
||||||
|
- Allow user to review/revise any phase
|
||||||
|
- Generate actionable, specific outputs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why This Version Is Optimal
|
||||||
|
|
||||||
|
1. ✅ **Adaptive** - Questions change based on what user actually asked for
|
||||||
|
2. ✅ **Intelligent** - Sequential thinking powers all analysis and generation
|
||||||
|
3. ✅ **Context-aware** - Expert questions reference actual code found
|
||||||
|
4. ✅ **Simple tools** - Only serena, context7, WebSearch (no redundant tools)
|
||||||
|
5. ✅ **User-friendly** - Numbered choices, revisions, progress tracking
|
||||||
|
6. ✅ **Actionable** - Output includes specific files, patterns, and steps
|
||||||
|
7. ✅ **Flexible** - Works for any type of request (logging, UI, API, refactoring, etc.)
|
||||||
|
8. ✅ **Safe** - READ-ONLY mode prevents accidental implementation during requirements gathering
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Examples of Adaptive Behavior
|
||||||
|
|
||||||
|
### Request: "add logging to error handlers"
|
||||||
|
- Phase 2 generates questions about: log levels, storage, PII handling, error context
|
||||||
|
- Phase 3 finds: existing error handlers, current logging setup
|
||||||
|
- Phase 4 asks: extend current logger? which error handler files to modify?
|
||||||
|
|
||||||
|
### Request: "build user dashboard"
|
||||||
|
- Phase 2 generates questions about: data to show, real-time updates, user personalization
|
||||||
|
- Phase 3 finds: existing dashboard components, data fetching patterns
|
||||||
|
- Phase 4 asks: reuse Dashboard layout? follow existing chart library pattern?
|
||||||
|
|
||||||
|
### Request: "refactor authentication"
|
||||||
|
- Phase 2 generates questions about: what to improve, breaking changes okay?, migration path
|
||||||
|
- Phase 3 finds: current auth implementation, all usage locations
|
||||||
|
- Phase 4 asks: backward compatibility approach? update all 47 references at once?
|
||||||
|
|
||||||
|
**The questions adapt to the request - no more generic "what type of feature is this?"**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase Transitions
|
||||||
|
|
||||||
|
After each phase, clearly announce:
|
||||||
|
- ✅ "Phase 1 complete. Generating discovery questions for: [request]..."
|
||||||
|
- ✅ "Phase 2 complete. Starting READ-ONLY codebase analysis (no code will be modified)..."
|
||||||
|
- ✅ "Phase 3 complete (READ-ONLY analysis - no code changed). Generating expert questions based on findings..."
|
||||||
|
- ✅ "Phase 4 complete. Generating comprehensive requirements specification..."
|
||||||
|
- ✅ "Requirements gathering complete! Review at `.requirements/[folder]/`. NO CODE WAS MODIFIED - implementation is a separate step."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
- **If you catch yourself using Edit/Write/modification tools**: STOP IMMEDIATELY, apologize, explain this is read-only mode, continue with read-only analysis
|
||||||
|
- **If you start implementing code**: STOP IMMEDIATELY, delete any modifications, remind yourself this is requirements gathering only
|
||||||
|
- If tools unavailable: Skip Phase 3, ask generic expert questions
|
||||||
|
- If sequential thinking fails: Fall back to manual analysis
|
||||||
|
- If user abandons mid-session: Save progress in metadata, allow resume
|
||||||
|
- If folder exists: Ask "Requirement exists. Overwrite, new version, or cancel?"
|
||||||
|
- **If user asks "can you implement this?"**: Respond "This is requirements gathering phase. Once complete, use `/implement [slug]` to start implementation."
|
||||||
77
commands/continue.md
Normal file
77
commands/continue.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Continue implementation
|
||||||
|
|
||||||
|
Resume implementation of a requirement that was interrupted.
|
||||||
|
|
||||||
|
# Instructions
|
||||||
|
|
||||||
|
When the user runs `/continue [name]`:
|
||||||
|
|
||||||
|
1. **Determine which requirement to continue**
|
||||||
|
|
||||||
|
a. **If name is provided**: `/continue user-authentication`
|
||||||
|
- Use that specific requirement
|
||||||
|
|
||||||
|
b. **If no name provided**: `/continue`
|
||||||
|
- Read `.requirements/_index.json`
|
||||||
|
- Find the requirement with the most recent `lastWorked` timestamp
|
||||||
|
- If none found or multiple with same timestamp, ask user to specify
|
||||||
|
|
||||||
|
2. **Load the requirement and current state**
|
||||||
|
- Read `.requirements/<name>.md`
|
||||||
|
- Check which items in Implementation Checklist are checked
|
||||||
|
- Check which Acceptance Criteria are marked done
|
||||||
|
- Review any notes about implementation progress
|
||||||
|
|
||||||
|
3. **Analyze codebase for current state**
|
||||||
|
- Use available tools to examine relevant files
|
||||||
|
- Identify what has been implemented
|
||||||
|
- Find where implementation stopped
|
||||||
|
- Look for TODO comments or incomplete code
|
||||||
|
|
||||||
|
4. **Determine remaining work**
|
||||||
|
- Compare requirements with actual implementation
|
||||||
|
- List what's complete
|
||||||
|
- List what remains to be done
|
||||||
|
- Identify any gaps or issues
|
||||||
|
|
||||||
|
5. **Present status to user**
|
||||||
|
Show clearly:
|
||||||
|
```
|
||||||
|
Continuing: <name>
|
||||||
|
|
||||||
|
✅ Completed:
|
||||||
|
- [Item 1]
|
||||||
|
- [Item 2]
|
||||||
|
|
||||||
|
⏳ In Progress:
|
||||||
|
- [Item 3] (partially done)
|
||||||
|
|
||||||
|
❌ Not Started:
|
||||||
|
- [Item 4]
|
||||||
|
- [Item 5]
|
||||||
|
|
||||||
|
Next step: [What I'll do next]
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Ask for confirmation**
|
||||||
|
"Should I continue with [next step], or would you like to adjust the plan?"
|
||||||
|
|
||||||
|
7. **Resume implementation**
|
||||||
|
- Pick up where it left off
|
||||||
|
- Follow the same systematic approach as `/implement`
|
||||||
|
- Update checklist items as completed
|
||||||
|
- Update `_index.json` with `lastWorked` timestamp
|
||||||
|
|
||||||
|
8. **Handle completion**
|
||||||
|
- If all work is done, mark requirement as "done" in `_index.json`
|
||||||
|
- Summarize what was completed in this session
|
||||||
|
- Suggest running `/req-status <name>` to verify
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
- Always verify current state before continuing
|
||||||
|
- Don't assume previous implementation was complete
|
||||||
|
- Check for code quality issues in existing implementation
|
||||||
|
- Maintain consistency with existing code
|
||||||
|
- Update the requirements document with any new insights
|
||||||
|
- If previous implementation has issues, fix them before continuing
|
||||||
89
commands/implement.md
Normal file
89
commands/implement.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# Implement a requirement
|
||||||
|
|
||||||
|
Implement a feature based on its requirements document.
|
||||||
|
|
||||||
|
# Instructions
|
||||||
|
|
||||||
|
When the user runs `/implement <name>`:
|
||||||
|
|
||||||
|
1. **Validate requirement exists**
|
||||||
|
- Check if `.requirements/<name>.md` exists
|
||||||
|
- If not found, list available requirements and ask user to choose or run `/brainstorm` first
|
||||||
|
|
||||||
|
2. **Read and analyze the requirement**
|
||||||
|
- Load `.requirements/<name>.md`
|
||||||
|
- Parse all sections: overview, functional requirements, technical requirements, edge cases, acceptance criteria
|
||||||
|
- Understand the full scope before starting
|
||||||
|
|
||||||
|
3. **Update status to in-progress**
|
||||||
|
- Update `.requirements/_index.json`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"<name>": {
|
||||||
|
"status": "in-progress",
|
||||||
|
"lastWorked": "2025-01-17T11:00:00Z",
|
||||||
|
"lastModified": "2025-01-17T11:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Create implementation plan**
|
||||||
|
Present a clear plan to the user:
|
||||||
|
- Break down into logical steps
|
||||||
|
- Identify files that need to be created/modified
|
||||||
|
- Highlight any dependencies or prerequisites
|
||||||
|
- Estimate complexity
|
||||||
|
|
||||||
|
Ask user: "Does this plan look good? Should I proceed?"
|
||||||
|
|
||||||
|
5. **Execute implementation systematically**
|
||||||
|
|
||||||
|
a. **Setup phase**
|
||||||
|
- Create necessary directories
|
||||||
|
- Set up any configuration files
|
||||||
|
- Install dependencies if needed
|
||||||
|
|
||||||
|
b. **Core implementation**
|
||||||
|
- Follow the plan step by step
|
||||||
|
- Implement according to technical requirements
|
||||||
|
- Handle edge cases mentioned in requirements
|
||||||
|
- Add proper error handling
|
||||||
|
- Include logging where appropriate
|
||||||
|
|
||||||
|
c. **Testing**
|
||||||
|
- Write unit tests for core functionality
|
||||||
|
- Write integration tests if applicable
|
||||||
|
- Test edge cases from requirements
|
||||||
|
- Verify acceptance criteria
|
||||||
|
|
||||||
|
d. **Documentation**
|
||||||
|
- Add code comments for complex logic
|
||||||
|
- Update README if needed
|
||||||
|
- Document API endpoints or interfaces
|
||||||
|
|
||||||
|
6. **Track progress in requirements file**
|
||||||
|
- Check off items in the Implementation Checklist
|
||||||
|
- Mark completed acceptance criteria
|
||||||
|
- Add notes about implementation decisions
|
||||||
|
|
||||||
|
7. **Report completion**
|
||||||
|
- Summarize what was implemented
|
||||||
|
- Show which acceptance criteria were met
|
||||||
|
- Highlight any deviations from original requirements
|
||||||
|
- Suggest running `/req-status <name>` to verify
|
||||||
|
- Update status in `_index.json` to "done" if fully complete
|
||||||
|
|
||||||
|
8. **Handle interruptions gracefully**
|
||||||
|
- If implementation is interrupted, save state clearly
|
||||||
|
- Update `_index.json` with current progress
|
||||||
|
- User can resume with `/continue <name>`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
- Always confirm the plan before executing
|
||||||
|
- Implement incrementally, not all at once
|
||||||
|
- Test as you go, don't wait until the end
|
||||||
|
- Keep the user informed of progress
|
||||||
|
- If requirements are unclear, ask for clarification before implementing
|
||||||
|
- Follow existing code patterns and project conventions
|
||||||
|
- Prioritize code quality and maintainability
|
||||||
62
commands/req-list.md
Normal file
62
commands/req-list.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# List all requirements
|
||||||
|
|
||||||
|
Show all requirements with their status and metadata.
|
||||||
|
|
||||||
|
# Instructions
|
||||||
|
|
||||||
|
When the user runs `/req-list`:
|
||||||
|
|
||||||
|
1. **Check if requirements directory exists**
|
||||||
|
- Look for `.requirements/` directory
|
||||||
|
- If not found, show message: "No requirements found. Run `/brainstorm <name>` to create your first requirement."
|
||||||
|
|
||||||
|
2. **Read all requirement files**
|
||||||
|
- List all `.md` files in `.requirements/` directory (excluding `_index.json`)
|
||||||
|
- Load metadata from `.requirements/_index.json`
|
||||||
|
|
||||||
|
3. **Display requirements in a table format**
|
||||||
|
|
||||||
|
```
|
||||||
|
Requirements
|
||||||
|
|
||||||
|
Name Status Created Last Modified
|
||||||
|
────────────────────────────────────────────────────────────────
|
||||||
|
user-authentication in-progress 2025-01-15 2025-01-17
|
||||||
|
payment-flow done 2025-01-14 2025-01-16
|
||||||
|
admin-dashboard draft 2025-01-17 2025-01-17
|
||||||
|
api-rate-limiting in-progress 2025-01-16 2025-01-17
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Add summary statistics**
|
||||||
|
```
|
||||||
|
Total: 4 requirements
|
||||||
|
✅ Done: 1
|
||||||
|
⏳ In Progress: 2
|
||||||
|
📝 Draft: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Provide helpful next actions**
|
||||||
|
- If there are draft requirements: "Run `/implement <name>` to start implementation"
|
||||||
|
- If there are in-progress: "Run `/continue <name>` to resume work"
|
||||||
|
- If there are done requirements: "Run `/req-status <name>` to verify completion"
|
||||||
|
|
||||||
|
6. **Handle empty or missing metadata**
|
||||||
|
- If `_index.json` doesn't exist, create it with default values for discovered requirements
|
||||||
|
- If a requirement file exists but not in index, add it with default metadata
|
||||||
|
|
||||||
|
## Display Options
|
||||||
|
|
||||||
|
**Sort by:**
|
||||||
|
- Default: Last modified (most recent first)
|
||||||
|
- Can be enhanced to allow sorting by name, status, or created date
|
||||||
|
|
||||||
|
**Filter by status** (optional enhancement):
|
||||||
|
- Show only requirements with specific status
|
||||||
|
- Example: `/req-list --status in-progress`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
- Keep display clean and easy to scan
|
||||||
|
- Use emojis sparingly for status indicators
|
||||||
|
- Show most recently modified first by default
|
||||||
|
- Make it easy to identify what to work on next
|
||||||
126
commands/req-status.md
Normal file
126
commands/req-status.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# Show requirement implementation status
|
||||||
|
|
||||||
|
Compare requirements with actual implementation to show progress and gaps.
|
||||||
|
|
||||||
|
# Instructions
|
||||||
|
|
||||||
|
When the user runs `/req-status [name]`:
|
||||||
|
|
||||||
|
1. **Determine which requirement(s) to check**
|
||||||
|
|
||||||
|
a. **If name provided**: `/req-status user-authentication`
|
||||||
|
- Check that specific requirement
|
||||||
|
|
||||||
|
b. **If no name provided**: `/req-status`
|
||||||
|
- Show status for all requirements
|
||||||
|
- Focus on in-progress and recent ones
|
||||||
|
|
||||||
|
2. **Load requirement and analyze**
|
||||||
|
- Read `.requirements/<name>.md`
|
||||||
|
- Extract all requirements, acceptance criteria, and checklist items
|
||||||
|
|
||||||
|
3. **Analyze codebase implementation**
|
||||||
|
- Use available tools to examine relevant files
|
||||||
|
- Search for related code
|
||||||
|
- Check tests
|
||||||
|
- Verify functionality exists
|
||||||
|
|
||||||
|
4. **Compare requirements vs reality**
|
||||||
|
|
||||||
|
For each requirement, determine:
|
||||||
|
- ✅ **Fully Implemented** - Code exists, tests pass, acceptance criteria met
|
||||||
|
- ⚠️ **Partially Implemented** - Started but incomplete
|
||||||
|
- ❌ **Not Started** - No code found
|
||||||
|
- ❓ **Cannot Verify** - Need manual verification
|
||||||
|
|
||||||
|
5. **Generate detailed status report**
|
||||||
|
|
||||||
|
**For single requirement:**
|
||||||
|
```
|
||||||
|
Status: user-authentication
|
||||||
|
|
||||||
|
Overall Progress: 75% (6/8 items complete)
|
||||||
|
|
||||||
|
Functional Requirements:
|
||||||
|
✅ User can register with email/password
|
||||||
|
✅ User can login with credentials
|
||||||
|
⚠️ Password reset flow (partially done - email not implemented)
|
||||||
|
❌ OAuth integration not started
|
||||||
|
|
||||||
|
Acceptance Criteria:
|
||||||
|
✅ Passwords are hashed
|
||||||
|
✅ JWT tokens are generated
|
||||||
|
⚠️ Password strength validation (basic only, missing special chars)
|
||||||
|
❌ Rate limiting not implemented
|
||||||
|
|
||||||
|
Tests:
|
||||||
|
✅ Unit tests: 12/12 passing
|
||||||
|
⚠️ Integration tests: 3/5 passing
|
||||||
|
❌ E2E tests: Not written
|
||||||
|
|
||||||
|
Issues Found:
|
||||||
|
- Password reset emails not configured
|
||||||
|
- Rate limiting mentioned in requirements but missing
|
||||||
|
- Integration tests failing for OAuth flows
|
||||||
|
```
|
||||||
|
|
||||||
|
**For all requirements:**
|
||||||
|
```
|
||||||
|
Requirements Status Overview
|
||||||
|
|
||||||
|
Name Progress Status
|
||||||
|
────────────────────────────────────────────
|
||||||
|
user-authentication 75% in-progress
|
||||||
|
payment-flow 100% done ✅
|
||||||
|
admin-dashboard 30% in-progress
|
||||||
|
api-rate-limiting 0% draft
|
||||||
|
|
||||||
|
Summary:
|
||||||
|
- 1 complete
|
||||||
|
- 2 in progress (average 52.5% done)
|
||||||
|
- 1 not started
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Identify gaps and issues**
|
||||||
|
- Requirements with no implementation
|
||||||
|
- Partial implementations
|
||||||
|
- Missing tests
|
||||||
|
- Acceptance criteria not met
|
||||||
|
- Code that exists but wasn't in requirements (scope creep)
|
||||||
|
|
||||||
|
7. **Provide actionable recommendations**
|
||||||
|
```
|
||||||
|
Recommendations:
|
||||||
|
|
||||||
|
High Priority:
|
||||||
|
- Complete password reset email integration
|
||||||
|
- Implement rate limiting (security requirement)
|
||||||
|
- Fix failing integration tests
|
||||||
|
|
||||||
|
Medium Priority:
|
||||||
|
- Enhance password validation
|
||||||
|
- Add E2E tests
|
||||||
|
|
||||||
|
Low Priority:
|
||||||
|
- Start OAuth integration planning
|
||||||
|
```
|
||||||
|
|
||||||
|
8. **Update metadata if status changed**
|
||||||
|
- If implementation is now complete, update status to "done"
|
||||||
|
- Update `lastModified` timestamp
|
||||||
|
|
||||||
|
9. **Suggest next actions**
|
||||||
|
- If incomplete: "Run `/continue <name>` to finish implementation"
|
||||||
|
- If gaps found: "Run `/req-update <name>` to adjust requirements"
|
||||||
|
- If complete: "Requirement fully implemented!"
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
- Be thorough but don't overwhelm with too much detail
|
||||||
|
- Highlight critical gaps (security, core functionality)
|
||||||
|
- Show progress visually (percentages, checkmarks)
|
||||||
|
- Make it easy to see what needs attention
|
||||||
|
- Don't just check if files exist - verify functionality
|
||||||
|
- Consider test coverage as part of "done"
|
||||||
|
- Flag discrepancies between requirements and implementation
|
||||||
|
- Provide clear next steps
|
||||||
153
commands/req-tests.md
Normal file
153
commands/req-tests.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# Generate test plan from requirements
|
||||||
|
|
||||||
|
Create comprehensive test scenarios based on a requirement document.
|
||||||
|
|
||||||
|
# Instructions
|
||||||
|
|
||||||
|
When the user runs `/req-tests <name>`:
|
||||||
|
|
||||||
|
1. **Validate requirement exists**
|
||||||
|
- Check if `.requirements/<name>.md` exists
|
||||||
|
- If not found, list available requirements
|
||||||
|
|
||||||
|
2. **Read and analyze the requirement**
|
||||||
|
- Load `.requirements/<name>.md`
|
||||||
|
- Extract:
|
||||||
|
- Functional requirements
|
||||||
|
- Edge cases and constraints
|
||||||
|
- Acceptance criteria
|
||||||
|
- User stories
|
||||||
|
|
||||||
|
3. **Generate comprehensive test scenarios**
|
||||||
|
|
||||||
|
Create tests covering:
|
||||||
|
|
||||||
|
**a. Unit Tests**
|
||||||
|
- Test each functional requirement individually
|
||||||
|
- Test edge cases mentioned in requirements
|
||||||
|
- Test error conditions
|
||||||
|
- Test validation logic
|
||||||
|
|
||||||
|
**b. Integration Tests**
|
||||||
|
- Test interactions between components
|
||||||
|
- Test external integrations (APIs, databases, etc.)
|
||||||
|
- Test data flow through the system
|
||||||
|
|
||||||
|
**c. End-to-End Tests**
|
||||||
|
- Test complete user flows from user stories
|
||||||
|
- Test acceptance criteria scenarios
|
||||||
|
- Test real-world usage patterns
|
||||||
|
|
||||||
|
**d. Edge Case Tests**
|
||||||
|
- Test all edge cases mentioned in requirements
|
||||||
|
- Test boundary conditions
|
||||||
|
- Test error handling
|
||||||
|
- Test performance under constraints
|
||||||
|
|
||||||
|
4. **Structure test scenarios**
|
||||||
|
|
||||||
|
Format:
|
||||||
|
```markdown
|
||||||
|
## Test Scenarios
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
|
||||||
|
#### Test: [Function/Component Name]
|
||||||
|
- **Given:** [Initial state/conditions]
|
||||||
|
- **When:** [Action taken]
|
||||||
|
- **Then:** [Expected outcome]
|
||||||
|
- **Test Type:** Unit
|
||||||
|
- **Priority:** High/Medium/Low
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
|
||||||
|
#### Test: [Integration Point]
|
||||||
|
- **Given:** [Setup]
|
||||||
|
- **When:** [Integration action]
|
||||||
|
- **Then:** [Expected result]
|
||||||
|
- **Test Type:** Integration
|
||||||
|
- **Priority:** High/Medium/Low
|
||||||
|
|
||||||
|
### End-to-End Tests
|
||||||
|
|
||||||
|
#### Test: [User Flow]
|
||||||
|
- **Scenario:** [User story or flow]
|
||||||
|
- **Steps:**
|
||||||
|
1. [Step 1]
|
||||||
|
2. [Step 2]
|
||||||
|
3. [Step 3]
|
||||||
|
- **Expected:** [Final outcome]
|
||||||
|
- **Test Type:** E2E
|
||||||
|
- **Priority:** High/Medium/Low
|
||||||
|
|
||||||
|
### Edge Case Tests
|
||||||
|
|
||||||
|
#### Test: [Edge Case Description]
|
||||||
|
- **Given:** [Edge case setup]
|
||||||
|
- **When:** [Edge case trigger]
|
||||||
|
- **Then:** [Expected handling]
|
||||||
|
- **Test Type:** Edge Case
|
||||||
|
- **Priority:** High/Medium/Low
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Ask for preference on storage**
|
||||||
|
```
|
||||||
|
Where should I save these test scenarios?
|
||||||
|
|
||||||
|
1. Append to requirements file (.requirements/<name>.md)
|
||||||
|
2. Create separate test file (.requirements/<name>-tests.md)
|
||||||
|
3. Show only (don't save)
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Save test scenarios**
|
||||||
|
Based on user choice:
|
||||||
|
- If appending: Add "## Test Scenarios" section to requirement file
|
||||||
|
- If separate: Create new test file
|
||||||
|
- If show only: Display but don't persist
|
||||||
|
|
||||||
|
7. **Generate test code templates** (optional)
|
||||||
|
Ask: "Would you like me to generate test code templates?"
|
||||||
|
|
||||||
|
If yes, create example test code in the project's test framework:
|
||||||
|
```javascript
|
||||||
|
// Example for Jest
|
||||||
|
describe('User Authentication', () => {
|
||||||
|
test('should allow login with valid credentials', () => {
|
||||||
|
// Given: Valid user credentials
|
||||||
|
const credentials = { email: 'user@example.com', password: 'password123' };
|
||||||
|
|
||||||
|
// When: User attempts to login
|
||||||
|
const result = login(credentials);
|
||||||
|
|
||||||
|
// Then: Login succeeds
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
expect(result.token).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
8. **Update requirement metadata**
|
||||||
|
- Add note that test scenarios were generated
|
||||||
|
- Update `lastModified` in `_index.json`
|
||||||
|
|
||||||
|
9. **Provide summary**
|
||||||
|
```
|
||||||
|
Generated test scenarios:
|
||||||
|
- 5 Unit Tests
|
||||||
|
- 3 Integration Tests
|
||||||
|
- 2 End-to-End Tests
|
||||||
|
- 4 Edge Case Tests
|
||||||
|
|
||||||
|
Total: 14 test scenarios covering all requirements
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
- Cover all functional requirements with tests
|
||||||
|
- Don't forget negative test cases (what should fail)
|
||||||
|
- Prioritize tests based on critical functionality
|
||||||
|
- Make tests specific and actionable
|
||||||
|
- Include setup/teardown considerations
|
||||||
|
- Consider performance testing for performance requirements
|
||||||
|
- Include security testing for security requirements
|
||||||
|
- Map tests back to acceptance criteria
|
||||||
93
commands/req-update.md
Normal file
93
commands/req-update.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# Update a requirement
|
||||||
|
|
||||||
|
Modify an existing requirement document.
|
||||||
|
|
||||||
|
# Instructions
|
||||||
|
|
||||||
|
When the user runs `/req-update <name>`:
|
||||||
|
|
||||||
|
1. **Validate requirement exists**
|
||||||
|
- Check if `.requirements/<name>.md` exists
|
||||||
|
- If not found, list available requirements or suggest creating one with `/brainstorm`
|
||||||
|
|
||||||
|
2. **Load current requirement**
|
||||||
|
- Read `.requirements/<name>.md`
|
||||||
|
- Show summary of current content
|
||||||
|
|
||||||
|
3. **Ask what to update**
|
||||||
|
Present options:
|
||||||
|
```
|
||||||
|
What would you like to update?
|
||||||
|
|
||||||
|
1. Overview / Goals
|
||||||
|
2. User Stories
|
||||||
|
3. Functional Requirements
|
||||||
|
4. Technical Requirements
|
||||||
|
5. Edge Cases & Constraints
|
||||||
|
6. Acceptance Criteria
|
||||||
|
7. Free-form edit (tell me what to change)
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Handle the update based on choice**
|
||||||
|
|
||||||
|
**For specific sections (1-6):**
|
||||||
|
- Show current content of that section
|
||||||
|
- Ask: "What changes would you like to make?"
|
||||||
|
- Accept additions, modifications, or deletions
|
||||||
|
- Update that section while preserving the rest
|
||||||
|
|
||||||
|
**For free-form edit (7):**
|
||||||
|
- Ask: "Describe the changes you want to make"
|
||||||
|
- Parse user's intent
|
||||||
|
- Apply changes to appropriate sections
|
||||||
|
- Show what changed
|
||||||
|
|
||||||
|
5. **Preview changes**
|
||||||
|
Show diff or summary:
|
||||||
|
```
|
||||||
|
Changes to be made:
|
||||||
|
|
||||||
|
+ Added to Functional Requirements:
|
||||||
|
- Support OAuth 2.0 authentication
|
||||||
|
|
||||||
|
~ Modified in Technical Requirements:
|
||||||
|
- JWT tokens → OAuth 2.0 tokens
|
||||||
|
|
||||||
|
- Removed from Edge Cases:
|
||||||
|
- Password reset via email (no longer needed)
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Confirm before saving**
|
||||||
|
Ask: "Should I save these changes?"
|
||||||
|
|
||||||
|
7. **Save updates**
|
||||||
|
- Write updated content to `.requirements/<name>.md`
|
||||||
|
- Update metadata in `.requirements/_index.json`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"<name>": {
|
||||||
|
"lastModified": "2025-01-17T12:00:00Z",
|
||||||
|
"version": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Add changelog entry at bottom of requirement file:
|
||||||
|
```markdown
|
||||||
|
## Changelog
|
||||||
|
- **2025-01-17**: Updated authentication approach to OAuth 2.0
|
||||||
|
- **2025-01-15**: Initial version
|
||||||
|
```
|
||||||
|
|
||||||
|
8. **Suggest next steps**
|
||||||
|
- If status is "done": "Requirements changed. Consider running `/req-status <name>` to check if implementation still matches."
|
||||||
|
- If status is "in-progress": "Updated requirements. You may want to adjust your implementation."
|
||||||
|
- If status is "draft": "Requirements updated. Ready to run `/implement <name>`?"
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
- Always show what will change before saving
|
||||||
|
- Preserve existing content unless explicitly asked to remove it
|
||||||
|
- Maintain document structure and formatting
|
||||||
|
- Keep changelog for traceability
|
||||||
|
- If changes affect completed work, warn the user
|
||||||
|
- Be careful not to lose information during updates
|
||||||
365
hooks/README.md
Normal file
365
hooks/README.md
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
# Puerto Prompt Analyzer Hook (v2.0)
|
||||||
|
|
||||||
|
Intelligent prompt analyzer for Claude Code that automatically validates user instructions and recommends relevant plugins from the Puerto marketplace.
|
||||||
|
|
||||||
|
**🆕 Version 2.0 Features:**
|
||||||
|
- ⚡ **60x faster** with intelligent caching
|
||||||
|
- 🎯 **2x more accurate** with advanced text processing
|
||||||
|
- 🚫 **Filters installed plugins** - never recommends what you already have
|
||||||
|
- 🧠 **Project context aware** - detects JavaScript, Python, Rust, Go, Ruby, Java projects
|
||||||
|
- 🔧 **Fully configurable** - customize scoring, blacklist plugins, set favorites
|
||||||
|
- 📊 **Performance monitoring** - logs slow executions
|
||||||
|
- 🎲 **Diversity algorithm** - shows varied recommendations, not repetitive ones
|
||||||
|
- 💾 **Session memory** - avoids showing same plugins repeatedly
|
||||||
|
|
||||||
|
> **⚠️ Manual Setup Required**
|
||||||
|
> Due to Claude Code security restrictions, hooks cannot be automatically configured when installing plugins.
|
||||||
|
> **You must manually add this hook to your `~/.claude/settings.json` file.**
|
||||||
|
> See the [Essentials Plugin README](../README.md#instruction-analysis-hook-optional) for step-by-step setup instructions.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The instruction analysis hook runs before Claude processes your prompts, providing:
|
||||||
|
|
||||||
|
- **Task Type Classification:** Automatically categorizes your request as Research, Implementation, Mixed, or General
|
||||||
|
- **Instruction Validation:** Detects vague or unclear instructions and provides improvement suggestions
|
||||||
|
- **Plugin Recommendations:** Suggests top 2-3 relevant plugins from Puerto marketplace based on your task
|
||||||
|
- **Transparent Analysis:** Shows recommendations directly in Claude's response with install commands
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **You submit a prompt** (any non-command message)
|
||||||
|
2. **Hook analyzes** your prompt before Claude sees it:
|
||||||
|
- Classifies task type using keyword detection
|
||||||
|
- Validates instruction clarity
|
||||||
|
- Scores all marketplace plugins for relevance
|
||||||
|
- Generates top recommendations
|
||||||
|
3. **Claude processes** your original prompt + recommendations
|
||||||
|
4. **You see** analysis section in Claude's response with suggested plugins
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Task Classification (Enhanced v2.0)
|
||||||
|
|
||||||
|
Uses advanced tokenization and stemming to determine task type:
|
||||||
|
|
||||||
|
- **Research:** explain, analyze, investigate, understand, compare, study, evaluate, etc.
|
||||||
|
- **Implementation:** implement, create, build, fix, refactor, add, deploy, optimize, etc.
|
||||||
|
- **Mixed:** Contains both research and implementation keywords (requires 1.5x threshold)
|
||||||
|
- **General:** No clear classification
|
||||||
|
|
||||||
|
**Improvements:** Stemming ("building" → "build"), stop word filtering, better thresholds
|
||||||
|
|
||||||
|
### Instruction Validation
|
||||||
|
|
||||||
|
Detects common issues:
|
||||||
|
|
||||||
|
- **Too vague:** "fix it", "make it better", "help" → Suggests being more specific
|
||||||
|
- **Missing context:** Short prompts (<30 chars) with ambiguous pronouns → Requests clarification
|
||||||
|
- **Overly broad:** "build an app" → Suggests breaking down into components
|
||||||
|
|
||||||
|
### Intelligent Plugin Scoring (v2.0)
|
||||||
|
|
||||||
|
Recommendations based on weighted scoring algorithm:
|
||||||
|
|
||||||
|
1. **Tokenized description overlap** (weight: 2) - Advanced text matching with stemming
|
||||||
|
2. **Name matching** (weight: 5) - Plugin name relevance (strongest signal)
|
||||||
|
3. **Keyword tags** (weight: 3) - Plugin keywords matching prompt
|
||||||
|
4. **Task type alignment** (weight: 5) - Agents for implementation, skills for research
|
||||||
|
5. **Project context** (weight: 3) - Detects your project type and boosts relevant plugins
|
||||||
|
6. **Category matching** (weight: 4) - Favorite categories get priority
|
||||||
|
|
||||||
|
**Quality threshold:** Only shows plugins scoring ≥8 points (configurable)
|
||||||
|
|
||||||
|
**Filters:**
|
||||||
|
- ✅ Skips already-installed plugins
|
||||||
|
- ✅ Reduces score for recently shown plugins (-5 points)
|
||||||
|
- ✅ Respects blacklist configuration
|
||||||
|
- ✅ Diversity algorithm ensures varied recommendations
|
||||||
|
|
||||||
|
### Project Context Detection (New in v2.0)
|
||||||
|
|
||||||
|
Automatically detects your project type:
|
||||||
|
|
||||||
|
- **JavaScript/Node.js** - Detects `package.json`, frameworks (React, Vue, Next.js, Express)
|
||||||
|
- **Python** - Detects `requirements.txt`, `pyproject.toml`
|
||||||
|
- **Rust** - Detects `Cargo.toml`
|
||||||
|
- **Go** - Detects `go.mod`
|
||||||
|
- **Ruby** - Detects `Gemfile`
|
||||||
|
- **Java** - Detects `pom.xml`, `build.gradle`
|
||||||
|
|
||||||
|
Boosts plugin scores when they match your project stack!
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 🔍 Instruction Analysis
|
||||||
|
|
||||||
|
**Task Type:** Implementation
|
||||||
|
|
||||||
|
**📦 Recommended Plugins:**
|
||||||
|
|
||||||
|
### 1. `engineering`
|
||||||
|
**Description:** Full-stack development department with 7 specialized agents
|
||||||
|
**Why:** Matches keywords: implementation, build, create
|
||||||
|
**Install:** `/plugin install engineering`
|
||||||
|
|
||||||
|
### 2. `product`
|
||||||
|
**Description:** Product management and data analysis department
|
||||||
|
**Why:** Matches keywords: analyze, track, metrics
|
||||||
|
**Install:** `/plugin install product`
|
||||||
|
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
**⚠️ Manual setup is required.** Hooks cannot be automatically configured by plugins for security reasons.
|
||||||
|
|
||||||
|
### Hook Configuration (Manual Setup Required)
|
||||||
|
|
||||||
|
You must manually add this to your `~/.claude/settings.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"UserPromptSubmit": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "node ~/.claude/plugins/marketplaces/puerto/plugins/essentials/hooks/puerto-prompt-analyzer.js",
|
||||||
|
"timeout": 60
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Setup Steps:**
|
||||||
|
|
||||||
|
1. Install the essentials plugin: `/plugin install essentials@puerto`
|
||||||
|
|
||||||
|
2. Find your plugin path:
|
||||||
|
```bash
|
||||||
|
find ~/.claude/plugins -name "puerto-prompt-analyzer.js" 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Replace the path in the hook configuration above with your actual path
|
||||||
|
|
||||||
|
4. Edit `~/.claude/settings.json` and add the hook configuration
|
||||||
|
|
||||||
|
5. Verify JSON is valid: `cat ~/.claude/settings.json | python3 -m json.tool`
|
||||||
|
|
||||||
|
6. **Restart Claude Code** (required)
|
||||||
|
|
||||||
|
7. Test by submitting a non-command prompt - you should see "🔍 Instruction Analysis" in the response
|
||||||
|
|
||||||
|
**Note:** If `node` is not in your PATH, use the full path: `"command": "/usr/local/bin/node /path/to/puerto-prompt-analyzer.js"`
|
||||||
|
|
||||||
|
For detailed setup instructions with troubleshooting, see the [Essentials Plugin README](../README.md#puerto-prompt-analyzer-hook-optional).
|
||||||
|
|
||||||
|
### Advanced Configuration (New in v2.0)
|
||||||
|
|
||||||
|
Customize the hook behavior by creating `~/.claude/puerto-prompt-analyzer.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"minScore": 8,
|
||||||
|
"maxRecommendations": 3,
|
||||||
|
"cacheMinutes": 1,
|
||||||
|
"blacklist": [],
|
||||||
|
"favoriteCategories": [],
|
||||||
|
"showScores": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Configuration Options:**
|
||||||
|
|
||||||
|
| Option | Type | Default | Description |
|
||||||
|
|--------|------|---------|-------------|
|
||||||
|
| `minScore` | number | 8 | Minimum score threshold (0-100). Higher = more selective |
|
||||||
|
| `maxRecommendations` | number | 3 | Maximum number of plugins to recommend |
|
||||||
|
| `cacheMinutes` | number | 1 | How long to cache marketplace data (in minutes) |
|
||||||
|
| `blacklist` | array | [] | Plugin names to never recommend (e.g., `["plugin-name"]`) |
|
||||||
|
| `favoriteCategories` | array | [] | Categories to boost (e.g., `["frontend", "backend"]`) |
|
||||||
|
| `showScores` | boolean | false | Show relevance scores for debugging |
|
||||||
|
|
||||||
|
**Example Configurations:**
|
||||||
|
|
||||||
|
**Conservative** (fewer, higher-quality recommendations):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"minScore": 12,
|
||||||
|
"maxRecommendations": 2,
|
||||||
|
"showScores": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Exploratory** (more recommendations, lower threshold):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"minScore": 5,
|
||||||
|
"maxRecommendations": 5,
|
||||||
|
"showScores": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Frontend-focused**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"minScore": 8,
|
||||||
|
"maxRecommendations": 3,
|
||||||
|
"favoriteCategories": ["frontend", "ui", "design"],
|
||||||
|
"blacklist": ["backend-heavy-plugin"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See `puerto-prompt-analyzer.example.json` for more examples.
|
||||||
|
|
||||||
|
### Disabling the Hook
|
||||||
|
|
||||||
|
To temporarily disable the analyzer:
|
||||||
|
|
||||||
|
1. Open `~/.claude/settings.json`
|
||||||
|
2. Remove or comment out the `UserPromptSubmit` hook entry
|
||||||
|
3. Restart Claude Code
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
**Version 2.0 Performance:**
|
||||||
|
- **Execution time:** < 100ms for 95% of prompts (was < 1s)
|
||||||
|
- **Cache hit rate:** ~95% after first run
|
||||||
|
- **Memory:** ~50KB marketplace.json cached in memory
|
||||||
|
- **Latency:** Minimal impact on workflow (<5% overhead)
|
||||||
|
- **Dependencies:** None (uses Node.js built-ins only)
|
||||||
|
|
||||||
|
**Optimizations:**
|
||||||
|
- ✅ Marketplace data cached for 60 seconds
|
||||||
|
- ✅ Installed plugins cached for 60 seconds
|
||||||
|
- ✅ Session memory for deduplication
|
||||||
|
- ✅ Efficient tokenization with stop words
|
||||||
|
- ✅ Logs executions >500ms for monitoring
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The hook follows a **fail-open** philosophy:
|
||||||
|
|
||||||
|
- Never blocks your prompt, even on errors
|
||||||
|
- All errors logged to stderr for debugging
|
||||||
|
- If marketplace.json is missing, proceeds without recommendations
|
||||||
|
- If JSON parsing fails, allows prompt normally
|
||||||
|
- Timeout protection (60s limit)
|
||||||
|
|
||||||
|
**You will never be prevented from working due to hook failures.**
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### No recommendations appearing
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
1. Is marketplace.json present? Run: `ls .claude-plugin/marketplace.json`
|
||||||
|
2. Is the hook executable? Run: `ls -la plugins/essentials/hooks/puerto-prompt-analyzer.js`
|
||||||
|
3. Check stderr for errors: Look for `[puerto-prompt-analyzer]` messages
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
# Regenerate marketplace catalog
|
||||||
|
npm run generate-catalog
|
||||||
|
|
||||||
|
# Make hook executable
|
||||||
|
chmod +x plugins/essentials/hooks/puerto-prompt-analyzer.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hook seems slow
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
```bash
|
||||||
|
# Test hook execution time
|
||||||
|
time echo '{"prompt": "test", "hook_event_name": "UserPromptSubmit"}' | \
|
||||||
|
node plugins/essentials/hooks/puerto-prompt-analyzer.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected:** < 1 second
|
||||||
|
|
||||||
|
### Invalid recommendations
|
||||||
|
|
||||||
|
The hook uses simple keyword matching (MVP). Accuracy improves with:
|
||||||
|
- More specific prompts
|
||||||
|
- Using keywords from plugin descriptions
|
||||||
|
- Clearer task intent (research vs implementation)
|
||||||
|
|
||||||
|
**Future:** v2 will include LLM-based classification for better accuracy.
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
### Input Format
|
||||||
|
|
||||||
|
Hook receives JSON via stdin:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"session_id": "abc123",
|
||||||
|
"transcript_path": "/path/to/transcript.jsonl",
|
||||||
|
"cwd": "/current/working/directory",
|
||||||
|
"permission_mode": "default",
|
||||||
|
"hook_event_name": "UserPromptSubmit",
|
||||||
|
"prompt": "User's submitted text"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Output Format
|
||||||
|
|
||||||
|
Hook outputs JSON to stdout:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"decision": undefined,
|
||||||
|
"reason": "Analysis complete",
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "UserPromptSubmit",
|
||||||
|
"additionalContext": "## 🔍 Instruction Analysis\n..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Skipped Prompts
|
||||||
|
|
||||||
|
Hook automatically skips:
|
||||||
|
- Empty prompts
|
||||||
|
- Command prompts (start with `/`)
|
||||||
|
- Prompts that fail JSON parsing
|
||||||
|
|
||||||
|
## Customization (Future v2)
|
||||||
|
|
||||||
|
Planned features:
|
||||||
|
- Configurable keywords in settings.json
|
||||||
|
- Plugin blacklist/whitelist
|
||||||
|
- LLM-based classification option
|
||||||
|
- User feedback loop (track recommendation acceptance)
|
||||||
|
- Installation status detection
|
||||||
|
- Context-aware recommendations
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Found a bug or have a suggestion?
|
||||||
|
|
||||||
|
1. Check if it's a known issue in the troubleshooting section
|
||||||
|
2. File an issue with:
|
||||||
|
- Sample prompt that caused the issue
|
||||||
|
- Expected vs actual recommendations
|
||||||
|
- stderr output if available
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - Part of the Puerto marketplace ecosystem
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Claude Code Hooks Documentation](https://docs.claude.com/en/docs/claude-code/hooks)
|
||||||
|
- [Puerto Marketplace](https://github.com/bandofai/puerto)
|
||||||
|
- [Essentials Plugin README](../README.md)
|
||||||
127
hooks/install-hook.ps1
Normal file
127
hooks/install-hook.ps1
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Puerto Prompt Analyzer Hook Installer (Windows PowerShell)
|
||||||
|
#
|
||||||
|
# Automatically configures the Puerto Prompt Analyzer hook in your
|
||||||
|
# Claude Code settings.json file.
|
||||||
|
#
|
||||||
|
# Usage: .\install-hook.ps1
|
||||||
|
|
||||||
|
Write-Host "🔧 Puerto Prompt Analyzer Hook Installer" -ForegroundColor Cyan
|
||||||
|
Write-Host "=========================================" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Set paths
|
||||||
|
$SettingsFile = Join-Path $env:USERPROFILE ".claude\settings.json"
|
||||||
|
$PluginSearchDir = Join-Path $env:USERPROFILE ".claude\plugins"
|
||||||
|
|
||||||
|
# Step 1: Find the hook script
|
||||||
|
Write-Host "🔍 Step 1: Finding puerto-prompt-analyzer.js..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$HookPath = Get-ChildItem -Path $PluginSearchDir -Recurse -Filter "puerto-prompt-analyzer.js" -ErrorAction SilentlyContinue |
|
||||||
|
Select-Object -First 1 -ExpandProperty FullName
|
||||||
|
|
||||||
|
if (-not $HookPath) {
|
||||||
|
Write-Host "❌ Error: Could not find puerto-prompt-analyzer.js" -ForegroundColor Red
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Please ensure the essentials plugin is installed:"
|
||||||
|
Write-Host " /plugin install essentials@puerto"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "✅ Found hook at: $HookPath" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Step 2: Check if Node.js is available
|
||||||
|
Write-Host "🔍 Step 2: Checking Node.js installation..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
try {
|
||||||
|
$NodeVersion = & node --version 2>$null
|
||||||
|
Write-Host "✅ Found Node.js: $NodeVersion" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
} catch {
|
||||||
|
Write-Host "❌ Error: Node.js not found in PATH" -ForegroundColor Red
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Please install Node.js >= v18.0.0"
|
||||||
|
Write-Host "Visit: https://nodejs.org/"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Step 3: Create or update settings.json
|
||||||
|
Write-Host "🔍 Step 3: Updating settings.json..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
# Check if settings file exists
|
||||||
|
if (-not (Test-Path $SettingsFile)) {
|
||||||
|
Write-Host "📝 Creating new settings.json..." -ForegroundColor Cyan
|
||||||
|
$SettingsDir = Split-Path $SettingsFile -Parent
|
||||||
|
if (-not (Test-Path $SettingsDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $SettingsDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
Set-Content -Path $SettingsFile -Value '{}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Backup original settings
|
||||||
|
$BackupFile = "$SettingsFile.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||||
|
Copy-Item $SettingsFile $BackupFile
|
||||||
|
Write-Host "📦 Backup created: $BackupFile" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Read current settings
|
||||||
|
$CurrentSettings = Get-Content $SettingsFile -Raw
|
||||||
|
|
||||||
|
# Check if hook already exists
|
||||||
|
if ($CurrentSettings -match "puerto-prompt-analyzer") {
|
||||||
|
Write-Host "⚠️ Hook configuration already exists in settings.json" -ForegroundColor Yellow
|
||||||
|
Write-Host ""
|
||||||
|
$Response = Read-Host "Do you want to update it? (y/N)"
|
||||||
|
if ($Response -notmatch "^[Yy]$") {
|
||||||
|
Write-Host "❌ Installation cancelled" -ForegroundColor Red
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update settings using PowerShell JSON handling
|
||||||
|
try {
|
||||||
|
$Settings = Get-Content $SettingsFile -Raw | ConvertFrom-Json -AsHashtable
|
||||||
|
|
||||||
|
# Ensure hooks object exists
|
||||||
|
if (-not $Settings.ContainsKey("hooks")) {
|
||||||
|
$Settings["hooks"] = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add or update UserPromptSubmit hook
|
||||||
|
$Settings["hooks"]["UserPromptSubmit"] = @(
|
||||||
|
@{
|
||||||
|
"hooks" = @(
|
||||||
|
@{
|
||||||
|
"type" = "command"
|
||||||
|
"command" = "node $HookPath"
|
||||||
|
"timeout" = 60
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write back to file with proper formatting
|
||||||
|
$Settings | ConvertTo-Json -Depth 10 | Set-Content $SettingsFile
|
||||||
|
Write-Host "✅ Successfully updated settings.json" -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Host "❌ Error updating settings: $_" -ForegroundColor Red
|
||||||
|
Write-Host "Your original settings have been backed up to: $BackupFile"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "✅ Installation Complete!" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Next steps:"
|
||||||
|
Write-Host " 1. Restart Claude Code"
|
||||||
|
Write-Host " 2. Test by submitting any prompt (e.g., 'help me build a feature')"
|
||||||
|
Write-Host " 3. You should see '🔍 Instruction Analysis' in the response"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "To uninstall:"
|
||||||
|
Write-Host " 1. Edit $SettingsFile"
|
||||||
|
Write-Host " 2. Remove the 'hooks' > 'UserPromptSubmit' section"
|
||||||
|
Write-Host " 3. Restart Claude Code"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Original settings backed up to:"
|
||||||
|
Write-Host " $BackupFile"
|
||||||
|
Write-Host ""
|
||||||
170
hooks/install-hook.sh
Executable file
170
hooks/install-hook.sh
Executable file
@@ -0,0 +1,170 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Puerto Prompt Analyzer Hook Installer
|
||||||
|
#
|
||||||
|
# Automatically configures the Puerto Prompt Analyzer hook in your
|
||||||
|
# Claude Code settings.json file.
|
||||||
|
#
|
||||||
|
# Usage: ./install-hook.sh
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🔧 Puerto Prompt Analyzer Hook Installer"
|
||||||
|
echo "========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Detect OS
|
||||||
|
OS="$(uname -s)"
|
||||||
|
case "$OS" in
|
||||||
|
Darwin*) OS_TYPE="macOS";;
|
||||||
|
Linux*) OS_TYPE="Linux";;
|
||||||
|
CYGWIN*|MINGW*|MSYS*) OS_TYPE="Windows";;
|
||||||
|
*) OS_TYPE="Unknown";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "📍 Detected OS: $OS_TYPE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Set paths based on OS
|
||||||
|
if [ "$OS_TYPE" = "Windows" ]; then
|
||||||
|
SETTINGS_FILE="$USERPROFILE/.claude/settings.json"
|
||||||
|
PLUGIN_SEARCH_DIR="$USERPROFILE/.claude/plugins"
|
||||||
|
else
|
||||||
|
SETTINGS_FILE="$HOME/.claude/settings.json"
|
||||||
|
PLUGIN_SEARCH_DIR="$HOME/.claude/plugins"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 1: Find the hook script
|
||||||
|
echo "🔍 Step 1: Finding puerto-prompt-analyzer.js..."
|
||||||
|
|
||||||
|
if [ "$OS_TYPE" = "macOS" ] || [ "$OS_TYPE" = "Linux" ]; then
|
||||||
|
HOOK_PATH=$(find "$PLUGIN_SEARCH_DIR" -name "puerto-prompt-analyzer.js" 2>/dev/null | head -1)
|
||||||
|
else
|
||||||
|
echo "⚠️ Windows detected. Please run the PowerShell version: install-hook.ps1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$HOOK_PATH" ]; then
|
||||||
|
echo "❌ Error: Could not find puerto-prompt-analyzer.js"
|
||||||
|
echo ""
|
||||||
|
echo "Please ensure the essentials plugin is installed:"
|
||||||
|
echo " /plugin install essentials@puerto"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Found hook at: $HOOK_PATH"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 2: Check if Node.js is available
|
||||||
|
echo "🔍 Step 2: Checking Node.js installation..."
|
||||||
|
|
||||||
|
if ! command -v node &> /dev/null; then
|
||||||
|
echo "❌ Error: Node.js not found in PATH"
|
||||||
|
echo ""
|
||||||
|
echo "Please install Node.js >= v18.0.0"
|
||||||
|
echo "Visit: https://nodejs.org/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
NODE_VERSION=$(node --version)
|
||||||
|
echo "✅ Found Node.js: $NODE_VERSION"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 3: Create or update settings.json
|
||||||
|
echo "🔍 Step 3: Updating settings.json..."
|
||||||
|
|
||||||
|
# Check if settings file exists
|
||||||
|
if [ ! -f "$SETTINGS_FILE" ]; then
|
||||||
|
echo "📝 Creating new settings.json..."
|
||||||
|
mkdir -p "$(dirname "$SETTINGS_FILE")"
|
||||||
|
echo '{}' > "$SETTINGS_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Backup original settings
|
||||||
|
BACKUP_FILE="${SETTINGS_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
cp "$SETTINGS_FILE" "$BACKUP_FILE"
|
||||||
|
echo "📦 Backup created: $BACKUP_FILE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Read current settings
|
||||||
|
CURRENT_SETTINGS=$(cat "$SETTINGS_FILE")
|
||||||
|
|
||||||
|
# Check if hook already exists
|
||||||
|
if echo "$CURRENT_SETTINGS" | grep -q "puerto-prompt-analyzer"; then
|
||||||
|
echo "⚠️ Hook configuration already exists in settings.json"
|
||||||
|
echo ""
|
||||||
|
read -p "Do you want to update it? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "❌ Installation cancelled"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use Python to safely merge JSON
|
||||||
|
python3 << PYTHON_EOF
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Read current settings
|
||||||
|
with open("$SETTINGS_FILE", "r") as f:
|
||||||
|
settings = json.load(f)
|
||||||
|
|
||||||
|
# Ensure hooks object exists
|
||||||
|
if "hooks" not in settings:
|
||||||
|
settings["hooks"] = {}
|
||||||
|
|
||||||
|
# Add or update UserPromptSubmit hook
|
||||||
|
settings["hooks"]["UserPromptSubmit"] = [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "node $HOOK_PATH",
|
||||||
|
"timeout": 60
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Write back to file
|
||||||
|
with open("$SETTINGS_FILE", "w") as f:
|
||||||
|
json.dump(settings, f, indent=2)
|
||||||
|
f.write("\n")
|
||||||
|
|
||||||
|
print("✅ Successfully updated settings.json")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error updating settings: {e}")
|
||||||
|
print(f"Your original settings have been backed up to: $BACKUP_FILE")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
PYTHON_EOF
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Installation failed. Your original settings are safe in:"
|
||||||
|
echo " $BACKUP_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Installation Complete!"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Restart Claude Code"
|
||||||
|
echo " 2. Test by submitting any prompt (e.g., 'help me build a feature')"
|
||||||
|
echo " 3. You should see '🔍 Instruction Analysis' in the response"
|
||||||
|
echo ""
|
||||||
|
echo "To uninstall:"
|
||||||
|
echo " 1. Edit $SETTINGS_FILE"
|
||||||
|
echo " 2. Remove the 'hooks' > 'UserPromptSubmit' section"
|
||||||
|
echo " 3. Restart Claude Code"
|
||||||
|
echo ""
|
||||||
|
echo "Original settings backed up to:"
|
||||||
|
echo " $BACKUP_FILE"
|
||||||
|
echo ""
|
||||||
37
hooks/puerto-prompt-analyzer.example.json
Normal file
37
hooks/puerto-prompt-analyzer.example.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"$schema": "Configuration for Puerto Prompt Analyzer Hook v2.0",
|
||||||
|
"minScore": 8,
|
||||||
|
"maxRecommendations": 3,
|
||||||
|
"cacheMinutes": 1,
|
||||||
|
"blacklist": [],
|
||||||
|
"favoriteCategories": [],
|
||||||
|
"showScores": false,
|
||||||
|
|
||||||
|
"_comments": {
|
||||||
|
"minScore": "Minimum score threshold (0-100). Higher = more selective. Default: 8",
|
||||||
|
"maxRecommendations": "Maximum number of plugin recommendations to show. Default: 3",
|
||||||
|
"cacheMinutes": "How long to cache marketplace data in minutes. Default: 1",
|
||||||
|
"blacklist": "Array of plugin names to never recommend. Example: ['plugin-name']",
|
||||||
|
"favoriteCategories": "Array of categories to boost in recommendations. Example: ['frontend', 'backend']",
|
||||||
|
"showScores": "Show relevance scores in output for debugging. Default: false"
|
||||||
|
},
|
||||||
|
|
||||||
|
"_examples": {
|
||||||
|
"conservative": {
|
||||||
|
"minScore": 12,
|
||||||
|
"maxRecommendations": 2,
|
||||||
|
"showScores": false
|
||||||
|
},
|
||||||
|
"exploratory": {
|
||||||
|
"minScore": 5,
|
||||||
|
"maxRecommendations": 5,
|
||||||
|
"showScores": true
|
||||||
|
},
|
||||||
|
"frontend_focused": {
|
||||||
|
"minScore": 8,
|
||||||
|
"maxRecommendations": 3,
|
||||||
|
"favoriteCategories": ["frontend", "ui", "design"],
|
||||||
|
"blacklist": ["backend-specific-plugin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
790
hooks/puerto-prompt-analyzer.js
Executable file
790
hooks/puerto-prompt-analyzer.js
Executable file
@@ -0,0 +1,790 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puerto Prompt Analyzer Hook for Claude Code (v2.0)
|
||||||
|
*
|
||||||
|
* Analyzes user prompts before Claude processes them, providing:
|
||||||
|
* - Task type classification (research, implementation, mixed)
|
||||||
|
* - Instruction quality validation
|
||||||
|
* - Intelligent plugin recommendations from Puerto marketplace
|
||||||
|
* - Project context awareness
|
||||||
|
* - Caching and performance optimization
|
||||||
|
*
|
||||||
|
* Part of the essentials plugin
|
||||||
|
* @see plugins/essentials/hooks/README.md for documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// CONFIGURATION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
const RESEARCH_KEYWORDS = [
|
||||||
|
'explain', 'analyze', 'research', 'investigate', 'understand',
|
||||||
|
'review', 'compare', 'summarize', 'describe', 'document',
|
||||||
|
'learn', 'study', 'explore', 'examine', 'evaluate'
|
||||||
|
];
|
||||||
|
|
||||||
|
const IMPLEMENTATION_KEYWORDS = [
|
||||||
|
'implement', 'create', 'build', 'fix', 'refactor', 'add',
|
||||||
|
'modify', 'write', 'develop', 'code', 'make', 'update',
|
||||||
|
'change', 'remove', 'delete', 'optimize', 'improve', 'deploy'
|
||||||
|
];
|
||||||
|
|
||||||
|
const STOP_WORDS = new Set([
|
||||||
|
'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
|
||||||
|
'of', 'with', 'by', 'from', 'as', 'is', 'was', 'are', 'be', 'been',
|
||||||
|
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'should',
|
||||||
|
'could', 'may', 'might', 'can', 'this', 'that', 'these', 'those'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const VALIDATION_PATTERNS = {
|
||||||
|
tooVague: {
|
||||||
|
patterns: [/^(fix it|make it better|improve this|do it|help)$/i],
|
||||||
|
suggestion: 'Be more specific about what you want to fix or improve'
|
||||||
|
},
|
||||||
|
missingContext: {
|
||||||
|
patterns: [/\b(this|that|it)\b/i],
|
||||||
|
minLength: 30,
|
||||||
|
suggestion: 'Provide clear context - what specifically does "this" or "that" refer to?'
|
||||||
|
},
|
||||||
|
overlyBroad: {
|
||||||
|
patterns: [/^(build an? app|create a (website|system)|make (something|a thing))$/i],
|
||||||
|
suggestion: 'Break down your request into specific features or components'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scoring weights (tuned for better results)
|
||||||
|
const WEIGHTS = {
|
||||||
|
keywordMatch: 3,
|
||||||
|
nameMatch: 5,
|
||||||
|
descriptionOverlap: 2,
|
||||||
|
categoryMatch: 4,
|
||||||
|
taskTypeAlign: 5,
|
||||||
|
projectTypeMatch: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const MIN_SCORE_THRESHOLD = 8;
|
||||||
|
const MAX_RECOMMENDATIONS = 3;
|
||||||
|
const CACHE_TTL = 60000; // 60 seconds
|
||||||
|
const SESSION_MEMORY_TTL = 3600000; // 1 hour
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// CACHING & SESSION MANAGEMENT
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
const CACHE = {
|
||||||
|
marketplace: null,
|
||||||
|
marketplacePath: null,
|
||||||
|
timestamp: 0,
|
||||||
|
installedPlugins: null,
|
||||||
|
installedTimestamp: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const SESSION_MEMORY = new Map(); // session_id -> { shown: Set, timestamp }
|
||||||
|
|
||||||
|
function cleanupOldSessions() {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const [sessionId, data] of SESSION_MEMORY.entries()) {
|
||||||
|
if (now - data.timestamp > SESSION_MEMORY_TTL) {
|
||||||
|
SESSION_MEMORY.delete(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSessionMemory(sessionId) {
|
||||||
|
if (!SESSION_MEMORY.has(sessionId)) {
|
||||||
|
SESSION_MEMORY.set(sessionId, {
|
||||||
|
shown: new Set(),
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return SESSION_MEMORY.get(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function markAsShown(sessionId, pluginName) {
|
||||||
|
const memory = getSessionMemory(sessionId);
|
||||||
|
memory.shown.add(pluginName);
|
||||||
|
memory.timestamp = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
function wasRecentlyShown(sessionId, pluginName) {
|
||||||
|
const memory = SESSION_MEMORY.get(sessionId);
|
||||||
|
return memory && memory.shown.has(pluginName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// MAIN ENTRY POINT
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const perfStart = Date.now();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Cleanup old sessions periodically
|
||||||
|
if (Math.random() < 0.1) { // 10% chance
|
||||||
|
cleanupOldSessions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read hook input from stdin
|
||||||
|
const input = fs.readFileSync(0, 'utf-8');
|
||||||
|
const hookInput = JSON.parse(input);
|
||||||
|
|
||||||
|
// Analyze and generate output
|
||||||
|
const result = analyzeInstruction(hookInput);
|
||||||
|
|
||||||
|
// Output JSON to stdout
|
||||||
|
console.log(JSON.stringify(result, null, 2));
|
||||||
|
|
||||||
|
// Performance logging
|
||||||
|
const elapsed = Date.now() - perfStart;
|
||||||
|
if (elapsed > 500) {
|
||||||
|
console.error(`[puerto-prompt-analyzer] SLOW execution: ${elapsed}ms`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
// Fail open - log error but allow prompt to proceed
|
||||||
|
console.error('[puerto-prompt-analyzer] Fatal error:', error.message);
|
||||||
|
console.log(JSON.stringify(allowPrompt()));
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// CORE ANALYSIS LOGIC
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function analyzeInstruction(hookInput) {
|
||||||
|
try {
|
||||||
|
const { prompt, cwd, session_id } = hookInput;
|
||||||
|
|
||||||
|
// Skip if empty or command
|
||||||
|
if (!prompt || !prompt.trim()) {
|
||||||
|
return allowPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prompt.trim().startsWith('/')) {
|
||||||
|
return allowPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load configuration
|
||||||
|
const config = loadConfiguration();
|
||||||
|
|
||||||
|
// Classify task type
|
||||||
|
const taskType = classifyTaskType(prompt);
|
||||||
|
|
||||||
|
// Detect project context
|
||||||
|
const projectContext = detectProjectContext(cwd);
|
||||||
|
|
||||||
|
// Validate instruction quality
|
||||||
|
const validation = validateInstruction(prompt);
|
||||||
|
|
||||||
|
// Load and score plugins
|
||||||
|
const recommendations = getPluginRecommendations(
|
||||||
|
prompt,
|
||||||
|
taskType,
|
||||||
|
cwd,
|
||||||
|
session_id,
|
||||||
|
projectContext,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mark shown plugins
|
||||||
|
recommendations.forEach(p => markAsShown(session_id, p.name));
|
||||||
|
|
||||||
|
// Generate markdown output
|
||||||
|
const additionalContext = formatRecommendations(
|
||||||
|
taskType,
|
||||||
|
recommendations,
|
||||||
|
validation,
|
||||||
|
projectContext
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
decision: undefined,
|
||||||
|
reason: 'Analysis complete',
|
||||||
|
hookSpecificOutput: {
|
||||||
|
hookEventName: 'UserPromptSubmit',
|
||||||
|
additionalContext
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[puerto-prompt-analyzer] Error during analysis:', error.message);
|
||||||
|
return allowPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// CONFIGURATION MANAGEMENT
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function loadConfiguration() {
|
||||||
|
const configPath = path.join(os.homedir(), '.claude', 'puerto-prompt-analyzer.json');
|
||||||
|
|
||||||
|
const defaults = {
|
||||||
|
minScore: MIN_SCORE_THRESHOLD,
|
||||||
|
maxRecommendations: MAX_RECOMMENDATIONS,
|
||||||
|
cacheMinutes: 1,
|
||||||
|
blacklist: [],
|
||||||
|
favoriteCategories: [],
|
||||||
|
showScores: false
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(configPath)) {
|
||||||
|
const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||||
|
return { ...defaults, ...userConfig };
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[puerto-prompt-analyzer] Error loading config:', error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PROJECT CONTEXT DETECTION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function detectProjectContext(cwd) {
|
||||||
|
if (!cwd) return { type: 'unknown', files: [] };
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
type: 'unknown',
|
||||||
|
languages: [],
|
||||||
|
frameworks: [],
|
||||||
|
files: []
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check for package.json (JavaScript/Node.js)
|
||||||
|
if (fs.existsSync(path.join(cwd, 'package.json'))) {
|
||||||
|
context.type = 'javascript';
|
||||||
|
context.languages.push('javascript', 'nodejs');
|
||||||
|
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf-8'));
|
||||||
|
|
||||||
|
// Detect frameworks
|
||||||
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
||||||
|
if (deps['react']) context.frameworks.push('react');
|
||||||
|
if (deps['vue']) context.frameworks.push('vue');
|
||||||
|
if (deps['next']) context.frameworks.push('nextjs');
|
||||||
|
if (deps['express']) context.frameworks.push('express');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Python
|
||||||
|
if (fs.existsSync(path.join(cwd, 'requirements.txt')) ||
|
||||||
|
fs.existsSync(path.join(cwd, 'pyproject.toml'))) {
|
||||||
|
context.type = 'python';
|
||||||
|
context.languages.push('python');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Rust
|
||||||
|
if (fs.existsSync(path.join(cwd, 'Cargo.toml'))) {
|
||||||
|
context.type = 'rust';
|
||||||
|
context.languages.push('rust');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Go
|
||||||
|
if (fs.existsSync(path.join(cwd, 'go.mod'))) {
|
||||||
|
context.type = 'go';
|
||||||
|
context.languages.push('go', 'golang');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Ruby
|
||||||
|
if (fs.existsSync(path.join(cwd, 'Gemfile'))) {
|
||||||
|
context.type = 'ruby';
|
||||||
|
context.languages.push('ruby');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Java/Kotlin
|
||||||
|
if (fs.existsSync(path.join(cwd, 'pom.xml')) ||
|
||||||
|
fs.existsSync(path.join(cwd, 'build.gradle'))) {
|
||||||
|
context.type = 'java';
|
||||||
|
context.languages.push('java');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[puerto-prompt-analyzer] Error detecting project:', error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TEXT PROCESSING UTILITIES
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function stem(word) {
|
||||||
|
// Simple stemmer - remove common suffixes
|
||||||
|
return word
|
||||||
|
.replace(/ies$/, 'y')
|
||||||
|
.replace(/ing$/, '')
|
||||||
|
.replace(/ed$/, '')
|
||||||
|
.replace(/s$/, '')
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenize(text) {
|
||||||
|
return text
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^\w\s-]/g, ' ') // Keep hyphens
|
||||||
|
.split(/\s+/)
|
||||||
|
.map(stem)
|
||||||
|
.filter(w => w.length > 2 && !STOP_WORDS.has(w));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TASK CLASSIFICATION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function classifyTaskType(prompt) {
|
||||||
|
const tokens = tokenize(prompt);
|
||||||
|
const lower = prompt.toLowerCase();
|
||||||
|
|
||||||
|
// Count keyword matches (using stemmed tokens)
|
||||||
|
const researchScore = RESEARCH_KEYWORDS.filter(kw =>
|
||||||
|
tokens.includes(stem(kw)) || lower.includes(kw)
|
||||||
|
).length;
|
||||||
|
|
||||||
|
const implScore = IMPLEMENTATION_KEYWORDS.filter(kw =>
|
||||||
|
tokens.includes(stem(kw)) || lower.includes(kw)
|
||||||
|
).length;
|
||||||
|
|
||||||
|
// Enhanced classification
|
||||||
|
if (implScore > researchScore * 1.5) {
|
||||||
|
return 'Implementation';
|
||||||
|
}
|
||||||
|
if (researchScore > implScore * 1.5) {
|
||||||
|
return 'Research';
|
||||||
|
}
|
||||||
|
if (researchScore > 0 && implScore > 0) {
|
||||||
|
return 'Mixed';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'General';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// INSTRUCTION VALIDATION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function validateInstruction(prompt) {
|
||||||
|
const suggestions = [];
|
||||||
|
|
||||||
|
// Check for vague instructions
|
||||||
|
if (VALIDATION_PATTERNS.tooVague.patterns.some(p => p.test(prompt))) {
|
||||||
|
suggestions.push(VALIDATION_PATTERNS.tooVague.suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for missing context (only if prompt is very short)
|
||||||
|
const minLength = VALIDATION_PATTERNS.missingContext.minLength;
|
||||||
|
if (prompt.length < minLength &&
|
||||||
|
VALIDATION_PATTERNS.missingContext.patterns.some(p => p.test(prompt))) {
|
||||||
|
suggestions.push(VALIDATION_PATTERNS.missingContext.suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for overly broad requests
|
||||||
|
if (VALIDATION_PATTERNS.overlyBroad.patterns.some(p => p.test(prompt))) {
|
||||||
|
suggestions.push(VALIDATION_PATTERNS.overlyBroad.suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { suggestions };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// INSTALLED PLUGINS DETECTION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function getInstalledPlugins() {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// Use cache
|
||||||
|
if (CACHE.installedPlugins && (now - CACHE.installedTimestamp) < CACHE_TTL) {
|
||||||
|
return CACHE.installedPlugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
const installed = new Set();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
||||||
|
|
||||||
|
if (fs.existsSync(settingsPath)) {
|
||||||
|
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
||||||
|
|
||||||
|
if (settings.enabledPlugins) {
|
||||||
|
Object.keys(settings.enabledPlugins).forEach(pluginId => {
|
||||||
|
// Extract plugin name from "plugin@marketplace" format
|
||||||
|
const pluginName = pluginId.split('@')[0];
|
||||||
|
installed.add(pluginName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[puerto-prompt-analyzer] Error reading installed plugins:', error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
CACHE.installedPlugins = installed;
|
||||||
|
CACHE.installedTimestamp = now;
|
||||||
|
|
||||||
|
return installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PLUGIN RECOMMENDATIONS
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function getPluginRecommendations(prompt, taskType, cwd, sessionId, projectContext, config) {
|
||||||
|
try {
|
||||||
|
// Find and load marketplace.json (with caching)
|
||||||
|
const marketplacePath = findMarketplaceJson(cwd);
|
||||||
|
|
||||||
|
if (!marketplacePath) {
|
||||||
|
console.error('[puerto-prompt-analyzer] marketplace.json not found');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const marketplace = getMarketplaceData(marketplacePath);
|
||||||
|
|
||||||
|
if (!marketplace || !marketplace.plugins || !Array.isArray(marketplace.plugins)) {
|
||||||
|
console.error('[puerto-prompt-analyzer] Invalid marketplace format');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const installedPlugins = getInstalledPlugins();
|
||||||
|
|
||||||
|
// Score all plugins
|
||||||
|
const scored = marketplace.plugins
|
||||||
|
.map(plugin => ({
|
||||||
|
...plugin,
|
||||||
|
score: scorePlugin(plugin, prompt, taskType, sessionId, projectContext, installedPlugins, config)
|
||||||
|
}))
|
||||||
|
.filter(p => p.score >= config.minScore) // Quality threshold
|
||||||
|
.sort((a, b) => b.score - a.score);
|
||||||
|
|
||||||
|
// Apply diversity (don't show too many similar plugins)
|
||||||
|
const diverse = diversifyRecommendations(scored, config.maxRecommendations);
|
||||||
|
|
||||||
|
// Add recommendation reasons
|
||||||
|
return diverse.map(plugin => ({
|
||||||
|
...plugin,
|
||||||
|
reason: generateReason(plugin, taskType, prompt, projectContext)
|
||||||
|
}));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[puerto-prompt-analyzer] Error loading marketplace:', error.message);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMarketplaceData(marketplacePath) {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// Check cache
|
||||||
|
if (CACHE.marketplace &&
|
||||||
|
CACHE.marketplacePath === marketplacePath &&
|
||||||
|
(now - CACHE.timestamp) < CACHE_TTL) {
|
||||||
|
return CACHE.marketplace;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and cache
|
||||||
|
try {
|
||||||
|
CACHE.marketplace = JSON.parse(fs.readFileSync(marketplacePath, 'utf-8'));
|
||||||
|
CACHE.marketplacePath = marketplacePath;
|
||||||
|
CACHE.timestamp = now;
|
||||||
|
return CACHE.marketplace;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[puerto-prompt-analyzer] Error parsing marketplace:', error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findMarketplaceJson(startDir) {
|
||||||
|
if (!startDir) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentDir = startDir;
|
||||||
|
|
||||||
|
// Search up to 5 levels up
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const marketplacePath = path.join(currentDir, '.claude-plugin', 'marketplace.json');
|
||||||
|
|
||||||
|
if (fs.existsSync(marketplacePath)) {
|
||||||
|
return marketplacePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentDir = path.dirname(currentDir);
|
||||||
|
if (parentDir === currentDir) {
|
||||||
|
break; // Reached root
|
||||||
|
}
|
||||||
|
currentDir = parentDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scorePlugin(plugin, prompt, taskType, sessionId, projectContext, installedPlugins, config) {
|
||||||
|
const promptTokens = new Set(tokenize(prompt));
|
||||||
|
const lower = prompt.toLowerCase();
|
||||||
|
let score = 0;
|
||||||
|
|
||||||
|
// Skip essentials plugin (it's already installed by definition)
|
||||||
|
if (plugin.name === 'essentials') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip blacklisted plugins
|
||||||
|
if (config.blacklist.includes(plugin.name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip installed plugins
|
||||||
|
if (installedPlugins.has(plugin.name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce score for recently shown plugins
|
||||||
|
if (wasRecentlyShown(sessionId, plugin.name)) {
|
||||||
|
score -= 5; // Penalty for repetition
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Tokenized description overlap (better than simple word matching)
|
||||||
|
if (plugin.description) {
|
||||||
|
const descTokens = tokenize(plugin.description);
|
||||||
|
const overlap = descTokens.filter(t => promptTokens.has(t)).length;
|
||||||
|
score += overlap * WEIGHTS.descriptionOverlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Name match (strong signal)
|
||||||
|
if (plugin.name) {
|
||||||
|
const nameWords = plugin.name.split('-');
|
||||||
|
const nameMatches = nameWords.filter(w =>
|
||||||
|
promptTokens.has(stem(w)) || lower.includes(w)
|
||||||
|
).length;
|
||||||
|
score += nameMatches * WEIGHTS.nameMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Keywords match
|
||||||
|
if (plugin.keywords && Array.isArray(plugin.keywords)) {
|
||||||
|
const keywordMatches = plugin.keywords.filter(kw =>
|
||||||
|
promptTokens.has(stem(kw)) || lower.includes(kw.toLowerCase())
|
||||||
|
).length;
|
||||||
|
score += keywordMatches * WEIGHTS.keywordMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Task type alignment
|
||||||
|
if (taskType === 'Implementation') {
|
||||||
|
if (plugin.description && /agent|specialist|builder|creator|developer/.test(plugin.description.toLowerCase())) {
|
||||||
|
score += WEIGHTS.taskTypeAlign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taskType === 'Research') {
|
||||||
|
if (plugin.description && /skill|knowledge|guide|reference|documentation/.test(plugin.description.toLowerCase())) {
|
||||||
|
score += WEIGHTS.taskTypeAlign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Project context matching
|
||||||
|
if (projectContext.type !== 'unknown') {
|
||||||
|
const contextTerms = [
|
||||||
|
...projectContext.languages,
|
||||||
|
...projectContext.frameworks,
|
||||||
|
projectContext.type
|
||||||
|
];
|
||||||
|
|
||||||
|
contextTerms.forEach(term => {
|
||||||
|
if (plugin.keywords && plugin.keywords.some(kw => kw.toLowerCase().includes(term))) {
|
||||||
|
score += WEIGHTS.projectTypeMatch;
|
||||||
|
}
|
||||||
|
if (plugin.description && plugin.description.toLowerCase().includes(term)) {
|
||||||
|
score += WEIGHTS.projectTypeMatch * 0.5;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Category boost for favorites
|
||||||
|
if (config.favoriteCategories.length > 0 && plugin.category) {
|
||||||
|
if (config.favoriteCategories.includes(plugin.category)) {
|
||||||
|
score += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.max(0, score); // Never negative
|
||||||
|
}
|
||||||
|
|
||||||
|
function diversifyRecommendations(plugins, maxCount) {
|
||||||
|
const selected = [];
|
||||||
|
const usedCategories = new Set();
|
||||||
|
const usedKeywords = new Set();
|
||||||
|
|
||||||
|
// First pass: pick best from different categories
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
if (selected.length >= maxCount) break;
|
||||||
|
|
||||||
|
const category = plugin.category || 'general';
|
||||||
|
const primaryKeyword = (plugin.keywords && plugin.keywords[0]) || '';
|
||||||
|
|
||||||
|
// Prefer different categories and keywords
|
||||||
|
if (!usedCategories.has(category) || selected.length === 0) {
|
||||||
|
selected.push(plugin);
|
||||||
|
usedCategories.add(category);
|
||||||
|
if (primaryKeyword) usedKeywords.add(primaryKeyword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: fill remaining slots if needed
|
||||||
|
if (selected.length < maxCount) {
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
if (selected.length >= maxCount) break;
|
||||||
|
if (!selected.includes(plugin)) {
|
||||||
|
selected.push(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateReason(plugin, taskType, prompt, projectContext) {
|
||||||
|
const reasons = [];
|
||||||
|
|
||||||
|
// Check for strong keyword matches
|
||||||
|
if (plugin.keywords && Array.isArray(plugin.keywords)) {
|
||||||
|
const matches = plugin.keywords.filter(kw =>
|
||||||
|
prompt.toLowerCase().includes(kw.toLowerCase())
|
||||||
|
);
|
||||||
|
if (matches.length > 0) {
|
||||||
|
reasons.push(`Matches keywords: ${matches.slice(0, 2).join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for name matches
|
||||||
|
const nameWords = plugin.name.split('-');
|
||||||
|
const nameMatches = nameWords.filter(w =>
|
||||||
|
prompt.toLowerCase().includes(w)
|
||||||
|
);
|
||||||
|
if (nameMatches.length > 0) {
|
||||||
|
reasons.push(`Related to ${nameMatches.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project context match
|
||||||
|
if (projectContext.type !== 'unknown') {
|
||||||
|
const contextTerms = [...projectContext.languages, ...projectContext.frameworks];
|
||||||
|
const matches = contextTerms.filter(term =>
|
||||||
|
(plugin.description && plugin.description.toLowerCase().includes(term)) ||
|
||||||
|
(plugin.keywords && plugin.keywords.some(kw => kw.toLowerCase().includes(term)))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (matches.length > 0) {
|
||||||
|
reasons.push(`Fits your ${projectContext.type} project`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task type alignment
|
||||||
|
if (taskType === 'Implementation') {
|
||||||
|
reasons.push('Provides specialized implementation tools');
|
||||||
|
} else if (taskType === 'Research') {
|
||||||
|
reasons.push('Offers expert knowledge and guidance');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default reason if nothing specific
|
||||||
|
if (reasons.length === 0) {
|
||||||
|
reasons.push('Relevant to your task based on description');
|
||||||
|
}
|
||||||
|
|
||||||
|
return reasons[0]; // Return the most specific reason
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// OUTPUT FORMATTING
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function formatRecommendations(taskType, plugins, validation, projectContext) {
|
||||||
|
let md = '\n\n---\n\n## 🔍 Puerto Prompt Analysis\n\n';
|
||||||
|
|
||||||
|
// Task type
|
||||||
|
md += `**Task Type:** ${taskType}`;
|
||||||
|
|
||||||
|
// Project context if detected
|
||||||
|
if (projectContext.type !== 'unknown') {
|
||||||
|
md += ` | **Project:** ${projectContext.type}`;
|
||||||
|
if (projectContext.frameworks.length > 0) {
|
||||||
|
md += ` (${projectContext.frameworks.slice(0, 2).join(', ')})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md += '\n';
|
||||||
|
|
||||||
|
// Validation suggestions
|
||||||
|
if (validation.suggestions.length > 0) {
|
||||||
|
md += `\n**💡 Suggestions:**\n`;
|
||||||
|
validation.suggestions.forEach(s => {
|
||||||
|
md += `- ${s}\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin recommendations
|
||||||
|
if (plugins.length === 0) {
|
||||||
|
md += '\n*No specific plugin recommendations found.*\n';
|
||||||
|
md += '\n---\n\n';
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
|
md += `\n**📦 Recommended Plugins:**\n\n`;
|
||||||
|
|
||||||
|
plugins.forEach((plugin, idx) => {
|
||||||
|
md += `### ${idx + 1}. \`${plugin.name}\`\n`;
|
||||||
|
md += `**Description:** ${plugin.description}\n`;
|
||||||
|
md += `**Why:** ${plugin.reason}\n`;
|
||||||
|
|
||||||
|
// Show score if configured
|
||||||
|
const config = loadConfiguration();
|
||||||
|
if (config.showScores) {
|
||||||
|
md += `**Score:** ${Math.round(plugin.score)}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
md += `**Install:** \`/plugin install ${plugin.name}\`\n\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
md += '---\n\n';
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// HELPER FUNCTIONS
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function allowPrompt() {
|
||||||
|
return {
|
||||||
|
decision: undefined,
|
||||||
|
reason: 'Proceeding normally',
|
||||||
|
hookSpecificOutput: {
|
||||||
|
hookEventName: 'UserPromptSubmit',
|
||||||
|
additionalContext: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// RUN
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export for testing
|
||||||
|
module.exports = {
|
||||||
|
classifyTaskType,
|
||||||
|
validateInstruction,
|
||||||
|
scorePlugin,
|
||||||
|
analyzeInstruction,
|
||||||
|
tokenize,
|
||||||
|
stem,
|
||||||
|
detectProjectContext
|
||||||
|
};
|
||||||
89
plugin.lock.json
Normal file
89
plugin.lock.json
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:bandofai/puerto:plugins/essentials",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "1d7dd43a1768c3fc7b535a83fa3c669b64a6a437",
|
||||||
|
"treeHash": "b36d3d22d2cad2af10fabc290ece79080ab009247b792de8c83f97de90e9217a",
|
||||||
|
"generatedAt": "2025-11-28T10:14:07.166608Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "essentials",
|
||||||
|
"description": "Essential MCP servers, requirements management, and intelligent instruction analysis for enhanced Claude Code development workflow",
|
||||||
|
"version": "1.1.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "4b03266f9234b9684fcd902ae863828b7bbea58925b5ed671b96479da12bcd46"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/install-hook.ps1",
|
||||||
|
"sha256": "5a64e32cf0e32ff15858bd1248b459e64b8bc533e887e35b15b81ed0ed4500f9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/puerto-prompt-analyzer.js",
|
||||||
|
"sha256": "f78ed547c63e0b8f1f7075032f7651b8282315f7f44d454296a83af9e3e6f562"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/README.md",
|
||||||
|
"sha256": "49c803fb205d5ff30e3a9fff681f5d5ef1793954df280446c0b1ca5dce0a3162"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/install-hook.sh",
|
||||||
|
"sha256": "2a8a73dac22acb186094e176630e2d025a4cf99e157474682cf9ff399e29bf10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/puerto-prompt-analyzer.example.json",
|
||||||
|
"sha256": "f279af1cfcbca5e466a7087256400f1b348b09205f93498073401c1752073aa6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "b0512cfef3ab8fc2b03efda0f76a20143d6fd66b50c6b2f6587299d7c7928591"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/req-status.md",
|
||||||
|
"sha256": "8d7650964e6ca0a0228a89ffdf2f5c24380558083f99b81724d58050cb929404"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/implement.md",
|
||||||
|
"sha256": "db0df8d097ce319f6c46410235848bf2fa67dbac2647792d9a5f9b2d5320cdc5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/continue.md",
|
||||||
|
"sha256": "cfc00350f59a851fc7ea24a7175837a1aed1640df6a43394ddc3b55850e07a37"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/req-list.md",
|
||||||
|
"sha256": "db85a6742b26ea945d4fccd7241bcae0688d70874df6abd56c4957aa52e79de8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/req-tests.md",
|
||||||
|
"sha256": "68e4c35ad8b1d3972943ce2bb1cdc8c8a49f75029294c70dc7e388fb1e2a9dec"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/req-update.md",
|
||||||
|
"sha256": "8cf6a2c8244f1588481369374d410c769def093939bdf2692ab90a4351933cd7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/brainstorm.md",
|
||||||
|
"sha256": "aee7673e4481b0a833b1ae894db0119a211770c50568b08c93f49520a42d37fb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "b36d3d22d2cad2af10fabc290ece79080ab009247b792de8c83f97de90e9217a"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user