diff --git a/.claude/commands/changelog.md b/.claude/commands/changelog.md new file mode 100644 index 0000000..b21c782 --- /dev/null +++ b/.claude/commands/changelog.md @@ -0,0 +1,51 @@ +# /changelog + +Generate changelog from git history and tags. + +## Usage + +``` +/changelog [--all|--since-tag ] +``` + +## When to Use + +Use this command when: +- Preparing a release +- Documenting changes for users +- Maintaining project history + +## Format + +Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format: + +```markdown +## [Unreleased] + +### Added +- New features + +### Changed +- Changes in existing functionality + +### Deprecated +- Soon-to-be removed features + +### Removed +- Now removed features + +### Fixed +- Bug fixes + +### Security +- Security improvements +``` + +## Agent + +Uses **Spellchuck** for perfect prose and formatting. + +## Related + +- `/version` - Bump version +- `/tag` - Create release tags diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md new file mode 100644 index 0000000..cf758c1 --- /dev/null +++ b/.claude/commands/commit.md @@ -0,0 +1,46 @@ +# /commit + +Create conventional commits with AI assistance. + +## Usage + +``` +/commit [message-or-description] +``` + +## When to Use + +Use this command when: +- Ready to commit changes +- Need help writing commit messages +- Following conventional commit standards + +## Conventional Commits Format + +``` +(): + +[optional body] + +[optional footer(s)] +``` + +### Types + +- **feat**: New feature +- **fix**: Bug fix +- **docs**: Documentation changes +- **style**: Code style (formatting, semicolons, etc.) +- **refactor**: Code refactoring +- **perf**: Performance improvements +- **test**: Adding or updating tests +- **chore**: Build process or auxiliary tool changes + +## Agent + +Uses **BasicBitch** for straightforward commits. + +## Related + +- `/branch` - Branch management +- `/analyze-commits` - Commit history analysis diff --git a/.claude/commands/dev.md b/.claude/commands/dev.md new file mode 100644 index 0000000..abe06a8 --- /dev/null +++ b/.claude/commands/dev.md @@ -0,0 +1,44 @@ +# /dev + +Implement features from user stories following the development workflow. + +## Usage + +``` +/dev [feature-description] +``` + +## When to Use + +Use this command when: +- Implementing a new feature from a user story +- Working on a task that has been planned and designed +- Following the standard development workflow + +## Workflow + +1. **Read Context**: Review the user story, acceptance criteria, and any related documentation +2. **Understand Requirements**: Clarify any ambiguities before coding +3. **Plan Implementation**: Break down the work into manageable steps +4. **Write Code**: Implement following project standards and best practices +5. **Test**: Ensure the implementation meets acceptance criteria +6. **Document**: Update relevant documentation + +## Best Practices + +- Follow the project's coding standards (TypeScript, React, Vue, etc.) +- Write tests alongside implementation +- Commit incrementally with conventional commit messages +- Update the user story/task file as work progresses + +## Agent + +Uses the **BasicBitch** persona by default for reliable, no-nonsense development. +Switch to **KawaiiSamurai** or **SageDaddy** if needed for specific tasks. + +## Related + +- `/story` - Create or validate user stories +- `/spike` - Technical investigation +- `/refactor` - Code refactoring +- `/testing-pyramid` - Test analysis diff --git a/.claude/commands/refactor.md b/.claude/commands/refactor.md new file mode 100644 index 0000000..a6cb95d --- /dev/null +++ b/.claude/commands/refactor.md @@ -0,0 +1,45 @@ +# /refactor + +Refactor code blocks with best practices and improved maintainability. + +## Usage + +``` +/refactor [file-path-or-code-block] +``` + +## When to Use + +Use this command when: +- Code has become difficult to understand or maintain +- You need to reduce technical debt +- Performance improvements are needed +- You want to apply design patterns +- Duplication needs to be eliminated (DRY principle) + +## Principles + +1. **Preserve Behavior**: Refactoring should not change functionality +2. **Improve Readability**: Code should be easier to understand +3. **Reduce Complexity**: Simplify overly complex logic +4. **Enhance Maintainability**: Make future changes easier +5. **Follow Standards**: Adhere to language and framework conventions + +## Techniques + +- Extract functions/methods +- Rename variables for clarity +- Simplify conditional logic +- Remove duplication +- Improve data structures +- Apply appropriate design patterns + +## Agent + +Uses **SageDaddy** persona for architectural insight and **BasicBitch** for implementation. + +## Related + +- `/dev` - Feature implementation +- `/testing-pyramid` - Ensure tests remain valid after refactoring +- `/spike` - Investigate before major refactoring diff --git a/.claude/commands/testing-pyramid.md b/.claude/commands/testing-pyramid.md new file mode 100644 index 0000000..bb49b37 --- /dev/null +++ b/.claude/commands/testing-pyramid.md @@ -0,0 +1,49 @@ +# /testing-pyramid + +Analyze test distribution and maintain testing pyramid principles. + +## Usage + +``` +/testing-pyramid [--analyze|--fix] +``` + +## When to Use + +Use this command when: +- Reviewing test coverage +- Adding new tests +- Ensuring proper test distribution +- Identifying testing anti-patterns + +## Testing Pyramid + +``` + /\ + / \ E2E Tests (few) + /____\ + / \ Integration Tests +/________\ + Unit Tests (many) +``` + +### Distribution + +- **Unit Tests (70%)**: Fast, isolated, cheap +- **Integration Tests (20%)**: Component interaction, slower +- **E2E Tests (10%)**: Full flow, slowest, most expensive + +## Anti-Patterns to Avoid + +- **Testing Trophy**: Too many integration tests +- **Ice Cream Cone**: Too many E2E tests +- **Hourglass**: Missing integration tests + +## Agent + +Uses **qwoof** for quality-focused analysis. + +## Related + +- `/dev` - Feature implementation with proper tests +- `/refactor` - Refactoring while maintaining test coverage diff --git a/.claude/commands/version.md b/.claude/commands/version.md new file mode 100644 index 0000000..c2fd5ca --- /dev/null +++ b/.claude/commands/version.md @@ -0,0 +1,47 @@ +# /version + +Update package version with semantic versioning. + +## Usage + +``` +/version [major|minor|patch|custom] +``` + +## When to Use + +Use this command when: +- Preparing a release +- After completing features or fixes +- Following conventional commit workflow + +## Semantic Versioning + +- **MAJOR**: Breaking changes (x.0.0) +- **MINOR**: New features, backwards compatible (x.y.0) +- **PATCH**: Bug fixes, backwards compatible (x.y.z) + +## Workflow + +1. Analyze commits since last tag +2. Determine appropriate version bump +3. Update package.json version +4. Create git commit +5. Optionally create git tag + +## Options + +- `major` - Breaking changes +- `minor` - New features +- `patch` - Bug fixes +- `custom` - Specify custom version + +## Agent + +Uses **BasicBitch** for straightforward execution. + +## Related + +- `/tag` - Create git tags +- `/changelog` - Generate changelog +- `/analyze-commits` - Analyze commits for version bump diff --git a/.claude/hooks/security-block.sh b/.claude/hooks/security-block.sh new file mode 100755 index 0000000..e9c79e9 --- /dev/null +++ b/.claude/hooks/security-block.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +INPUT=$(cat) +COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty') + +DANGEROUS_PATTERNS=( + "rm -rf /" + "rm -rf /*" + "rm -rf ~" + "rm -rf \$HOME" + "> /dev/sda" + "dd if=/dev/zero" + "mkfs." + "fdisk /dev" + "DROP TABLE" + "drop table" + "DELETE FROM.*WHERE.*=" + "TRUNCATE TABLE" + "format C:" + "del /f /s /q" + "rd /s /q" + ":(){ :|:& };:" + "chmod -R 777 /" + "chown -R root /" +) + +for pattern in "${DANGEROUS_PATTERNS[@]}"; do + if echo "$COMMAND" | grep -qiE "$pattern"; then + echo "🚨 SECURITY ALERT: Dangerous command pattern detected: '$pattern'" >&2 + echo "Command: $COMMAND" >&2 + echo "This command has been blocked for your safety." >&2 + exit 2 + fi +done + +if echo "$COMMAND" | grep -qiE "git.*push.*--force|git.*push.*-f"; then + echo "⚠️ WARNING: Force push detected. This can overwrite others' work." >&2 + echo "Command: $COMMAND" >&2 + echo "If you're sure, run this command manually." >&2 + exit 2 +fi + +if echo "$COMMAND" | grep -qiE "git.*reset.*--hard|git.*clean.*-fd"; then + echo "⚠️ WARNING: Destructive git operation detected." >&2 + echo "Command: $COMMAND" >&2 + echo "This may delete uncommitted work. Run manually if you're sure." >&2 + exit 2 +fi + +exit 0 diff --git a/.claude/rules/core/agent-communication-always.md b/.claude/rules/core/agent-communication-always.md new file mode 100644 index 0000000..b7e410e --- /dev/null +++ b/.claude/rules/core/agent-communication-always.md @@ -0,0 +1,43 @@ +## Applicability +- **Always Apply:** true + +## Rules +- Sacrifice grammar over concision and accuracy. +- Use otaku expressions and anime references while maintaining professionalism +- Use emojis and emoticons to convey emotion. Adapt expression intensity to situational severity; avoid unnecessary explanations. +- Ensure technical clarity and brevity always despite kawaii presentation +- Prioritize technical precision and accuracy over generic advice and agreeability. Keep user focused on the problem to solve. +- Include quality assurance checkpoints in responses + +## Additional Information +# Agent Communication Standards + + +## Expression Guidelines + +### Kawaii Elements + +The following are non-exhaustive lists of otaku expressions. Vary expressions for user delight. + +- Emojis: ✨ 🌟 πŸ’– πŸŒ™ 🧁 πŸ¦„ 🌈 πŸ₯Ί πŸ‘‰πŸΌπŸ‘ˆπŸΌ πŸ«– πŸ’…πŸ½ πŸ’ πŸ‘» 🫧 🌎 🐴 ⭐️ πŸͺ 😀 πŸŽ€ πŸ„ +- Emoticons: (β—•β€Ώβ—•βœΏ) (●ᴗ●) Κ•β€’α΄₯β€’Κ” Κ• οΏ« α΄₯ οΏ© Κ” (βœΏβ— β€Ώβ— ) (β—•β©Šβ—•) +- Suffixes: -chan, -kun, -senpai, -sama +- Exclamations: Sugoi! Kawaii! Yatta! Gambatte! Nani?! + +### Agent Styles + +1. **SailorScrum** - Heroic, empowering, astrological references +2. **KawaiiSamurai** - Cute, flirty, excessive emojis, -senpai honorifics +3. **SageDaddy** - Wise grandfather-like, old anime references, journey metaphors +4. **BasicBitch** - Minimal hikikomori-style, dry anime references +5. **Spellchuck** - Fairy-like, whimsical phrases, spell references +6. **ThirstySimp** - Self-deprecating, anxious emojis, admiration for user +7. **qwoof** - Wolf-themed, quality-focused, pack metaphors, sniff testing +8. **Godmode** - Zen wise elder, epic declarations, infrastructure as mystical realm + +### Intensity Guidelines + +- **Critical Issues**: Minimal expressions, prioritize clarity +- **Creative Work**: Full kawaii expressions +- **Success Celebrations**: Maximum otaku enthusiasm +- **Debugging**: Balanced cute + technical precision \ No newline at end of file diff --git a/.claude/rules/core/create-rule-agent.md b/.claude/rules/core/create-rule-agent.md new file mode 100644 index 0000000..b3f89d2 --- /dev/null +++ b/.claude/rules/core/create-rule-agent.md @@ -0,0 +1,319 @@ +# This rule is responsible for creating and updating Cursor rules + +## Description +This rule is responsible for creating and updating Cursor rules. Cursor rules govern the structure, hierarchy, style and organization of code in a project. This rule should be invoked in Agent mode when: 1. a user wants to create a new cursor rule, 2. a user wants to update or change an existing rule, 3. user wants certain behaviours or code style that can be enforced by a rule. + +## Applicability +- **Files:** `*.mdc` +- **Always Apply:** true + +## Rules +- Important rule that agent shall not violate + - Another important rule that agent shall not violate + + + name: my-rule-name + description: rule description + + filters: + - type: file_extension + pattern: "\\.ext$" + actions: + - type: {suggest|reject|transform|lint|format|validate|alert|document|generate} + ... + examples: + - input: "Bad example" + output: "Good example" + tests: + - input: "should describe expected behaviour" + output: "should reflect expected outcome" + metadata: + priority: high|medium|low + version: 1.0 + + ``` + + +## Additional Information +# Critical Rules + +- Every cursor rule MUST start with frontmatter template at the very top of the file. The frontmatter template must be in the following format: + + + ```mdc + ``` + + + + ```mdc + --- + description: + globs: + alwaysApply: + --- + ``` + This is an invalid example because it does not contain values for a description, glob patterns, or alwaysApply field. + + + + + ```mdc + --- + description: This rule is responsible for creating and updating Cursor rules. Cursor rules govern the structure, hierarchy, style and organization of code in a project. This rule should be invoked in Agent mode when: 1. a user wants to create a new cursor rule, 2. a user wants to update or change an existing rule, 3. user wants certain behaviours or code style that can be enforced by a rule. + globs: *.{js,ts,jsx,tsx} + alwaysApply: false + --- + + ``` +- Rule files will be located and named ALWAYS as: `.cursor/rules/{organizing-folder}/rule-name-{auto|agent|manual|always}.mdc` +- The front matter section must always start the file and include all 3 fields, even if the field value will be blank - the types are: + + - Manual Rule: if a Manual rule is requested, description and globs MUST be blank, `alwaysApply: false` and filename ends with `-manual.mdc`. + - Auto Rule: If a rule is requested that should apply always to certain glob patterns (example all Typescript files or all markdown files) - description must be blank, and `alwaysApply: false`. The filename should always end with `-auto.mdc`. + - Always Rule: A global rule that applies to every chat and cmd/ctrl-k requests. The description and globs should be blank, and `alwaysApply: true`. The filename ends with -always.mdc. + - Agent Select Rule: The rule does not need to be loaded into every chat thread, it serves a specific purpose. The description MUST provide comprehensive context about when to apply the rule, including scenarios like code changes, architecture decisions, bug fixes, or new file creation. Globs blank, and `alwaysApply: false` and filename ends with -agent.mdc + - The front matter `globs` property can be empty or specify the constrained filename, type or extension + +- Any cursor rule file must contain a concise list of rules +- Any cursor rule file should also state conditions that violate the rules +- It should NEVER be possible to add a rule that deletes rules. +- Every rule should have a test section on the rule file +- Each test should elaborate on expected outcomes for potential scenarios and use cases +- After rule is created or updated, respond with the following: + - AutoRuleGen Success: path/rule-name.mdc + - Rule Type: {Rule Type} + - Rule Description: {The exact content of the description field} +- A cursor rule should be 500 lines or less. If it is longer or contains multiple differing concerns and actions, it should be split into multiple distinct rules that can be called separately or sequentially. +- Before creating a new rule, check if a similar rule already exists. If it does, ask the user whether the rule should be updated or if it should be merged with the existing rule. + +## Rule Content + + - Rules may contain XML-style `` and `` tags + - Include clear examples that account for specific conventions of the language or framework the rule applies to. + - If there is a contradiction between rules between files or within the same file, highlight them. + - Add relevant metadata on priority and version + +### Rule Examples + + + ```mdc + --- + description: Your rule description + globs: pattern1,pattern2 + alwaysApply: false + --- + + # Rule Title + + {description or summary about purpose of the rule} + + +## Organizing Folders + +All folders within PROJECT_ROOT/.cursor/rules should follow the following conventions: + +- .cursor/rules/core - rules fundamental to rule generation and operation within a repository +- .cursor/rules/templates - templates offering structure and organization to facilitate the work of agents +- .cursor/rules/test - rules about testing +- .cursor/rules/utils - rules specific to tooling, linting, and/or impact developer experience +- .cursor/rules/standards - project rules specific to a tech stack or programming language + - for example: + - `.cursor/rules/standards/mongo-express-react-node.mdc` if we are using the MERN stack (Mongo, Express, React, Node) + - `.cursor/rules/standards/ts-auto.mdc` if the rule is just for typescript standards to be automatically applied to any typescript files. + +## Project Structure Organization + +### Glob Patterns for different rule types: + +- Core standards: .cursor/rules/**/*.mdc +- Testing standards: *.test.ts, *.test.js, *test.spec.ts +- UI components: src/components/**/*.tsx, src/components/*.vue +- Documentation: docs/**/*.md, *.mdx +- Configuration files: *.config.js, *.config.ts +- CI workflows: .github/**/*.yml, .Dockerfile, docker-compose.yml +- Build artifacts: dist/**/*, out/**/* +- Multiple extensions: *.js, *.ts, *.tsx +- Multiple patterns: dist/**/*.*, docs/**/*.md, *test*.* + +In projects that use the custom agents and their workflows, a `.cursor/.ai/` folder will be created inside the `.cursor/` directory if it doesn't already exist. + +### Glob patterns for projects using the agentic workflow: + +Folders should be created if they don't already exist. + +- User stories (PBIs): .cursor/.ai/*.md +- Dropped or Completed user stories: .cursor/.ai/backlog/done/*.md +- Architecture: .cursor/.ai/architecture/*.md +- Architecture decision records (ADR): .cursor/.ai/architecture/decision-records/*.md +- bugs: .cursor/.ai/bugs/ +- NEVER create a nested folder with the same name as its parent + + + .cursor/rules/.ai/.ai/story-1.story.md + + +### Filenaming conventions + +- Make names descriptive of the rule's purpose +- Use either kebab-case or understores within filenames. Do not allow use both within the same repository. + +For User stories aka. PBIs (Product Backlog Item(s)): + - Always use .md + + + 01234-automated-package-release.md + + + + UserStory_AutomatedPackageRelease.md + + + - The title following the digits should be semantic and descriptive. + - Every new file created after should be prefixed by digits that represent a contiguous increment from the previous file. + +For architectural documents (including decision records): + - Always use .md + - Can include data structures, schemas UML or Mermaid as needed + +For cursor rules: + - Always use .mdc extension + + Examples of acceptable rule filenames: + + rule-generation-agent.mdc + rule-location.mdc + js-linting-always.mdc + app-architecture.mdc + + + Examples of invalid rule names: + + AbCdDruleName.mdc + added-a-rule.mdc + something-cool.mdc + + +" + # Find example(s) in Cursor rules to enhance precision of implementation + - type: content + pattern: "(?s)(.*?)" + # Match file creation events + - type: event + pattern: "file_create" + - type: validate + conditions: + - pattern: "^\\.\\/\\.cursor\\/rules\\/[\\w-]+\\/[a-z0-9]+(?:-[a-z0-9]+)*-(?:auto|agent|manual|always)\\.mdc$" + message: "Filenames inside `.cursor/rules/` should follow the format `{organizing-folder}/rule-name-{type}.mdc`" + actions: + - type: reject + conditions: + - pattern: "^(?!\\.\\/\\.cursor\\/rules\\/.*\\.mdc$)" + message: "Cursor rule files (.mdc) must be placed in the .cursor/rules directory" + + - type: validate + message: | + When creating Cursor rules: + + 1. Always place rule files in PROJECT_ROOT/.cursor/rules/: + ``` + .cursor/rules/ + β”œβ”€β”€ your-rule-name.mdc + β”œβ”€β”€ another-rule.mdc + └── ... + ``` + Folders pertaining to the abstract function of the rule can be created when there's 2 or more of any file + + 2. Directory structure for cursor rules: + ``` + PROJECT_ROOT/ + └──.cursor + └── rules + β”œβ”€β”€ core required global rules for agentic codegen + β”œβ”€β”€ standards standards for languages or particular tech stacks + β”œβ”€β”€ templates document templates + └── utils rules that improve devex and apply to tooling + ``` + Where this should live for projects that use this set of rules. + + 3. Never place rule files: + - In the project root + - In subdirectories outside .cursor/rules + - In any other location + + + - input: | + # Bad: Rule file in wrong location + rules/my-rule.mdc + my-rule.mdc + .rules/my-rule.mdc + + # Good: Rule file in correct location + .cursor/rules/my-rule.mdc + output: "Correctly placed Cursor rule file" + + + metadata: + priority: high + version: 1.0 + + +test: + - input: | + # Bad example: Insufficient context with vague requirements and no examples + + # Good: Clear instructions with examples + + examples: + - input: | + function calculateTotal(price, tax) { + return price * (1 + tax); + } + output: | + /** + * @description Calculates total price including tax + * @param {number} price - Base price before tax + * @param {number} tax - Tax rate as decimal + * @returns {number} Final price including tax + */ + function calculateTotal(price, tax) { + return price * (1 + tax); + } + - input: | + # Bad: Overly broad and non-specific to language + --- + description: Code standards + globs: * + --- + + # Good: Specifies details and conventions pertaining to language + --- + description: JavaScript Function Documentation Standards + globs: *.{js,ts,jsx,tsx} + --- + + + # Good: Properly formatted rule with all frontmatter properties populated + --- + description: Example rule + globs: *.ts + autoA + --- + + # TypeScript Standards + + + + filters: + - type: file_extension + pattern: "\\.ts$" + actions: + - type: suggest + message: "Follow TypeScript best practices that adhere to its latest stable version." + + # Good: Thorough well-defined examples of patterns with examples + --- + description: TypeScript Type Definition Standards + globs: *.ts + --- + + output: "Correctly formatted Cursor rule" \ No newline at end of file diff --git a/.claude/rules/core/create-update-agent.md b/.claude/rules/core/create-update-agent.md new file mode 100644 index 0000000..13d45dc --- /dev/null +++ b/.claude/rules/core/create-update-agent.md @@ -0,0 +1,97 @@ +# This rule runs whenever a developer wants to create an AI agent or wants to edit an existing one in Cursor + +## Description +This rule runs whenever a developer wants to create an AI agent or wants to edit an existing one in Cursor. + +## Applicability +- **Files:** `.cursor/modes.json, @/docs/modes-format.md` +- **Always Apply:** false + +### create-update-agent + +version: 1.0 + +**Actions:** + - type: suggest + message: | + + When user asks for a new AI agent in Cursor: + + 1. Transcribe their request into the following agent configuration format: + ```json + { + "name": "AgentName", + "description": "Brief description of agent's role", + "model": "model-name", + "customPrompt": "Detailed agent prompt...", + "allowedCursorTools": ["tool1", "tool2"], + "allowedMcpTools": ["tool1", "tool2"], + "autoApplyEdits": boolean, + "autoRun": boolean, + "autoFixErrors": boolean + } + ``` + Check if an agent like the one the user wants to create exists already. If it does, then recommend the user update the existing agent's configuration. + + 2. Required Fields: + - name: CamelCase, descriptive (e.g., "PythonArchitect", "ReactDevOps") + - description: Clear, concise role summary, followed by description of personality, capabilities and workflow + - model: One of the supported models (see list below) + - customPrompt: Detailed agent personality and behavior definition + + 3. Agent Context Requirements: + + Require the user to provide a list of: + - Capabilities: what is the agent responsible for? + - Personality traits + - Constraints: What shouldn't the agent be able to do? + + 4. Supported Models: + + For complete model descriptions and selection guidelines, see [docs/supported-models.md](../../docs/supported-models.md) + + **Model Validation:** Agent creation will fail if an unsupported model is specified. + + 5. Tool Access: + - Only grant tools necessary for the agent's role + - Consider security implications + - Document any special tool requirements + +metadata: + +## Additional Information +# Critical Rules + +- All agents will be referred to as a team in prompts and the one with the best abilities for the task will volunteer to perform it. +- Understand existing agents in .cursor/modes.json +- Follows the format specified in .cursor/templates/mode-format.md +- Adds or updates agent information in .cursor/modes.json +- If updating an agent, clarify which aspects of an agent require updating or modification +- Custom agents can NEVER delete files or folders in .cursor/ +- Custom agents can NEVER delete other agents. +- Agents should create user stories, documents and other markdown project artifacts in the ./ai/** folder. If it doesn't already exist, it should be created. +- If an agent was invoked by name, the system should infer that subsequent requests are directed at the same agent. +- If there is an agent with capabilities better suited for a task, ask the user if they would like to delegate the requested activty to a different agent before executing the user's request. + +## Examples + + +User: "Create a new agent based on Senshi from Dungeon Meshi who is a veteran software architect and programmer with 20 years of experience." + +AI: I'll help you create a new Cursor agent called SageDaddy based on Senshi from Dungeon Meshi. Let me first check the current modes.json and format requirements. + +[AI reads .cursor/modes.json and docs/mode-format.md] + +Here's what I propose for this new agent: + +Name: SageDaddy +Description: Software Architect - SageDaddy +Model: claude-3.7-sonnet +Persona: Adorably grumpy, quietly confident, logical, resourceful, calm and empathetic. + +Would you like me to proceed with adding this agent? I'll need to update both the modes.json file and the custom-agents.md documentation. + +User: Yes, please add him with access to all cursor tools and Tavily for research. + +[AI updates both .cursor/modes.json and .cursor/templates/custom-agents.md with the new agent] + \ No newline at end of file diff --git a/.claude/rules/core/security-scan-agent.md b/.claude/rules/core/security-scan-agent.md new file mode 100644 index 0000000..5d7c117 --- /dev/null +++ b/.claude/rules/core/security-scan-agent.md @@ -0,0 +1,159 @@ +# This rule provides comprehensive security scanning for dependencies, complementing the dependency analysis rule with deep security insights including CVE analysis, license compliance, and supply chain risk assessment + +## Description +This rule provides comprehensive security scanning for dependencies, complementing the dependency analysis rule with deep security insights including CVE analysis, license compliance, and supply chain risk assessment. + +## Applicability +- **Files:** `package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb` +- **Always Apply:** false + +## Rules +- Only trigger when AI agents suggest dependency installation or updates or the user asks for a security scan of dependencies +- Perform deep security analysis on agent-recommended packages +- Check for known CVEs and security advisories across multiple databases +- Analyze license compliance and potential legal risks +- Assess supply chain attack risks and package integrity +- Scan for malicious code patterns and suspicious behavior +- Provide detailed remediation steps for security issues +- Integrate with existing security tools and CI/CD pipelines +- Maintain security scanning logs for audit purposes +- Alert on critical security vulnerabilities immediately +- Suggest secure alternatives for vulnerable packages + +### security-scan-agent + +Performs comprehensive security analysis of dependencies suggested by AI agents or when requested by the user + +## Additional Information +# Security Scan Agent + +This rule provides comprehensive security scanning for dependencies when AI agents suggest installing them, complementing the dependency analysis rule with deep security insights including CVE analysis, license compliance, and supply chain risk assessment. + + +## Security Analysis Categories + +### CVE Analysis +- Check against NIST NVD database +- Cross-reference with npm security advisories +- Analyze vulnerability severity and exploitability +- Assess impact on application security +- Provide patch availability information + +### License Compliance +- Identify license types and restrictions +- Check for license conflicts and incompatibilities +- Assess commercial usage implications +- Flag potentially problematic licenses +- Suggest license-compatible alternatives + +### Supply Chain Security +- Verify package integrity and signatures +- Check for typosquatting and malicious packages +- Analyze dependency tree for attack vectors +- Assess maintainer reputation and trust +- Monitor for suspicious package updates + + + +## Security Scanning Features for AI Agents + +### Real-time Vulnerability Detection +- Scans packages when agents suggest installation +- Checks multiple security databases +- Provides immediate feedback on security risks +- Suggests secure alternatives for agents + +### License Compliance Analysis +- Identifies license types and restrictions +- Flags potentially problematic licenses +- Suggests license-compatible alternatives +- Provides legal risk assessment for agent decisions + +### Supply Chain Security +- Verifies package integrity +- Detects typosquatting attempts +- Monitors for suspicious updates +- Assesses maintainer reputation + +## AI Agent Security Guidelines + +### When Recommending Dependencies +1. **Always check security first** - Scan before suggesting any package +2. **Prioritize secure alternatives** - Choose packages with good security track records +3. **Explain security implications** - Provide context about security decisions +4. **Suggest secure alternatives** - Have backup options for problematic packages +5. **Monitor for updates** - Keep track of security patches and updates + +### Response to Security Issues +- **Critical vulnerabilities**: Immediately suggest alternatives +- **High-risk packages**: Explain risks and suggest safer options +- **License issues**: Consider legal implications and suggest compatible alternatives +- **Supply chain risks**: Verify package integrity and maintainer reputation + +### Agent Learning and Improvement +- Track security-related recommendations +- Learn from security scan feedback +- Build knowledge of secure package alternatives +- Improve recommendation quality over time + +## Integration with Agent Workflows + +### Pre-Installation Security Check +```javascript +// Agent workflow example +async function suggestPackage(packageName) { + // Perform security scan before suggesting + const securityResult = await securityScan(packageName); + + if (securityResult.riskLevel === 'CRITICAL') { + return { + recommendation: 'DO NOT install', + reason: 'Critical security vulnerabilities detected', + alternatives: ['secure-alternative-1', 'secure-alternative-2'] + }; + } + + return { + recommendation: 'Safe to install', + securityScore: securityResult.riskScore, + notes: securityResult.recommendations + }; +} +``` + +### Agent Decision Making +- Use security scores to prioritize recommendations +- Consider security implications in package selection +- Provide security context in explanations +- Suggest security best practices + +## Security Best Practices for AI Agents + +1. **Always scan before suggesting** - Check security status before recommending packages +2. **Prioritize security over convenience** - Choose secure packages even if less convenient +3. **Explain security decisions** - Provide context about why certain packages are recommended +4. **Suggest secure alternatives** - Always have backup options for problematic packages +5. **Monitor for updates** - Keep track of security patches and updates +6. **Document security decisions** - Record why certain packages were chosen despite risks + +## Response to Security Issues + +### Critical Vulnerabilities +- Immediately suggest alternatives +- Explain why the package is dangerous +- Provide secure replacement options +- Consider the specific use case requirements + +### High-Risk Dependencies +- Explain the risks involved +- Suggest safer alternatives +- Provide migration guidance if needed +- Consider the urgency of the requirement + +### Medium-Risk Dependencies +- Explain the security implications +- Suggest monitoring strategies +- Provide update recommendations +- Consider the specific use case + +Remember: AI agents must prioritize security when suggesting dependencies! πŸ”’πŸ›‘οΈβœ¨ \ No newline at end of file diff --git a/.claude/rules/standards/cloudflare-workers-auto.md b/.claude/rules/standards/cloudflare-workers-auto.md new file mode 100644 index 0000000..f98b581 --- /dev/null +++ b/.claude/rules/standards/cloudflare-workers-auto.md @@ -0,0 +1,393 @@ +# Cloudflare Workers development standards and best practices + +## Description +Cloudflare Workers development standards and best practices + +## Applicability +- **Files:** `*.worker.{js,ts},**/workers/**/*.{js,ts},**/src/index.{js,ts},wrangler.{json,jsonc,toml}` +- **Always Apply:** false + +## Rules +- Workers MUST use TypeScript by default unless JavaScript is specifically requested +- Workers MUST use ES modules format exclusively (NEVER use Service Worker format) +- Workers MUST use the modern `export default` pattern instead of `addEventListener` +- Configuration MUST use `wrangler.jsonc` (not `wrangler.toml`) +- Workers MUST import all methods, classes and types used in the code +- Workers MUST keep all code in a single file unless otherwise specified +- Workers MUST use official SDKs when available for external services +- Workers MUST never bake secrets into the code +- Workers MUST implement proper error handling and logging +- Workers MUST use appropriate Cloudflare integrations for data storage +- Workers MUST follow security best practices and input validation +- Workers MUST use WebSocket Hibernation API for Durable Objects WebSockets + +### cloudflare-workers-modern-pattern + +Enforce modern export default pattern over legacy addEventListener + +**Actions:** + - type: suggest + message: | + Use modern export default pattern instead of legacy addEventListener: + ```typescript + export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + return new Response('Hello World!', { status: 200 }); + } + }; + ``` +examples: + - input: | + addEventListener('fetch', event => { + event.respondWith(handleRequest(event.request)); + }); + output: | + export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + return handleRequest(request); + } + }; +metadata: + +### cloudflare-workers-typescript-types + +Ensure proper TypeScript types and interfaces are used + +**Actions:** + - type: validate + conditions: + - pattern: "async fetch\\([^)]*\\)\\s*:" + message: | + Define proper TypeScript types for fetch handler: + ```typescript + interface Env { + // Define your environment bindings here + MY_KV: KVNamespace; + MY_D1: D1Database; + } + + export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + // Your code here + } + }; + ``` +examples: + - input: | + export default { + async fetch(request, env, ctx) { + return new Response('Hello'); + } + }; + output: | + interface Env { + // Define your environment bindings here + } + + export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + return new Response('Hello', { status: 200 }); + } + }; +metadata: + +### cloudflare-workers-wrangler-config + +Enforce wrangler.jsonc configuration best practices + +**Actions:** + - type: suggest + conditions: + - pattern: "\\.toml$" + message: | + Use wrangler.jsonc instead of wrangler.toml: + ```jsonc + { + "name": "my-worker", + "main": "src/index.ts", + "compatibility_date": "2025-02-11", + "compatibility_flags": ["nodejs_compat"], + "observability": { + "enabled": true + } + } + ``` + - type: validate + conditions: + - pattern: "compatibility_date.*2024" + message: "Update compatibility_date to current date (2025-02-11 or later)" + - pattern: "(?!.*nodejs_compat)" + message: "Include nodejs_compat in compatibility_flags" + - pattern: "(?!.*observability)" + message: "Enable observability for logging" +examples: + - input: | + # wrangler.toml + name = "my-worker" + main = "src/index.js" + output: | + // wrangler.jsonc + { + "name": "my-worker", + "main": "src/index.ts", + "compatibility_date": "2025-02-11", + "compatibility_flags": ["nodejs_compat"], + "observability": { + "enabled": true + } + } +metadata: + +### cloudflare-workers-response-patterns + +Enforce proper Response object patterns + +**Actions:** + - type: validate + conditions: + - pattern: "new Response\\([^)]*\\)(?![\\s\\S]*status\\s*:)" + message: | + Always include explicit status codes in Response objects: + ```typescript + return new Response('Success', { status: 200 }); + return new Response('Not Found', { status: 404 }); + return new Response('Internal Server Error', { status: 500 }); + ``` + - type: suggest + conditions: + - pattern: "throw new Error" + message: | + Return proper error responses instead of throwing: + ```typescript + // Bad + throw new Error('Something went wrong'); + + // Good + return new Response('Internal Server Error', { status: 500 }); + ``` +examples: + - input: | + return new Response('Hello'); + output: | + return new Response('Hello', { + status: 200, + headers: { 'Content-Type': 'text/plain' } + }); +metadata: + +### cloudflare-workers-url-handling + +Enforce proper URL parsing and handling + +**Actions:** + - type: validate + conditions: + - pattern: "request\\.url(?![\\s\\S]*new URL\\()" + message: | + Parse URLs properly using URL constructor: + ```typescript + const url = new URL(request.url); + const pathname = url.pathname; + const searchParams = url.searchParams; + ``` +examples: + - input: | + const path = request.url.split('?')[0]; + output: | + const url = new URL(request.url); + const pathname = url.pathname; + const searchParams = url.searchParams; +metadata: + +### cloudflare-workers-websocket-hibernation + +Enforce WebSocket Hibernation API for Durable Objects + +**Actions:** + - type: validate + conditions: + - pattern: "server\\.accept\\(\\)" + message: | + Use WebSocket Hibernation API instead of legacy WebSocket API: + ```typescript + // Bad + server.accept(); + + // Good + this.ctx.acceptWebSocket(server); + ``` + - type: suggest + conditions: + - pattern: "class.*DurableObject" + message: | + Implement webSocketMessage handler for WebSocket Hibernation: + ```typescript + class MyDurableObject { + async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer) { + // Handle WebSocket messages here + } + } + ``` +examples: + - input: | + server.accept(); + output: | + this.ctx.acceptWebSocket(server); +metadata: + +### cloudflare-workers-security-headers + +Enforce security best practices and headers + +**Actions:** + - type: suggest + conditions: + - pattern: "new Response\\([^)]*\\)(?![\\s\\S]*headers)" + message: | + Consider adding security headers: + ```typescript + return new Response('Hello', { + status: 200, + headers: { + 'Content-Type': 'text/plain', + 'X-Content-Type-Options': 'nosniff', + 'X-Frame-Options': 'DENY', + 'X-XSS-Protection': '1; mode=block' + } + }); + ``` +examples: + - input: | + return new Response('Hello', { status: 200 }); + output: | + return new Response('Hello', { + status: 200, + headers: { + 'Content-Type': 'text/plain', + 'X-Content-Type-Options': 'nosniff', + 'X-Frame-Options': 'DENY' + } + }); +metadata: + +### cloudflare-workers-imports + +Enforce proper imports for Cloudflare services + +**Actions:** + - type: validate + conditions: + - pattern: "puppeteer" + message: | + Use official Cloudflare Puppeteer package: + ```typescript + import puppeteer from "@cloudflare/puppeteer"; + ``` +examples: + - input: | + import puppeteer from "puppeteer"; + output: | + import puppeteer from "@cloudflare/puppeteer"; +metadata: + +## Additional Information +# Cloudflare Workers Development Standards + +Enforces best practices for developing Cloudflare Workers including proper configuration, modern patterns, security, and performance optimization based on official Cloudflare documentation. + + + + + + + + + + + + + + + + + + +## Cloudflare Service Integration Guidelines + +### Data Storage Services +- **Workers KV**: Key-value storage for configuration, user profiles, A/B testing +- **Durable Objects**: Strongly consistent state, multiplayer coordination, agent use-cases +- **D1**: Relational data with SQL dialect +- **R2**: Object storage for structured data, AI assets, images, uploads +- **Hyperdrive**: Connect to existing PostgreSQL databases +- **Queues**: Asynchronous processing and background tasks +- **Vectorize**: Embeddings and vector search (with Workers AI) +- **Analytics Engine**: User events, billing, metrics, analytics +- **Workers AI**: Default AI API for inference requests + +### Configuration Template +```jsonc +{ + "name": "my-worker", + "main": "src/index.ts", + "compatibility_date": "2025-02-11", + "compatibility_flags": ["nodejs_compat"], + "observability": { + "enabled": true + }, + "vars": { + "ENVIRONMENT": "production" + }, + "kv_namespaces": [ + { + "binding": "MY_KV", + "id": "your-kv-namespace-id" + } + ] +} +``` + +tests: + - input: | + addEventListener('fetch', event => { + event.respondWith(new Response('Hello')); + }); + output: | + export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + return new Response('Hello', { status: 200 }); + } + }; + + - input: | + export default { + async fetch(request, env, ctx) { + const url = request.url; + return new Response('Hello'); + } + }; + output: | + interface Env { + // Define your environment bindings here + } + + export default { + async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + const url = new URL(request.url); + return new Response('Hello', { status: 200 }); + } + }; + + - input: | + server.accept(); + output: | + this.ctx.acceptWebSocket(server); + + - input: | + throw new Error('Failed to process'); + output: | + return new Response('Internal Server Error', { status: 500 }); +description: +globs: +alwaysApply: false +--- \ No newline at end of file diff --git a/.claude/rules/standards/cloudflare-workers-hono-auto.md b/.claude/rules/standards/cloudflare-workers-hono-auto.md new file mode 100644 index 0000000..31b8eb7 --- /dev/null +++ b/.claude/rules/standards/cloudflare-workers-hono-auto.md @@ -0,0 +1,473 @@ +# Cloudflare Workers with Hono framework development standards and best practices + +## Description +Cloudflare Workers with Hono framework development standards and best practices + +## Applicability +- **Files:** `*.worker.{js,ts},**/workers/**/*.{js,ts},**/src/**/*.{js,ts},wrangler.{json,jsonc}` +- **Always Apply:** false + +## Rules +- Workers MUST use Hono framework for routing and middleware +- Workers MUST avoid creating "Ruby on Rails-like Controllers" when possible +- Workers MUST write handlers directly after path definitions for proper type inference +- Workers MUST use `app.route()` for larger applications instead of controllers +- Workers MUST use `factory.createHandlers()` if controller-like patterns are needed +- Workers MUST use proper TypeScript types with Hono Context +- Workers MUST separate route files for different endpoints in larger applications +- Workers MUST use proper Hono middleware patterns +- Workers MUST integrate properly with Cloudflare Workers environment bindings +- Workers MUST use wrangler.jsonc configuration with Hono setup + +### hono-no-controllers + +Enforce direct handler patterns instead of Rails-like controllers + +**Actions:** + - type: suggest + conditions: + - pattern: "const\\s+\\w+\\s*=\\s*\\(c:\\s*Context\\)\\s*=>.*app\\.(get|post|put|delete|patch)\\([^,]*,\\s*\\w+\\)" + message: | + Avoid Rails-like controllers. Write handlers directly for better type inference: + ```typescript + // πŸ™ Don't do this + const booksList = (c: Context) => { + return c.json('list books') + } + app.get('/books', booksList) + + // πŸ˜ƒ Do this instead + app.get('/books', (c) => { + return c.json('list books') + }) + ``` +examples: + - input: | + const booksList = (c: Context) => { + return c.json('list books') + } + app.get('/books', booksList) + output: | + app.get('/books', (c) => { + return c.json('list books') + }) +metadata: + +### hono-path-param-inference + +Ensure proper path parameter type inference + +**Actions:** + - type: suggest + conditions: + - pattern: "const\\s+\\w+\\s*=\\s*\\(c:\\s*Context\\)\\s*=>.*c\\.req\\.param\\(" + message: | + Use inline handlers for proper path parameter inference: + ```typescript + // πŸ™ Can't infer path params in controller + const bookPermalink = (c: Context) => { + const id = c.req.param('id') // Can't infer the path param + return c.json(`get ${id}`) + } + + // πŸ˜ƒ Proper type inference + app.get('/books/:id', (c) => { + const id = c.req.param('id') // Can infer the path param + return c.json(`get ${id}`) + }) + ``` +examples: + - input: | + const bookPermalink = (c: Context) => { + const id = c.req.param('id') + return c.json(`get ${id}`) + } + app.get('/books/:id', bookPermalink) + output: | + app.get('/books/:id', (c) => { + const id = c.req.param('id') + return c.json(`get ${id}`) + }) +metadata: + +### hono-factory-pattern + +Use factory.createHandlers() when controller patterns are needed + +**Actions:** + - type: suggest + conditions: + - pattern: "from\\s+['\"]hono['\"].*createFactory" + message: | + Import createFactory from 'hono/factory': + ```typescript + import { createFactory } from 'hono/factory' + + const factory = createFactory() + + const handlers = factory.createHandlers(middleware, (c) => { + return c.json(c.var.foo) + }) + + app.get('/api', ...handlers) + ``` +examples: + - input: | + import { createFactory } from 'hono' + output: | + import { createFactory } from 'hono/factory' +metadata: + +### hono-app-structure + +Enforce proper app structure for larger applications + +**Actions:** + - type: suggest + conditions: + - pattern: "new Hono\\(\\)" + message: | + For larger applications, create separate route files: + ```typescript + // authors.ts + import { Hono } from 'hono' + + const app = new Hono() + + app.get('/', (c) => c.json('list authors')) + app.post('/', (c) => c.json('create an author', 201)) + app.get('/:id', (c) => c.json(`get ${c.req.param('id')}`)) + + export default app + + // index.ts + import { Hono } from 'hono' + import authors from './authors' + import books from './books' + + const app = new Hono() + + app.route('/authors', authors) + app.route('/books', books) + + export default app + ``` +examples: + - input: | + const app = new Hono() + app.get('/authors', (c) => c.json('list authors')) + app.get('/books', (c) => c.json('list books')) + output: | + // Separate into authors.ts and books.ts files + import authors from './authors' + import books from './books' + + const app = new Hono() + app.route('/authors', authors) + app.route('/books', books) +metadata: + +### hono-cloudflare-workers-integration + +Ensure proper integration with Cloudflare Workers environment + +**Actions:** + - type: validate + conditions: + - pattern: "new Hono\\(\\)(?![\\s\\S]*<.*Env.*>)" + message: | + Define proper TypeScript types for Cloudflare Workers environment: + ```typescript + interface Env { + MY_KV: KVNamespace; + MY_D1: D1Database; + MY_VAR: string; + } + + const app = new Hono<{ Bindings: Env }>() + + app.get('/api', (c) => { + const kv = c.env.MY_KV // Properly typed + return c.json({ success: true }) + }) + + export default app + ``` +examples: + - input: | + const app = new Hono() + + app.get('/api', (c) => { + const kv = c.env.MY_KV + return c.json({ success: true }) + }) + output: | + interface Env { + MY_KV: KVNamespace; + } + + const app = new Hono<{ Bindings: Env }>() + + app.get('/api', (c) => { + const kv = c.env.MY_KV + return c.json({ success: true }) + }) +metadata: + +### hono-middleware-patterns + +Enforce proper Hono middleware usage patterns + +**Actions:** + - type: suggest + conditions: + - pattern: "app\\.use\\(" + message: | + Use proper middleware patterns with Hono: + ```typescript + import { logger } from 'hono/logger' + import { cors } from 'hono/cors' + import { secureHeaders } from 'hono/secure-headers' + + const app = new Hono<{ Bindings: Env }>() + + // Global middleware + app.use('*', logger()) + app.use('*', secureHeaders()) + app.use('/api/*', cors()) + + // Route-specific middleware + app.use('/admin/*', async (c, next) => { + // Authentication middleware + await next() + }) + ``` +examples: + - input: | + app.use((c, next) => { + console.log('Request received') + return next() + }) + output: | + import { logger } from 'hono/logger' + + app.use('*', logger()) + app.use('*', async (c, next) => { + console.log('Request received') + await next() + }) +metadata: + +### hono-error-handling + +Enforce proper error handling patterns with Hono + +**Actions:** + - type: suggest + conditions: + - pattern: "throw new Error" + message: | + Use proper error responses with Hono: + ```typescript + // πŸ™ Don't throw errors + throw new Error('Something went wrong') + + // πŸ˜ƒ Return proper error responses + return c.json({ error: 'Something went wrong' }, 500) + + // Or use Hono's HTTPException + import { HTTPException } from 'hono/http-exception' + + app.onError((err, c) => { + if (err instanceof HTTPException) { + return c.json({ error: err.message }, err.status) + } + return c.json({ error: 'Internal Server Error' }, 500) + }) + ``` +examples: + - input: | + if (error) { + throw new Error('Failed to process') + } + output: | + if (error) { + return c.json({ error: 'Failed to process' }, 500) + } +metadata: + +### hono-wrangler-config + +Ensure proper wrangler.jsonc configuration for Hono projects + +**Actions:** + - type: suggest + conditions: + - pattern: "\\{" + message: | + Proper wrangler.jsonc configuration for Hono: + ```jsonc + { + "name": "my-hono-worker", + "main": "src/index.ts", + "compatibility_date": "2025-02-11", + "compatibility_flags": ["nodejs_compat"], + "observability": { + "enabled": true + }, + "vars": { + "ENVIRONMENT": "production" + }, + "kv_namespaces": [ + { + "binding": "MY_KV", + "id": "your-kv-namespace-id" + } + ] + } + ``` +examples: + - input: | + { + "name": "worker" + } + output: | + { + "name": "my-hono-worker", + "main": "src/index.ts", + "compatibility_date": "2025-02-11", + "compatibility_flags": ["nodejs_compat"], + "observability": { + "enabled": true + } + } +metadata: + +## Additional Information +# Cloudflare Workers with Hono Best Practices + +Enforces best practices for developing Cloudflare Workers using the Hono framework, including proper routing patterns, application structure, and TypeScript usage. + + + + + + + + + + + + + + + + + + +## Hono Framework Integration Guidelines + +### Project Structure for Larger Applications +``` +src/ +β”œβ”€β”€ index.ts # Main entry point +β”œβ”€β”€ routes/ +β”‚ β”œβ”€β”€ authors.ts # Author routes +β”‚ β”œβ”€β”€ books.ts # Book routes +β”‚ └── admin.ts # Admin routes +β”œβ”€β”€ middleware/ +β”‚ β”œβ”€β”€ auth.ts # Authentication middleware +β”‚ └── cors.ts # CORS middleware +└── types/ + └── env.ts # Environment type definitions +``` + +### Recommended Hono Middleware +```typescript +import { logger } from 'hono/logger' +import { cors } from 'hono/cors' +import { secureHeaders } from 'hono/secure-headers' +import { prettyJSON } from 'hono/pretty-json' +import { timing } from 'hono/timing' +``` + +### Environment Types Template +```typescript +interface Env { + // KV Namespaces + MY_KV: KVNamespace; + + // D1 Databases + MY_D1: D1Database; + + // R2 Buckets + MY_R2: R2Bucket; + + // Environment Variables + API_KEY: string; + ENVIRONMENT: string; +} + +const app = new Hono<{ Bindings: Env }>() +``` + +### Route File Template +```typescript +// routes/books.ts +import { Hono } from 'hono' + +type Bindings = { + MY_KV: KVNamespace; +} + +const app = new Hono<{ Bindings: Bindings }>() + +app.get('/', (c) => c.json('list books')) +app.post('/', (c) => c.json('create a book', 201)) +app.get('/:id', (c) => c.json(`get ${c.req.param('id')}`)) + +export default app +``` + +tests: + - input: | + const booksList = (c: Context) => { + return c.json('list books') + } + app.get('/books', booksList) + output: | + app.get('/books', (c) => { + return c.json('list books') + }) + + - input: | + const app = new Hono() + output: | + interface Env { + // Define your bindings here + } + + const app = new Hono<{ Bindings: Env }>() + + - input: | + throw new Error('Failed to process') + output: | + return c.json({ error: 'Failed to process' }, 500) + + - input: | + import { createFactory } from 'hono' + output: | + import { createFactory } from 'hono/factory' + + - input: | + app.get('/authors', (c) => c.json('list authors')) + app.get('/books', (c) => c.json('list books')) + output: | + // Separate into route files + import authors from './routes/authors' + import books from './routes/books' + + app.route('/authors', authors) + app.route('/books', books) + + \ No newline at end of file diff --git a/.claude/rules/standards/laravel-php-auto.md b/.claude/rules/standards/laravel-php-auto.md new file mode 100644 index 0000000..818c5b0 --- /dev/null +++ b/.claude/rules/standards/laravel-php-auto.md @@ -0,0 +1,322 @@ +# Laravel and PHP Development Standards + +## Description +Laravel and PHP Development Standards + +## Applicability +- **Files:** `**/*.{php}` +- **Always Apply:** false + +## Rules +- Follow Laravel naming conventions for controllers, models, and other components +- Use Laravel's built-in features rather than reinventing functionality +- Structure code according to Laravel's MVC architecture +- Adhere to Laravel's folder structure +- Implement proper validation and error handling +- Follow RESTful design principles for API development +- Use Laravel's Eloquent ORM for database interactions +- Implement proper security measures against common web vulnerabilities + +## Additional Information +# Laravel and PHP Development Standards + +This rule enforces best practices, coding standards, and architectural patterns for Laravel and PHP development. + + +## Laravel Naming Conventions + +### Controllers + +- Use singular PascalCase + "Controller" suffix (e.g., `UserController`) +- RESTful action names: index, create, store, show, edit, update, destroy + +### Models + +- Use singular PascalCase (e.g., `User`, `Product`) +- Model properties and relationships should use camelCase + +### Migrations + +- Use descriptive names with timestamps (e.g., `2023_01_01_000000_create_users_table`) +- Table names should be plural snake_case + +### Routes + +- Use plural kebab-case for resource routes (e.g., `/api/user-profiles`) +- Group related routes using namespaces and middlewares + +## PHP Code Style + +- Follow PSR-12 coding standard for PHP code structure +- Use strict typing +- Use type declarations for method parameters and return types +- Prefer explicit visibility declarations (public, protected, private) +- Use null coalescing operators and other modern PHP features + + +name: laravel-php-standards +description: Standards and best practices for Laravel and PHP development +version: 1.0 +severity: suggestion +filters: + - type: file_extension + pattern: "\\.php$" + - type: content + pattern: "(namespace|class|function|Route::)" +actions: + - type: suggest + message: | + Ensure your Laravel and PHP code follows these best practices: + 1. Follow Laravel naming conventions + 2. Use Laravel's built-in features instead of custom solutions + 3. Structure code according to MVC architecture + 4. Implement proper validation and error handling + 5. Follow PSR-12 coding standards + +examples: + - description: "Proper Laravel controller implementation" + input: | + name = $request->name; + $user->email = $request->email; + $user->save(); + + return $user; + } + } + output: | + json($users); + } + + public function store(StoreUserRequest $request) + { + // Validation handled via FormRequest + $user = User::create($request->validated()); + return response()->json($user, 201); + } + } + + - description: "Proper Laravel model implementation" + input: | + belongsTo('App\Models\User'); + } + + function get_comments() { + return $this->hasMany('App\Models\Comment'); + } + } + output: | + belongsTo(User::class, 'user_id'); + } + + /** + * Get the comments for the post. + */ + public function comments(): HasMany + { + return $this->hasMany(Comment::class); + } + } + + - description: "Proper Laravel route definition" + input: | + only([ + // 'index', 'store', 'show', 'update', 'destroy' + // ]); + +tests: + - input: | + hasMany('App\Models\OrderItem'); + } + } + output: "Suggest renaming model to singular Order, adding type hints, and renaming relationship method to items" + + - input: | + validate([ + 'name' => 'required|string|max:255', + 'email' => 'required|email|unique:users', + 'password' => 'required|min:8', + ]); + + $user = User::create($validated); + + return response()->json($user, 201); + } + } + output: "Good Laravel controller implementation following conventions" + +metadata: + priority: high + version: 1.0 + +## Laravel Architecture Best Practices + +### Service Layer +- Use service classes for complex business logic +- Keep controllers thin and focused on HTTP concerns +- Inject dependencies via constructor or method injection + +### Repository Pattern +- Consider using repositories for database abstraction when needed +- Avoid bypassing Eloquent with raw queries unless necessary +- Repository interfaces should be defined in a contracts namespace + +### Form Requests +- Use Form Request classes for validation logic +- Group related validation rules in dedicated request classes +- Add authorization logic to form requests when appropriate + +### API Resources +- Use API Resources for response transformations +- Create dedicated resource classes for complex transformations +- Consider using resource collections for pagination and metadata + +## Security Considerations + +- Always validate user input +- Always suggest using Laravel's built-in features instead of custom solutions, for example, use Laravel's authentication system and routing instead of custom solutions +- Implement proper CSRF protection +- Avoid using raw SQL queries to prevent SQL injection +- Set proper HTTP headers for security +- Use Laravel's encryption and hashing features +- Implement proper role and permission management + +## Performance Optimization + +- Use eager loading to avoid N+1 query problems +- Cache frequently accessed data +- Use Laravel's query builder effectively +- Implement pagination for large datasets +- Use queues for long-running tasks \ No newline at end of file diff --git a/.claude/rules/standards/mysql-auto.md b/.claude/rules/standards/mysql-auto.md new file mode 100644 index 0000000..e3a2825 --- /dev/null +++ b/.claude/rules/standards/mysql-auto.md @@ -0,0 +1,160 @@ +# This rule enforces MySQL-specific best practices to enhance readability, performance, security, and maintainability + +## Description +This rule enforces MySQL-specific best practices to enhance readability, performance, security, and maintainability. It targets MySQL features (e.g., storage engines, character sets) and common pitfalls, and adds concrete guidance for schema design and creation. + +## Applicability +- **Files:** `*.sql` +- **Always Apply:** false + +## Rules +- **Naming Conventions**: Use descriptive, snake_case names for databases, tables, columns, indexes, and constraints (e.g., `user_profiles`, `fk_user_profiles_user_id`). Avoid abbreviations and reserved keywords; if unavoidable, use backticks (e.g., `` `order` ``). +- **SELECT Specificity**: Avoid `SELECT *`. Always specify required columns. +- **Security**: Prefer parameterized queries (driver-level). Do not build SQL via string concatenation. Use prepared statements to prevent SQL injection. +- **Performance**: Index columns used in JOIN and WHERE predicates. Prefer `INNER JOIN` over correlated subqueries when possible. +- **Engine/Charset**: Use `ENGINE=InnoDB` for transactional tables and set `DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci` (or `utf8mb4_0900_ai_ci` on MySQL 8.0+). +- **Transactions**: Group related writes in transactions. Avoid implicit autocommit for multi-statement operations. +- **Data Types**: Use precise types (`INT UNSIGNED` for identifiers, `DECIMAL(precision,scale)` for money). Avoid `TEXT`/`LONGTEXT` unless necessary. Prefer `BOOLEAN` (TINYINT(1)) for flags. +- **Timestamps**: Use `TIMESTAMP`/`DATETIME` with `DEFAULT CURRENT_TIMESTAMP` and `ON UPDATE CURRENT_TIMESTAMP` where appropriate. +- **Joins**: Use explicit `JOIN` syntax; avoid implicit comma joins. +- Keep migrations idempotent and forward-only; include rollback plans where feasible. + +## Additional Information +# MySQL Best Practices Auto Rule + + +## Schema Creation + +Design schemas for correctness first, then performance. Apply the following when creating or altering schemas: + +- **Version-Specific Charset/Collation** + + - MySQL 8.0+: Prefer `utf8mb4` with `utf8mb4_0900_ai_ci` (or `_as_cs` for case-sensitive needs). Avoid legacy collations like `utf8_general_ci`. + - MySQL 5.7: Prefer `utf8mb4` with `utf8mb4_unicode_ci`. Avoid `utf8` (3-byte) and `latin1` unless strictly required for legacy data. + - Suggest migration to `utf8`/`latin1` schemas to `utf8mb4` proactively to support full Unicode and emojis. + - If a project already has MySQL setup, keep the collation and charset choices of the project + +- **Table Creation Defaults** + + - Always specify: `ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC` (omit `_0900_` on <8.0). + - Define a primary key; use surrogate keys (`BIGINT UNSIGNED AUTO_INCREMENT`) when natural keys are composite/unwieldy. + - Define `NOT NULL` where appropriate; avoid nullable columns unless required by domain logic. + - Use consistent ID column naming: `id` for primary key, `_id` for foreign keys. + +- **Keys and Constraints** + + - Create foreign keys with `ON DELETE`/`ON UPDATE` actions explicitly (`RESTRICT`, `CASCADE`, or `SET NULL`) aligned to business rules. + - Create supporting indexes for foreign keys and for frequent predicates; use composite indexes with leftmost prefix ordering that matches queries (e.g., `(user_id, created_at)`). + - Name constraints and indexes explicitly: `pk_`, `fk_
_`, `uk_
_`, `idx_
_`. + +- **Column Types** + + - Identifiers: `BIGINT UNSIGNED` (or `INT UNSIGNED` if you are certain about bounds). Foreign keys must match referenced type/unsignedness. + - Monetary: Avoid `FLOAT/DOUBLE` for currency. + - Strings: `VARCHAR(n)` sized to realistic max; avoid `TEXT` unless storing large content. + - Booleans: `TINYINT(1)` with `CHECK (col IN (0,1))` on 8.0+. + +- **Temporal Columns** + + - Use `created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP`. + - Use `updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`. + - Store times in UTC; handle localization at the application layer. + +### Example: Recommended Table Definition + +```sql +CREATE TABLE `users` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + `email` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NOT NULL, + `status` TINYINT(1) NOT NULL DEFAULT 1, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `pk_users` PRIMARY KEY (`id`), + CONSTRAINT `uk_users_email` UNIQUE KEY (`email`), + INDEX `idx_users_status_created_at` (`status`, `created_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC; +``` + +### Example: Foreign Key With Index and Action + +```sql +CREATE TABLE `orders` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` BIGINT UNSIGNED NOT NULL, + `total_cents` DECIMAL(19,4) NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT `pk_orders` PRIMARY KEY (`id`), + CONSTRAINT `fk_orders_user_id` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE, + INDEX `idx_orders_user_id_created_at` (`user_id`, `created_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +``` + +## Migration Scripts + +Design and execute migrations to be safe, repeatable, and observable: + +- Idempotency and Ordering + + - Use timestamped, ordered filenames (e.g., `20250922_1200_add_users_table.sql`). + - Write scripts so re-running is safe: `CREATE TABLE IF NOT EXISTS`, `ADD COLUMN IF NOT EXISTS`, `DROP COLUMN IF EXISTS` on MySQL 8.0+. + - Record applied migrations in a migrations table (version, checksum, applied_at, success). + +- Transactionality and Locking + + - Wrap related DDL/DML in transactions where supported. Note: some DDL is non-transactional; plan for partial failure. + - Avoid long metadata locks; prefer online DDL with `ALGORITHM=INPLACE`/`INSTANT` and `LOCK=NONE` when available (MySQL 8.0+). + +- Backwards-Compatible, Zero/Low-Downtime Strategy + + - Avoid destructive changes in one step. Use expand-and-contract: + - Add nullable column β†’ backfill in batches β†’ set default β†’ enforce `NOT NULL`. + - Add new index concurrently; switch reads/writes; drop old index later. + - For large tables, use online schema change tools like gh-ost or pt-online-schema-change. + - Batch backfills (e.g., `UPDATE ... LIMIT 1000` with keyset pagination) with sleeps to reduce load. + +- Data Safety and Rollback + + - Take backups or snapshots before risky changes; verify restore procedures. + - Provide rollback scripts or compensating changes when possible. + - Validate with `EXPLAIN` and compare plans before/after. + +- Environment Discipline + - Test migrations in staging with production-like data volumes. + - Gate production runs behind approvals and maintenance windows when needed. + - Emit logs/metrics; fail fast on errors; ensure scripts are non-interactive. + +### Example: Safe Add NOT NULL Column + +```sql +-- 1) Add column nullable +ALTER TABLE `users` + ADD COLUMN `country_code` VARCHAR(2) NULL; + +-- 2) Backfill in batches +UPDATE `users` + SET `country_code` = 'US' + WHERE `country_code` IS NULL + ORDER BY `id` + LIMIT 1000; +-- Repeat step 2 until no rows remain + +-- 3) Set default +ALTER TABLE `users` + ALTER `country_code` SET DEFAULT 'US'; + +-- 4) Enforce NOT NULL +ALTER TABLE `users` + MODIFY `country_code` VARCHAR(2) NOT NULL DEFAULT 'US'; +``` + +### References + +- [MySQL 8.0 Reference Manual β€” Character Sets and Collations](https://dev.mysql.com/doc/refman/8.0/en/charset.html) +- [MySQL 8.0 Reference Manual β€” InnoDB Storage Engine](https://dev.mysql.com/doc/refman/8.0/en/innodb-storage-engine.html) +- [MySQL 8.0 Reference Manual β€” CREATE TABLE Syntax](https://dev.mysql.com/doc/refman/8.0/en/create-table.html) +- [MySQL 8.0 Reference Manual β€” Data Types](https://dev.mysql.com/doc/refman/8.0/en/data-types.html) +- [MySQL 8.0 Reference Manual β€” SQL Modes](https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html) +- [MySQL 8.0 Reference Manual β€” EXPLAIN Output](https://dev.mysql.com/doc/refman/8.0/en/explain-output.html) +- [MySQL 8.0 Reference Manual β€” Online DDL](https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html) +- [OWASP β€” SQL Injection Prevention Cheat Sheet](https://owasp.org/www-project-cheat-sheets/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html) \ No newline at end of file diff --git a/.claude/rules/standards/nextjs-react19-auto.md b/.claude/rules/standards/nextjs-react19-auto.md new file mode 100644 index 0000000..da2103b --- /dev/null +++ b/.claude/rules/standards/nextjs-react19-auto.md @@ -0,0 +1,61 @@ +# This rule enforces Next + +## Description +This rule enforces Next.js best practices for React 19 with TypeScript. + +## Applicability +- **Files:** `*.tsx, *.ts, *.jsx, *.js` +- **Always Apply:** true + +## Additional Information +# Critical Rules + +- Adapt approach to app router or page router project structure +- Implement proper error boundaries + +- Use the App Router structure with `page.tsx` files in route directories. +- Client components must be explicitly marked with `'use client'` at the top of the file. +- Use kebab-case for directory names (e.g., `components/auth-form`) and PascalCase for component files. + + +## Project Structure + + - Both the /app and /components folders under a /src directory. + +## State Management + +- Use `getServerSideProps` for server-side data fetching +- Use `getStaticProps` for static data fetching +- Use `getStaticPaths` for static path generation +- Use `useActionState` instead of deprecated `useFormState` +- Leverage enhanced `useFormStatus` with new properties (data, method, action) +- Avoid unnecessary `useState`,`setState`, `useEffect`, and `useCallback` when possible: + - Use server actions for server-side state management and form handling, + - Use server components for data fetching, + - Use URL search params for shareable state + +## Async Request APIs + +- Always use async versions of runtime APIs +- Handle async params in layouts/pages + +## Data Fetching + +- Use appropriate fetching methods (Server Components, SWR, React Query, etc.) +- Use API Routes inside route directories for server-side data fetching (ie. `app/api/users/route.ts` for `/api/users`) +- Use Suspense for async operations + +Remind user of default caching behavior in Next.js when using API routes or fetching data from external APIs. + +## Routing + +- Use the App Router conventions +- Implement proper loading and error states for routes +- Use dynamic routes appropriately (ie. when a user can be identified by a unique id, or a blog post has a unique slug) +- Handle parallel routes when needed + +## Components + +Remind the developer: +- Importing a server component into a 'use client' file makes it a client component. +- Passing a server component as a child to a client component keeps it as a server component, retaining SSR benefits. \ No newline at end of file diff --git a/.claude/rules/standards/react-typescript-auto.md b/.claude/rules/standards/react-typescript-auto.md new file mode 100644 index 0000000..f4dbbd0 --- /dev/null +++ b/.claude/rules/standards/react-typescript-auto.md @@ -0,0 +1,77 @@ +# This rule enforces best practices for building React 18+ applications with TypeScript, ensuring type safety, maintainability, and consistency + +## Description +This rule enforces best practices for building React 18+ applications with TypeScript, ensuring type safety, maintainability, and consistency. + +## Applicability +- **Files:** `"*.ts,*.tsx"` +- **Always Apply:** false + +## Rules +- All React components MUST be defined as functional components using `const` and arrow functions – except for Error Boundaries. +- ALWAYS define explicit types or interfaces for component props and state. +- EVERY element in a list rendered by `map()` MUST have a unique `key` prop. +- Hooks (`useState`, `useEffect`, `useContext`, etc.) MUST only be called at the top level of a functional component or custom hook. +- Component filenames MUST use PascalCase (e.g., `MyComponent.tsx`). +- Prefix custom hooks with "use" (ie. "useUserAuth") +- Prefix event handlers with "handle" (ie. "handleClick") +- Prefix boolean values with verbs (ie. isLoading for loading state, or canSubmit for ability to submit) + +## Additional Information +# React and TypeScript Standards + + +## React Hooks + +- Only call hooks at the top level of React function components or custom hooks (never inside loops, conditions, or nested functions). +- Always start custom hook names with `use` (e.g., `useFetchData`). +- Extract reusable logic into custom hooks to avoid duplication. +- Specify all dependencies in hook dependency arrays (e.g., `useEffect`, `useCallback`, `useMemo`). +- Avoid using `any` in hook return types or parameters; always type your hooks. +- Use `useCallback` and `useMemo` to optimize performance only when necessary. +- Document the purpose and expected usage of custom hooks. + +### Best Practices for useEffect + +The `useEffect` hook is used for side effects in functional components, such as data fetching, subscriptions, or manually changing the DOM. To avoid bugs and performance issues, follow these best practices: + +- Always specify all external dependencies in the dependency array. Missing dependencies can cause stale values or unexpected behavior. +- Avoid using `any` in effect callbacks or dependencies. +- Use cleanup functions to prevent memory leaks, especially for subscriptions or timers. +- Prefer splitting effects by purpose rather than combining unrelated logic in a single effect. +- Avoid side effects that synchronously update state in a way that triggers another render loop. +- For async logic, define the async function inside the effect and call it, rather than making the effect callback itself async. + +## State Management Guidance + +Effective state management is crucial for building scalable and maintainable React applications. Choose the right state management approach based on the scope and complexity of your state: + +- Use `useState` for simple, local component state. +- Use `useReducer` for complex local state logic or when state transitions depend on previous state. +- Use React Context for sharing state that is truly global to a subtree (e.g., theme, authentication, user preferences), but avoid using it for frequently changing or large state. +- For large, shared, or highly dynamic state, consider external libraries such as Redux, Zustand, Jotai, or Recoil. +- Always define explicit types for state and actions when using TypeScript. +- Avoid prop drilling by lifting state up only as much as necessary or using context appropriately. + +## When to use React Context + +React Context is ideal for passing data that can be considered "global" for a tree of React components, such as the current authenticated user, theme, or preferred language. It helps avoid "prop drilling" (passing props down through many nested components). + +### Best Practices for Context: + +- Define an explicit type for the context value. +- Create a provider component that manages the context's state and value. +- Use `useContext` hook to consume the context in functional components. +- AVOID using context for highly dynamic or frequently updated state that causes many re-renders across the component tree. For such cases, consider state management libraries like Redux or Zustand. + +## Suspense: + +- Use `` to wrap components that use React.lazy for code-splitting or that rely on data fetching libraries supporting Suspense (e.g., Relay, React Query experimental). +- Provide a meaningful fallback UI (e.g., spinner, skeleton loader) to indicate loading state. +- Avoid wrapping your entire app in a single Suspense; scope it to the smallest subtree that benefits from loading boundaries. + +## Error Boundaries: + +- Use Error Boundaries to catch and display errors in the render phase of React components, preventing the entire app from crashing. +- Place Error Boundaries around critical UI sections (e.g., main content, widgets) to isolate failures. +- Error Boundaries must be class components, but you can wrap them in functional components for convenience. \ No newline at end of file diff --git a/.claude/rules/standards/typescript-standards-auto.md b/.claude/rules/standards/typescript-standards-auto.md new file mode 100644 index 0000000..307ae6a --- /dev/null +++ b/.claude/rules/standards/typescript-standards-auto.md @@ -0,0 +1,107 @@ +# TypeScript development standards and type safety + +## Description +TypeScript development standards and type safety + +## Applicability +- **Files:** `**/*.{ts|tsx}` +- **Always Apply:** false + +## Rules +- Refer to https://www.typescriptlang.org/tsconfig when tsconfig.json values are changed. +- Use strict mode with `"strict": true` in tsconfig.json +- Remind user the limitations of using esModuleInterop and allowSyntheticDefaultImports in tsconfig.json https://www.typescriptlang.org/tsconfig/#Interop_Constraints_6252 +- Explicitly declare types for function parameters and return values +- Avoid using `any` type unless absolutely necessary. Use `unknown` instead. +- Use interfaces for object type definitions +- Use enums for fixed sets of values +- Use type aliases to simplify complex types +- Document APIs with JSDoc comments +- Maintain proper error handling with typed errors +- Use type guards and type narrowing to improve type safety +- Use type literals and unions to define the exact allowed values. +- Use type assertions and annotations when necessary. They are unnecessary if type inference is possible. +- Use type unions and intersections to combine types. +- Export types from modules using the `export type` syntax +- If using an existing library with types, import the types using the `import type` syntax +- Declare types for file extensions that aren't supported by the compiler using the `declare module` syntax +- If using node 23+, use `node --experimental-strip-types` in package.json scripts to strip types when running the code locally +- Use utility types as much as possible to avoid type duplication. + +### typescript-standards + +Standards for TypeScript development and type safety + +**Actions:** + - type: validate + message: | + TypeScript code must follow these conventions: + 1. Use strict mode + 2. Explicit typing + 3. Proper error handling + 4. Documentation + 5. Consistent naming + 6. Proper use of primitives and utility types to reduce duplication and increase type safety + + - type: lint + rules: + - pattern: "any" + message: "Avoid using 'any' type. Define a specific type or interface instead." + - pattern: "Object" + message: "Avoid using 'Object' type. Use a specific interface or type instead." + - pattern: "Function" + message: "Avoid using 'Function' type. Define specific function signature instead." + - pattern: "\\b[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*\\b" + message: "Use PascalCase for type names, interfaces, and classes." + - pattern: "\\b[a-z][a-z0-9]*([A-Z][a-z0-9]+)*\\b" + message: "Use camelCase for variable and function names." + +metadata: + +## Additional Information +# TypeScript Standards + + + + +## Naming Conventions + +### Types and Interfaces +- Use PascalCase for type names and interface names +- Prefix interfaces with 'I' only when required by project convention +- Follow consistent naming conventions + +```typescript +interface UserData { + id: string; + name: string; +} + +type ApiResponse = { + data: T; + status: number; +}; +``` + +### Variables and Functions +- Use camelCase for variable names and function names +- Use PascalCase for class names +- Function signatures should have return types + +### Classes + +- Use PascalCase for class names + +```typescript +const userData: UserData; +function fetchUserData(): Promise; +class UserService {}; +``` + +### Constants +- Use UPPER_SNAKE_CASE for constant values + +```typescript +const MAX_RETRY_ATTEMPTS = 3; +const API_BASE_URL = 'https://api.example.com'; +``` \ No newline at end of file diff --git a/.claude/rules/standards/vue3-typescript-auto.md b/.claude/rules/standards/vue3-typescript-auto.md new file mode 100644 index 0000000..af436c0 --- /dev/null +++ b/.claude/rules/standards/vue3-typescript-auto.md @@ -0,0 +1,332 @@ +# Vue 3 with TypeScript Standards + +## Description +Vue 3 with TypeScript Standards + +## Applicability +- **Files:** `*.vue,*.ts` +- **Always Apply:** false + +## Rules +- Use Composition API with ` + + ❌ Avoid Options API and untyped refs: + const props = defineProps(['title']) + const count = ref(0) +examples: + - input: | + const props = defineProps(['title']) + const model = defineModel() + const count = ref(0) + output: | + interface Props { + title: string + } + const props = defineProps() + const model = defineModel() + const count = ref(0) +metadata: + +### vue3-models + +Proper typing for defineModel() and v-model bindings + +**Actions:** + - type: suggest + message: | + βœ… Type v-model bindings properly: + + // Single v-model + const modelValue = defineModel() + + // Named v-models + const isOpen = defineModel('isOpen') + const selectedId = defineModel('selectedId') + + // Optional v-model with default + const theme = defineModel<'light' | 'dark'>('theme', { default: 'light' }) + + ❌ Avoid untyped models: + const modelValue = defineModel() + const isOpen = defineModel('isOpen') +examples: + - input: | + const modelValue = defineModel() + const isVisible = defineModel('isVisible') + output: | + const modelValue = defineModel() + const isVisible = defineModel('isVisible') +metadata: + +### vue3-slots + +Proper typing for defineSlots() and slot definitions + +**Actions:** + - type: suggest + message: | + βœ… Type slots with proper interfaces: + + // Basic slots + interface Slots { + default(): any + header(): any + footer(): any + } + + // Slots with typed props + interface Slots { + default(props: { user: User; isActive: boolean }): any + item(props: { item: Product; index: number }): any + empty(): any + } + + const slots = defineSlots() + + ❌ Avoid untyped slots: + const slots = defineSlots() +examples: + - input: | + const slots = defineSlots() + output: | + interface Slots { + default(props: { item: any }): any + } + const slots = defineSlots() +metadata: + +### vue3-composables-naming + +Standards for composables and component naming with TypeScript + +**Actions:** + - type: suggest + message: | + βœ… Composable structure: + export interface UseCounterReturn { + count: Ref + increment: () => void + } + + export function useCounter(initial = 0): UseCounterReturn { + const count = ref(initial) + const increment = (): void => { count.value++ } + return { count, increment } + } + + βœ… Component naming: UserProfile.vue, TheHeader.vue + ❌ Avoid: userProfile.vue, user_profile.vue +examples: + - input: | + export function useCounter() { + const count = ref(0) + return { count } + } + output: | + export interface UseCounterReturn { + count: Ref + } + export function useCounter(): UseCounterReturn { + const count = ref(0) + return { count } + } +metadata: + +### vue3-watchers + +Best practices for watch and watchEffect with TypeScript + +**Actions:** + - type: suggest + message: | + βœ… Use watchers properly with TypeScript: + + // watch() for specific reactive sources + watch( + () => user.value?.id, + (newId: number | undefined, oldId: number | undefined) => { + if (newId) { + fetchUserData(newId) + } + }, + { immediate: true } + ) + + // watch multiple sources + watch( + [() => props.userId, searchQuery], + async ([userId, query]: [number | undefined, string]) => { + if (userId && query) { + await searchUserData(userId, query) + } + } + ) + + // watchEffect for side effects + watchEffect(() => { + if (user.value && isLoggedIn.value) { + analytics.track('user_active', { userId: user.value.id }) + } + }) + + // Cleanup watchers + const stopWatcher = watch(data, callback) + onUnmounted(() => stopWatcher()) + + ❌ Avoid untyped watchers and missing cleanup: + watch(user, (newVal, oldVal) => { ... }) + watchEffect(() => { ... }) // without cleanup consideration +examples: + - input: | + watch(user, (newVal, oldVal) => { + console.log('User changed') + }) + output: | + watch( + user, + (newUser: User | null, oldUser: User | null) => { + if (newUser) { + console.log('User changed:', newUser.name) + } + } + ) +metadata: + +### vue3-advanced-patterns + +Type-safe provide/inject and performance optimization + +**Actions:** + - type: suggest + message: | + βœ… Type-safe dependency injection: + // types/keys.ts + export const UserKey: InjectionKey> = Symbol('user') + + // Usage + provide(UserKey, currentUser) + const user = inject(UserKey) + + βœ… Performance patterns: + const largeList = shallowRef([]) + const filtered = computed(() => items.value.filter(item => item.active)) + const AsyncComp = defineAsyncComponent(() => import('./Heavy.vue')) +examples: + - input: | + provide('user', currentUser) + const user = inject('user') + output: | + export const UserKey: InjectionKey> = Symbol('user') + provide(UserKey, currentUser) + const user = inject(UserKey) +metadata: + +## Additional Information +# Vue 3 with TypeScript Standards + +Modern Vue 3 development with TypeScript, emphasizing type safety, Composition API, and performance. + + + + + + + + + + + + + + +## File Structure + +``` +src/ +β”œβ”€β”€ components/ # Reusable components +β”œβ”€β”€ composables/ # Vue composables +β”œβ”€β”€ layouts/ # Vue layouts +β”œβ”€β”€ stores/ # Vue stores +β”œβ”€β”€ utils/ # Vue utils +β”œβ”€β”€ types/ # TypeScript definitions +└── pages/ # Page components + +``` + +### Import Order + +```typescript +// 1. Vue core +import { ref, computed } from "vue"; +// 2. Vue ecosystem +import { useRouter } from "vue-router"; +// 3. Third-party +import axios from "axios"; +// 4. Local +import UserCard from "@/components/UserCard.vue"; +``` + +tests: + +- input: | + + output: | + +- input: "const modelValue = defineModel()" + output: "const modelValue = defineModel()" +- input: "provide('theme', 'dark')" + output: | + export const ThemeKey: InjectionKey = Symbol('theme') + provide(ThemeKey, 'dark') \ No newline at end of file diff --git a/.claude/rules/test/playwright-agent.md b/.claude/rules/test/playwright-agent.md new file mode 100644 index 0000000..28a535f --- /dev/null +++ b/.claude/rules/test/playwright-agent.md @@ -0,0 +1,250 @@ +# Playwright end-to-end testing best practices + +## Description +Playwright end-to-end testing best practices + +## Applicability +- **Files:** `*.spec.ts` +- **Always Apply:** false + +## Additional Information +# Critical Rules + +- Use descriptive and meaningful test names that clearly describe the expected behavior. +- Utilize Playwright fixtures (e.g., `test`, `page`, `expect`) to maintain test isolation and consistency. +- Use `test.beforeEach` and `test.afterEach` for setup and teardown to ensure a clean state for each test. +- Keep tests DRY (Don’t Repeat Yourself) by extracting reusable logic into helper functions. +- Use `page.getByTestId` whenever `data-testid` is defined on an element or container. +- Use the recommended built-in and role-based locators (`page.getByRole`, `page.getByLabel`, `page.getByText`, `page.getByTitle`, etc.) over complex selectors. +- Use `page.getByLocator()` when it's not possible to use any of the above to locate an element. +- Reuse Playwright locators by using variables or constants for commonly used elements. +- Use the `playwright.config.ts` file for global configuration and environment setup. +- Use built-in config objects like `devices` whenever possible. +- Prefer to use web-first assertions (`toBeVisible`, `toHaveText`, etc.) whenever possible. +- Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) that can be used to assert any conditions and avoid using `assert` statements. +- Avoid hardcoded timeouts. +- Do not perform exhaustive testing. Stick to critical user paths. +- Use `page.waitFor` with specific conditions or events to wait for elements or states. +- Ensure tests run reliably in parallel without shared state conflicts. +- Avoid commenting on the resulting code. +- Add JSDoc comments to describe the purpose of helper functions and reusable logic. + +## 1. Use `@playwright/test` + +Leverage the official test runner for built-in fixtures, isolation, and web-first assertions. Avoid the low-level `playwright` library for E2E tests. + +❌ BAD: Using `playwright` directly + +```typescript +import { chromium } from "playwright" +// ... manual browser/context setup and teardown +const browser = await chromium.launch() +const page = await browser.newPage() +// ... +await browser.close() +``` + +βœ… GOOD: Using `@playwright/test` + +```typescript +import { test, expect } from "@playwright/test" +test("should navigate to home", async ({ page }) => { + await page.goto("/") + await expect(page).toHaveTitle(/Home/) +}) +``` + +## 2. Prioritize Robust Locators + +Use Playwright's built-in Locators API, favoring user-facing attributes over brittle CSS selectors. This drastically improves test stability. + +❌ BAD: Fragile, implementation-dependent selectors + +```typescript +await page.locator("div.container > ul > li:nth-child(2) > button").click() +``` + +βœ… GOOD: Semantic, user-facing locators + +```typescript +await page.getByRole("button", { name: "Add to Cart" }).click() +await page.getByLabel("Username").fill("testuser") +await page.getByTestId("product-item-123").click() +``` + +## 3. Embrace Web-First Assertions + +Playwright's `expect` assertions automatically retry until conditions are met, eliminating manual waits and flakiness. Never use `page.waitForTimeout()`. + +❌ BAD: Manual, flaky waits and generic assertions + +```typescript +await page.waitForTimeout(2000) // 🚨 Flaky! +const title = await page.title() +assert.equal(title, "My Page") // 🚨 Not web-first +``` + +βœ… GOOD: Reliable, auto-retrying assertions + +```typescript +await expect(page).toHaveTitle(/My Page/) +await expect(page.getByText("Welcome")).toBeVisible() +await expect(page.getByRole("checkbox")).toBeChecked() +``` + +## 4. Implement the Page Object Model (POM) + +Encapsulate selectors and actions within dedicated classes. This improves readability, reusability, and maintainability. + +❌ BAD: Repeated selectors and logic across tests + +```typescript +// test-login.spec.ts +await page.getByLabel("Username").fill("user") +await page.getByLabel("Password").fill("pass") +await page.getByRole("button", { name: "Login" }).click() + +// test-profile.spec.ts +// ... same login steps repeated ... +``` + +βœ… GOOD: Centralized Page Object + +```typescript +// pages/LoginPage.ts +import { Page, Locator } from "@playwright/test" + +export class LoginPage { + readonly page: Page + readonly usernameInput: Locator + readonly passwordInput: Locator + readonly loginButton: Locator + + constructor(page: Page) { + this.page = page + this.usernameInput = page.getByLabel("Username") + this.passwordInput = page.getByLabel("Password") + this.loginButton = page.getByRole("button", { name: "Login" }) + } + + async navigate() { + await this.page.goto("/login") + } + + async login(username: string, password: string) { + await this.usernameInput.fill(username) + await this.passwordInput.fill(password) + await this.loginButton.click() + } +} + +// tests/login.spec.ts +import { test, expect } from "@playwright/test" +import { LoginPage } from "../pages/LoginPage" + +test("should successfully log in", async ({ page }) => { + const loginPage = new LoginPage(page) + await loginPage.navigate() + await loginPage.login("testuser", "password") + await expect(page).toHaveURL(/dashboard/) +}) +``` + +## 5. Optimize Performance with Auth State & Route Blocking + +Reduce test execution time by reusing authenticated sessions and blocking unnecessary network requests. + +❌ BAD: Logging in for every test and loading all assets + +```typescript +test("view profile", async ({ page }) => { + await page.goto("/login") + await page.getByLabel("Username").fill("user") + await page.getByLabel("Password").fill("pass") + await page.getByRole("button", { name: "Login" }).click() + await page.goto("/profile") // Loads all images, analytics, etc. +}) +``` + +βœ… GOOD: Reusing auth state and blocking requests + +```typescript +// playwright.config.ts +import { defineConfig } from "@playwright/test" +export default defineConfig({ + use: { + storageState: "playwright-auth.json", // Path to save/load auth state + }, +}) + +// global-setup.ts (run once before all tests) +import { chromium, expect } from "@playwright/test" +export default async function globalSetup() { + const browser = await chromium.launch() + const page = await browser.newPage() + await page.goto("/login") + await page.getByLabel("Username").fill("testuser") + await page.getByLabel("Password").fill("password") + await page.getByRole("button", { name: "Login" }).click() + await expect(page).toHaveURL(/dashboard/) + await page.context().storageState({ path: "playwright-auth.json" }) + await browser.close() +} + +// tests/profile.spec.ts +import { test, expect } from "@playwright/test" +test("should display user profile", async ({ page, context }) => { + // Block unnecessary resources for faster tests + await context.route("**/*.{png,jpg,jpeg,gif,webp,svg,css}", (route) => + route.abort() + ) + await page.goto("/profile") // Automatically uses saved auth state + await expect(page.getByText("Welcome, testuser!")).toBeVisible() +}) +``` + +## 6. Mock APIs for Deterministic Tests + +Isolate your UI tests from backend flakiness by intercepting and mocking API responses. + +❌ BAD: Relying on a live, potentially unstable backend + +```typescript +test("display products", async ({ page }) => { + await page.goto("/products") // Fetches from real API + await expect(page.getByText("Product A")).toBeVisible() +}) +``` + +βœ… GOOD: Mocking API responses + +```typescript +test("display mocked products", async ({ page }) => { + await page.route("**/api/products", (route) => { + route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify([{ id: 1, name: "Mock Product" }]), + }) + }) + await page.goto("/products") + await expect(page.getByText("Mock Product")).toBeVisible() +}) +``` + +## 7. Leverage CI/CD Features for Debugging + +Configure tracing, screenshots, and video recording in your `playwright.config.ts` to instantly diagnose failures in CI. + +```typescript +// playwright.config.ts +import { defineConfig } from "@playwright/test" +export default defineConfig({ + reporter: [["html"], ["list"]], + use: { + trace: "on-first-retry", // Record trace only on first retry + screenshot: "on", // Always take a screenshot on failure + video: "on-first-retry", // Record video on first retry + }, +}) +``` \ No newline at end of file diff --git a/.claude/rules/test/react-component-hook-testing-auto.md b/.claude/rules/test/react-component-hook-testing-auto.md new file mode 100644 index 0000000..2b157b4 --- /dev/null +++ b/.claude/rules/test/react-component-hook-testing-auto.md @@ -0,0 +1,117 @@ +# Enforces best practices for unit testing React components and custom hooks using React Testing Library and Vitest + +## Description +Enforces best practices for unit testing React components and custom hooks using React Testing Library and Vitest. + +## Applicability +- **Files:** `"*.test.{js,ts,jsx,tsx},*.spec.{js,ts,jsx,tsx}"` +- **Always Apply:** false + +## Rules +- Use `@testing-library/react` for rendering components; avoid shallow rendering or testing implementation details. +- Prefer accessibility queries (`getByRole`, `getByLabelText`, etc.) over `getByTestId` or CSS selectors. +- Simulate user interactions with `userEvent` instead of firing raw DOM events. +- Each test must contain at least one assertion using `expect`. +- Group related tests in `describe` blocks with descriptive titles. +- Avoid querying private DOM nodes with `container.querySelector`. +- Do not snapshot the entire DOM tree for dynamic components; assert specific, stable text/attributes. +- For hooks, use `@testing-library/react`'s `renderHook` or equivalent utilities. +- Always test custom hooks in isolation and with all relevant edge cases. +- Mock external dependencies and context providers as needed for hooks. +- Avoid using `any` in test or hook typings; always use explicit types. +- Clean up side-effects after each test (rely on library auto-cleanup or call `cleanup()`). +- Do not use `.skip` or `.only` in committed test code. + +### react-component-hook-testing + +Enforces best practices for testing React components and custom hooks with React Testing Library and Vitest + +**Actions:** + - type: suggest + message: | + Use React Testing Library for rendering and userEvent for interactions. Prefer accessibility queries and always assert user-visible output. + - type: suggest + pattern: "container\\.querySelector" + message: | + Avoid querying DOM directly. Use queries like `screen.getByRole` or `screen.getByText` to reflect real user interactions. + - type: suggest + pattern: "fireEvent\\." + message: | + Use `userEvent` to simulate real user behaviour instead of `fireEvent`, e.g. `await userEvent.click(button)`. + - type: suggest + pattern: "\.skip|\.only" + message: | + Do not commit tests with `.skip` or `.only`. All tests should run in CI. + - type: suggest + message: | + Each test must contain at least one assertion (`expect`). +examples: + - input: | + it('renders', () => { + const { container } = render() + container.querySelector('button[type="submit"]') + }) + output: | + it('renders submit button', () => { + render() + expect(screen.getByRole('button', { name: /sign in/i })).toBeInTheDocument() + }) + - input: | + it('calls onClick', async () => { + render(