create-dev-agents 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js ADDED
@@ -0,0 +1,339 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import enquirer from 'enquirer';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
11
+
12
+ const COMMANDS = {
13
+ 'new-project': 'Create new projects (Expo, React Native, React, Next.js)',
14
+ 'feature': 'Implement complete features with components, hooks, tests',
15
+ 'commit': 'Generate conventional commit messages',
16
+ 'pr': 'Create pull requests with proper descriptions',
17
+ 'ticket': 'Create Jira tickets with templates',
18
+ 'review': 'Code review with actionable feedback'
19
+ };
20
+
21
+ const AGENTS = {
22
+ 'project': 'Project scaffolding agent',
23
+ 'feature': 'Feature development agent',
24
+ 'git': 'Git workflow agent (commits, PRs)',
25
+ 'jira': 'Jira ticket agent',
26
+ 'code-review': 'Code review agent'
27
+ };
28
+
29
+ export async function init(options = {}) {
30
+ const spinner = ora();
31
+ const targetDir = options.global ? path.join(process.env.HOME, '.claude') : process.cwd();
32
+
33
+ try {
34
+ // Prompt for what to install
35
+ let selections;
36
+ if (options.all) {
37
+ selections = { commands: Object.keys(COMMANDS), extras: ['agents', 'templates', 'scripts', 'mcp'] };
38
+ } else if (options.minimal) {
39
+ selections = { commands: ['commit', 'pr', 'review'], extras: [] };
40
+ } else {
41
+ const { Select, MultiSelect } = enquirer;
42
+
43
+ const commandPrompt = new MultiSelect({
44
+ name: 'commands',
45
+ message: 'Select commands to install',
46
+ choices: Object.entries(COMMANDS).map(([name, desc]) => ({
47
+ name,
48
+ message: `/${name}`,
49
+ hint: desc
50
+ })),
51
+ initial: Object.keys(COMMANDS)
52
+ });
53
+
54
+ const extrasPrompt = new MultiSelect({
55
+ name: 'extras',
56
+ message: 'Select additional components',
57
+ choices: [
58
+ { name: 'agents', message: 'Agent definitions', hint: 'Detailed agent behaviors' },
59
+ { name: 'templates', message: 'Templates', hint: 'PR, commit, Jira templates' },
60
+ { name: 'scripts', message: 'Shell scripts', hint: 'Automation scripts' },
61
+ { name: 'mcp', message: 'MCP config', hint: 'GitHub, Jira, Git servers' }
62
+ ],
63
+ initial: ['mcp']
64
+ });
65
+
66
+ const commands = await commandPrompt.run();
67
+ const extras = await extrasPrompt.run();
68
+ selections = { commands, extras };
69
+ }
70
+
71
+ // Create directories
72
+ spinner.start('Creating directories...');
73
+ const dirs = ['.claude/commands'];
74
+ if (selections.extras.includes('agents')) dirs.push('agents');
75
+ if (selections.extras.includes('templates')) dirs.push('templates');
76
+ if (selections.extras.includes('scripts')) dirs.push('scripts');
77
+
78
+ for (const dir of dirs) {
79
+ const fullPath = path.join(targetDir, dir);
80
+ fs.mkdirSync(fullPath, { recursive: true });
81
+ }
82
+ spinner.succeed('Directories created');
83
+
84
+ // Copy commands
85
+ spinner.start('Installing commands...');
86
+ for (const cmd of selections.commands) {
87
+ const src = path.join(TEMPLATES_DIR, 'commands', `${cmd}.md`);
88
+ const dest = path.join(targetDir, '.claude', 'commands', `${cmd}.md`);
89
+ if (fs.existsSync(src)) {
90
+ fs.copyFileSync(src, dest);
91
+ }
92
+ }
93
+ spinner.succeed(`Installed ${selections.commands.length} commands`);
94
+
95
+ // Copy extras
96
+ if (selections.extras.includes('agents')) {
97
+ spinner.start('Installing agents...');
98
+ copyDir(path.join(TEMPLATES_DIR, 'agents'), path.join(targetDir, 'agents'));
99
+ spinner.succeed('Agents installed');
100
+ }
101
+
102
+ if (selections.extras.includes('templates')) {
103
+ spinner.start('Installing templates...');
104
+ copyDir(path.join(TEMPLATES_DIR, 'templates'), path.join(targetDir, 'templates'));
105
+ spinner.succeed('Templates installed');
106
+ }
107
+
108
+ if (selections.extras.includes('scripts')) {
109
+ spinner.start('Installing scripts...');
110
+ copyDir(path.join(TEMPLATES_DIR, 'scripts'), path.join(targetDir, 'scripts'));
111
+ // Make scripts executable
112
+ const scriptsDir = path.join(targetDir, 'scripts');
113
+ if (fs.existsSync(scriptsDir)) {
114
+ for (const file of fs.readdirSync(scriptsDir)) {
115
+ if (file.endsWith('.sh')) {
116
+ fs.chmodSync(path.join(scriptsDir, file), '755');
117
+ }
118
+ }
119
+ }
120
+ spinner.succeed('Scripts installed');
121
+ }
122
+
123
+ if (selections.extras.includes('mcp')) {
124
+ spinner.start('Installing MCP config...');
125
+ const src = path.join(TEMPLATES_DIR, 'mcp-settings.json');
126
+ const dest = path.join(targetDir, '.claude', 'settings.json');
127
+ if (fs.existsSync(src) && !fs.existsSync(dest)) {
128
+ fs.copyFileSync(src, dest);
129
+ }
130
+ spinner.succeed('MCP config installed');
131
+ }
132
+
133
+ // Create CLAUDE.md if not exists
134
+ const claudeMd = path.join(targetDir, 'CLAUDE.md');
135
+ if (!fs.existsSync(claudeMd) && !options.global) {
136
+ const template = path.join(TEMPLATES_DIR, 'CLAUDE.md');
137
+ if (fs.existsSync(template)) {
138
+ fs.copyFileSync(template, claudeMd);
139
+ spinner.succeed('Created CLAUDE.md');
140
+ }
141
+ }
142
+
143
+ // Success message
144
+ console.log(chalk.green.bold('\n✅ Dev Agents installed successfully!\n'));
145
+ console.log(chalk.white('Available commands:'));
146
+ for (const cmd of selections.commands) {
147
+ console.log(chalk.yellow(` /${cmd}`) + chalk.gray(` - ${COMMANDS[cmd]}`));
148
+ }
149
+ console.log();
150
+ console.log(chalk.white('Next steps:'));
151
+ console.log(chalk.gray(' 1. Open this project in Claude Code'));
152
+ console.log(chalk.gray(' 2. Type a command like /new-project or /commit'));
153
+ if (selections.extras.includes('mcp')) {
154
+ console.log(chalk.gray(' 3. Run `dev-agents mcp` to configure API tokens'));
155
+ }
156
+ console.log();
157
+
158
+ } catch (error) {
159
+ spinner.fail('Installation failed');
160
+ console.error(chalk.red(error.message));
161
+ process.exit(1);
162
+ }
163
+ }
164
+
165
+ export async function addCommand(command) {
166
+ const spinner = ora();
167
+
168
+ if (!COMMANDS[command]) {
169
+ console.log(chalk.red(`Unknown command: ${command}`));
170
+ console.log(chalk.white('\nAvailable commands:'));
171
+ Object.keys(COMMANDS).forEach(cmd => {
172
+ console.log(chalk.yellow(` ${cmd}`) + chalk.gray(` - ${COMMANDS[cmd]}`));
173
+ });
174
+ return;
175
+ }
176
+
177
+ spinner.start(`Adding /${command}...`);
178
+
179
+ const targetDir = process.cwd();
180
+ fs.mkdirSync(path.join(targetDir, '.claude', 'commands'), { recursive: true });
181
+
182
+ const src = path.join(TEMPLATES_DIR, 'commands', `${command}.md`);
183
+ const dest = path.join(targetDir, '.claude', 'commands', `${command}.md`);
184
+
185
+ if (fs.existsSync(src)) {
186
+ fs.copyFileSync(src, dest);
187
+ spinner.succeed(`Added /${command}`);
188
+ } else {
189
+ spinner.fail(`Template not found for ${command}`);
190
+ }
191
+ }
192
+
193
+ export function listCommands() {
194
+ console.log(chalk.blue.bold('\n📋 Available Commands\n'));
195
+
196
+ console.log(chalk.white.bold('Slash Commands (/.claude/commands/):'));
197
+ Object.entries(COMMANDS).forEach(([name, desc]) => {
198
+ console.log(chalk.yellow(` /${name}`) + chalk.gray(` - ${desc}`));
199
+ });
200
+
201
+ console.log(chalk.white.bold('\nAgents (/agents/):'));
202
+ Object.entries(AGENTS).forEach(([name, desc]) => {
203
+ console.log(chalk.cyan(` ${name}`) + chalk.gray(` - ${desc}`));
204
+ });
205
+
206
+ console.log(chalk.white.bold('\nTemplates (/templates/):'));
207
+ console.log(chalk.gray(' pr/feature.md, pr/bugfix.md'));
208
+ console.log(chalk.gray(' jira/story.md, jira/bug.md'));
209
+ console.log(chalk.gray(' commit/examples.md'));
210
+ console.log();
211
+ }
212
+
213
+ export async function setupMcp() {
214
+ const { Input, Password } = enquirer;
215
+
216
+ console.log(chalk.blue.bold('\n🔌 MCP Server Configuration\n'));
217
+ console.log(chalk.gray('Configure API tokens for GitHub and Jira integration.\n'));
218
+
219
+ try {
220
+ // GitHub
221
+ console.log(chalk.white.bold('GitHub Configuration'));
222
+ console.log(chalk.gray('Create token at: https://github.com/settings/tokens'));
223
+ console.log(chalk.gray('Required scopes: repo, read:user\n'));
224
+
225
+ const githubPrompt = new Password({
226
+ name: 'github',
227
+ message: 'GitHub Token (leave empty to skip)'
228
+ });
229
+ const githubToken = await githubPrompt.run();
230
+
231
+ // Jira
232
+ console.log(chalk.white.bold('\nJira Configuration'));
233
+ console.log(chalk.gray('Create token at: https://id.atlassian.com/manage-profile/security/api-tokens\n'));
234
+
235
+ const jiraHostPrompt = new Input({
236
+ name: 'host',
237
+ message: 'Jira Host (e.g., company.atlassian.net)',
238
+ initial: ''
239
+ });
240
+ const jiraHost = await jiraHostPrompt.run();
241
+
242
+ let jiraEmail = '', jiraToken = '';
243
+ if (jiraHost) {
244
+ const emailPrompt = new Input({ name: 'email', message: 'Jira Email' });
245
+ const tokenPrompt = new Password({ name: 'token', message: 'Jira API Token' });
246
+ jiraEmail = await emailPrompt.run();
247
+ jiraToken = await tokenPrompt.run();
248
+ }
249
+
250
+ // Write to env file
251
+ const envContent = `# Dev Agents MCP Configuration
252
+ # Source this file: source ~/.dev-agents-env
253
+
254
+ # GitHub
255
+ export GITHUB_TOKEN="${githubToken}"
256
+
257
+ # Jira
258
+ export JIRA_HOST="${jiraHost}"
259
+ export JIRA_EMAIL="${jiraEmail}"
260
+ export JIRA_API_TOKEN="${jiraToken}"
261
+ `;
262
+
263
+ const envPath = path.join(process.env.HOME, '.dev-agents-env');
264
+ fs.writeFileSync(envPath, envContent, { mode: 0o600 });
265
+
266
+ console.log(chalk.green.bold('\n✅ Configuration saved!\n'));
267
+ console.log(chalk.white('Add to your shell profile:'));
268
+ console.log(chalk.yellow(` echo 'source ~/.dev-agents-env' >> ~/.zshrc`));
269
+ console.log(chalk.white('\nOr run:'));
270
+ console.log(chalk.yellow(` source ~/.dev-agents-env`));
271
+ console.log();
272
+
273
+ } catch (error) {
274
+ if (error.message !== 'cancelled') {
275
+ console.error(chalk.red(error.message));
276
+ }
277
+ }
278
+ }
279
+
280
+ export async function installGlobal() {
281
+ const spinner = ora();
282
+ const globalDir = path.join(process.env.HOME, '.claude');
283
+
284
+ spinner.start('Installing globally to ~/.claude...');
285
+
286
+ try {
287
+ // Create directories
288
+ fs.mkdirSync(path.join(globalDir, 'commands'), { recursive: true });
289
+
290
+ // Copy all commands
291
+ const commandsDir = path.join(TEMPLATES_DIR, 'commands');
292
+ if (fs.existsSync(commandsDir)) {
293
+ for (const file of fs.readdirSync(commandsDir)) {
294
+ fs.copyFileSync(
295
+ path.join(commandsDir, file),
296
+ path.join(globalDir, 'commands', file)
297
+ );
298
+ }
299
+ }
300
+
301
+ // Copy MCP settings if not exists
302
+ const settingsSrc = path.join(TEMPLATES_DIR, 'mcp-settings.json');
303
+ const settingsDest = path.join(globalDir, 'settings.json');
304
+ if (fs.existsSync(settingsSrc) && !fs.existsSync(settingsDest)) {
305
+ fs.copyFileSync(settingsSrc, settingsDest);
306
+ }
307
+
308
+ spinner.succeed('Installed globally');
309
+
310
+ console.log(chalk.green.bold('\n✅ Commands available in all projects!\n'));
311
+ console.log(chalk.white('Installed commands:'));
312
+ Object.keys(COMMANDS).forEach(cmd => {
313
+ console.log(chalk.yellow(` /${cmd}`));
314
+ });
315
+ console.log();
316
+
317
+ } catch (error) {
318
+ spinner.fail('Global installation failed');
319
+ console.error(chalk.red(error.message));
320
+ }
321
+ }
322
+
323
+ // Helper: Copy directory recursively
324
+ function copyDir(src, dest) {
325
+ if (!fs.existsSync(src)) return;
326
+
327
+ fs.mkdirSync(dest, { recursive: true });
328
+
329
+ for (const item of fs.readdirSync(src)) {
330
+ const srcPath = path.join(src, item);
331
+ const destPath = path.join(dest, item);
332
+
333
+ if (fs.statSync(srcPath).isDirectory()) {
334
+ copyDir(srcPath, destPath);
335
+ } else {
336
+ fs.copyFileSync(srcPath, destPath);
337
+ }
338
+ }
339
+ }
@@ -0,0 +1,38 @@
1
+ # Project Development Guide
2
+
3
+ ## Available Commands
4
+
5
+ | Command | Description |
6
+ |---------|-------------|
7
+ | `/new-project` | Create new project (Expo, React, Next.js) |
8
+ | `/feature [name]` | Implement a complete feature |
9
+ | `/commit` | Generate conventional commit message |
10
+ | `/pr` | Create pull request with description |
11
+ | `/ticket` | Create Jira ticket |
12
+ | `/review [file]` | Code review with suggestions |
13
+
14
+ ## Quick Start
15
+
16
+ ```bash
17
+ # Create a new project
18
+ /new-project
19
+
20
+ # Implement a feature
21
+ /feature user-authentication
22
+
23
+ # After making changes
24
+ /commit
25
+ /pr
26
+ ```
27
+
28
+ ## MCP Integrations
29
+
30
+ If configured, these commands can interact with:
31
+ - **GitHub** - Create PRs, issues, request reviews
32
+ - **Jira** - Create and update tickets
33
+ - **Git** - Commits, branches, diffs
34
+
35
+ Run `dev-agents mcp` to configure API tokens.
36
+
37
+ ---
38
+ *Powered by [create-dev-agents](https://github.com/yourusername/create-dev-agents)*
@@ -0,0 +1,158 @@
1
+ # Code Review Agent
2
+
3
+ You are a code review assistant that helps review code for quality, security, and best practices.
4
+
5
+ ## Review Checklist
6
+
7
+ ### 1. Code Quality
8
+ - [ ] Code is readable and self-documenting
9
+ - [ ] Functions are small and focused (Single Responsibility)
10
+ - [ ] No code duplication (DRY principle)
11
+ - [ ] Proper error handling
12
+ - [ ] Meaningful variable/function names
13
+ - [ ] No magic numbers/strings (use constants)
14
+
15
+ ### 2. TypeScript/Type Safety
16
+ - [ ] Proper types defined (no `any` without justification)
17
+ - [ ] Interfaces for complex objects
18
+ - [ ] Null/undefined handled properly
19
+ - [ ] Generic types used appropriately
20
+ - [ ] Type guards where needed
21
+
22
+ ### 3. React/React Native Specific
23
+ - [ ] Components follow single responsibility
24
+ - [ ] Proper use of hooks (dependencies correct)
25
+ - [ ] Memoization where beneficial (React.memo, useMemo, useCallback)
26
+ - [ ] No unnecessary re-renders
27
+ - [ ] Proper key props in lists
28
+ - [ ] Event handlers properly bound
29
+
30
+ ### 4. Performance
31
+ - [ ] No expensive operations in render
32
+ - [ ] Large lists use virtualization (FlatList)
33
+ - [ ] Images optimized
34
+ - [ ] Lazy loading implemented where appropriate
35
+ - [ ] No memory leaks (cleanup in useEffect)
36
+
37
+ ### 5. Security
38
+ - [ ] No sensitive data in logs
39
+ - [ ] Input validation present
40
+ - [ ] SQL injection prevention (prepared statements)
41
+ - [ ] XSS prevention
42
+ - [ ] Secrets not hardcoded
43
+
44
+ ### 6. Accessibility
45
+ - [ ] Proper accessibility labels
46
+ - [ ] Touch targets >= 44pt
47
+ - [ ] Color contrast sufficient
48
+ - [ ] Screen reader support
49
+
50
+ ### 7. Testing
51
+ - [ ] Unit tests for logic
52
+ - [ ] Component tests for UI
53
+ - [ ] Edge cases covered
54
+ - [ ] Error scenarios tested
55
+
56
+ ## Review Output Format
57
+
58
+ ```markdown
59
+ ## Code Review Summary
60
+
61
+ **Files Reviewed:** [number]
62
+ **Overall Quality:** [Excellent/Good/Needs Improvement/Major Issues]
63
+
64
+ ### Critical Issues (Must Fix)
65
+ 1. **[File:Line]** - [Issue description]
66
+ - **Problem:** [What's wrong]
67
+ - **Impact:** [Why it matters]
68
+ - **Suggestion:** [How to fix]
69
+
70
+ ### Improvements (Should Fix)
71
+ 1. **[File:Line]** - [Issue description]
72
+ - **Suggestion:** [Improvement]
73
+
74
+ ### Suggestions (Nice to Have)
75
+ 1. **[File:Line]** - [Suggestion]
76
+
77
+ ### Positive Highlights
78
+ - [Good practice observed]
79
+ - [Well-written code section]
80
+
81
+ ### Summary
82
+ [Overall assessment and recommendation]
83
+ ```
84
+
85
+ ## Common Issues to Check
86
+
87
+ ### React Hooks
88
+ ```typescript
89
+ // Bad: Missing dependency
90
+ useEffect(() => {
91
+ fetchData(userId);
92
+ }, []); // userId should be in deps
93
+
94
+ // Good: All dependencies included
95
+ useEffect(() => {
96
+ fetchData(userId);
97
+ }, [userId]);
98
+ ```
99
+
100
+ ### Memory Leaks
101
+ ```typescript
102
+ // Bad: No cleanup
103
+ useEffect(() => {
104
+ const subscription = eventEmitter.subscribe(handler);
105
+ }, []);
106
+
107
+ // Good: Proper cleanup
108
+ useEffect(() => {
109
+ const subscription = eventEmitter.subscribe(handler);
110
+ return () => subscription.unsubscribe();
111
+ }, []);
112
+ ```
113
+
114
+ ### Type Safety
115
+ ```typescript
116
+ // Bad: Using any
117
+ const handleData = (data: any) => { ... }
118
+
119
+ // Good: Proper typing
120
+ interface UserData {
121
+ id: string;
122
+ name: string;
123
+ }
124
+ const handleData = (data: UserData) => { ... }
125
+ ```
126
+
127
+ ### Error Handling
128
+ ```typescript
129
+ // Bad: Silent failure
130
+ try {
131
+ await saveData();
132
+ } catch (e) {}
133
+
134
+ // Good: Proper handling
135
+ try {
136
+ await saveData();
137
+ } catch (error) {
138
+ logger.error('Failed to save data', error);
139
+ showErrorToast('Could not save. Please try again.');
140
+ }
141
+ ```
142
+
143
+ ## Review Commands
144
+
145
+ ```bash
146
+ # Review specific files
147
+ review_files(paths: ["src/components/Button.tsx"])
148
+
149
+ # Review PR
150
+ review_pull_request(number: 123)
151
+
152
+ # Suggest changes
153
+ suggest_change(
154
+ file: "src/utils.ts",
155
+ line: 42,
156
+ suggestion: "Consider using optional chaining"
157
+ )
158
+ ```
@@ -0,0 +1,113 @@
1
+ # Feature Development Agent
2
+
3
+ You are a feature development assistant that helps implement features following best practices and project conventions.
4
+
5
+ ## Workflow
6
+
7
+ ### Step 1: Feature Analysis
8
+ When given a feature request:
9
+ 1. Understand the requirements
10
+ 2. Identify affected areas (UI, API, database, state)
11
+ 3. Break down into tasks
12
+ 4. Estimate complexity
13
+
14
+ ### Step 2: Planning
15
+ Create an implementation plan:
16
+ - List files to create/modify
17
+ - Define component hierarchy
18
+ - Plan state management approach
19
+ - Identify API endpoints needed
20
+ - Consider edge cases and error handling
21
+
22
+ ### Step 3: Implementation
23
+ For each task:
24
+ 1. Create types/interfaces first
25
+ 2. Implement core logic
26
+ 3. Create UI components
27
+ 4. Add state management
28
+ 5. Connect everything
29
+ 6. Add error handling
30
+ 7. Write tests
31
+
32
+ ## Feature Template
33
+
34
+ ### Component Feature
35
+ ```typescript
36
+ // types/[feature].types.ts
37
+ export interface Feature {
38
+ id: string;
39
+ // ... properties
40
+ }
41
+
42
+ export interface FeatureState {
43
+ items: Feature[];
44
+ loading: boolean;
45
+ error: string | null;
46
+ }
47
+
48
+ // hooks/use[Feature].ts
49
+ export function useFeature() {
50
+ // Hook implementation
51
+ }
52
+
53
+ // components/[Feature]/[Feature].tsx
54
+ export function Feature({ ...props }: FeatureProps) {
55
+ // Component implementation
56
+ }
57
+
58
+ // services/[feature].service.ts
59
+ export const featureService = {
60
+ getAll: async () => {},
61
+ getById: async (id: string) => {},
62
+ create: async (data: CreateFeatureInput) => {},
63
+ update: async (id: string, data: UpdateFeatureInput) => {},
64
+ delete: async (id: string) => {},
65
+ };
66
+ ```
67
+
68
+ ## Conventions
69
+
70
+ ### Naming
71
+ - Components: PascalCase (UserProfile.tsx)
72
+ - Hooks: camelCase with 'use' prefix (useAuth.ts)
73
+ - Services: camelCase with '.service' suffix
74
+ - Types: PascalCase for interfaces, camelCase for type aliases
75
+ - Constants: UPPER_SNAKE_CASE
76
+
77
+ ### File Structure
78
+ Each feature should contain:
79
+ ```
80
+ features/[feature]/
81
+ ├── components/
82
+ │ ├── [Component].tsx
83
+ │ ├── [Component].styles.ts (or .module.css)
84
+ │ └── index.ts
85
+ ├── hooks/
86
+ │ ├── use[Feature].ts
87
+ │ └── index.ts
88
+ ├── services/
89
+ │ ├── [feature].service.ts
90
+ │ └── index.ts
91
+ ├── types/
92
+ │ ├── [feature].types.ts
93
+ │ └── index.ts
94
+ ├── utils/
95
+ │ └── [feature].utils.ts
96
+ └── index.ts
97
+ ```
98
+
99
+ ### Code Quality
100
+ - Use TypeScript strict mode
101
+ - Add JSDoc comments for public APIs
102
+ - Handle loading and error states
103
+ - Implement proper accessibility
104
+ - Follow Single Responsibility Principle
105
+
106
+ ## Output Format
107
+
108
+ When implementing a feature, provide:
109
+ 1. **Plan**: Summary of what will be created
110
+ 2. **Files**: List of files with their purposes
111
+ 3. **Code**: Complete implementation
112
+ 4. **Usage**: Example of how to use the feature
113
+ 5. **Tests**: Test cases to verify functionality