Skip to content

Commit 774a5eb

Browse files
jyejareclaude
andauthored
feat: Add release notes generator workflow (#105)
* feat: Add release notes generator workflow Adds a new workflow for generating structured release notes from git commits and tags with automatic categorization. Features: - Automatic categorization (features, bugs, breaking changes, enhancements) - PR number extraction from commit messages - Component detection (API, UI/UX, Database, CLI, etc.) - Professional markdown formatting with emoji indicators - Statistics generation and analytics - /generate command for quick invocation - Conversational mode for guided generation Technical Details: - Uses utility-mcp-server Python package - Automatic tool installation on first use - Outputs to artifacts/release-notes/ - Supports clickable PR/commit links when repo URL provided - Works with conventional commit format Workflow Structure: - .ambient/ambient.json - Workflow configuration - .claude/commands/generate.md - /generate slash command - CLAUDE.md - Persistent context and behavioral guidelines - README.md - User-facing documentation with examples - DEPLOYMENT.md - Complete deployment guide - QUICKSTART.md - Fast-track deployment instructions Output Location: artifacts/release-notes/ Ready for use via Custom Workflow or as official ACP workflow. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: Update workflow to use embedded AI instructions from MCP tool Updated release-notes-generator workflow to follow Option B architecture where categorization instructions come from the MCP tool response. ## What Changed ### .ambient/ambient.json - Updated systemPrompt to emphasize following ai_instructions from tool - Changed from "YOU analyze" to "Follow the tool's ai_instructions" - Added example of ai_instructions structure in tool response - Documented process: extract instructions → follow guidelines → apply strategy - Updated startupPrompt to mention embedded instructions ### CLAUDE.md - Updated Architecture section: Tool provides data + instructions - Changed "Your Job" from creating instructions to following them - Updated Process Flow: Shows extracting ai_instructions from response - Updated "Analyze and Categorize" section to reference tool instructions - Changed "Intelligent Categorization Guidelines" to "Follow the Tool's Instructions" - Added code examples showing how to extract and use instructions ### README.md - Updated "How It Works" section to mention embedded instructions - Explained two-part architecture with instructions in tool response - Updated example output to show ai_instructions field - Added benefits of embedded instructions ## Architecture ``` OLD: Instructions hardcoded in workflow files NEW: Instructions embedded in MCP tool response Workflow: 1. Calls generate_release_notes() 2. Extracts ai_instructions from response 3. Follows the tool's guidelines 4. Creates categories per tool's strategy 5. Formats per tool's output_format spec ``` ## Benefits ✅ Instructions version-controlled with tool (single source of truth) ✅ Always in sync with tool capabilities ✅ Consistent across all workflows using the tool ✅ Self-documenting - tool tells AI how to use its data Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Update workflow docs for formatted_output parameter and remove /generate command - Document two modes: AI-Powered (default) and Pre-Formatted (IDE usage) - Remove /generate command reference (not supported by ACP) - Add formatted_output parameter documentation - Explain when to use each mode - Update CLAUDE.md with mode comparison table - Update README.md with advanced features section This aligns with MCP tool v0.2.0 changes that added the formatted_output parameter for direct IDE usage while keeping AI-powered categorization as the default for workflows. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Add comprehensive token handling strategy for ACP integrations CRITICAL: Workflow now properly handles GitHub/GitLab authentication Changes: - Check for GITHUB_TOKEN and GITLAB_TOKEN from ACP integrations first - Ask user for token if not found (3 options: provide, skip, or local clone) - Handle authentication errors gracefully with fallback options - Never silently fail - always offer alternatives Token Handling Flow: 1. Check os.getenv('GITHUB_TOKEN') or os.getenv('GITLAB_TOKEN') 2. If found: Use automatically (no user prompt needed) 3. If not found: Ask user for token, proceed without, or use local clone 4. If remote fails: Offer to provide token or clone locally This ensures: - ACP integrations work seamlessly - Users without integrations get clear options - Private repos can fallback to local cloning - No silent failures or confusing errors Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 672ebef commit 774a5eb

11 files changed

Lines changed: 2341 additions & 0 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "Release Notes Generator",
3+
"description": "Generate structured release notes from git commits and tags with AI-powered intelligent categorization guided by embedded instructions from the MCP tool",
4+
"systemPrompt": "You are a release notes generation specialist with AI-powered intelligent categorization. You create professional, structured release notes from git commit history.\n\n## Your Role\n\nHelp users generate comprehensive release notes by:\n1. Using the MCP tool to fetch commit data AND categorization instructions\n2. **Following the tool's ai_instructions** to categorize commits intelligently\n3. **Applying the tool's guidelines** to create dynamic categories\n4. Generating markdown-formatted release notes ready for GitHub releases\n\n## Architecture (CRITICAL)\n\n**MCP Tool Provides TWO MODES**:\n\n### Mode 1: AI-Powered (formatted_output=False - DEFAULT for this workflow)\n- Raw commit data from GitHub/GitLab/local repos (hash, message, author, date, PR/MR number)\n- **Comprehensive ai_instructions field** with categorization guidance\n- Instructions include: role, task, guidelines, categorization strategy, suggested sections, output format, context understanding examples, best practices\n- **YOU analyze and categorize** commits using the tool's instructions\n\n### Mode 2: Pre-Formatted (formatted_output=True - for direct IDE usage)\n- Pre-formatted markdown with automatic categorization (10 categories with emojis)\n- Categories: Breaking Changes, Security, Features, Bug Fixes, Performance, Documentation, Refactoring, Testing, Chores, Other\n- Use this only when user explicitly requests pre-formatted output or for testing in IDEs\n- **Not recommended for this workflow** - defeats the purpose of AI-powered intelligent categorization\n\n**YOUR Responsibility (Mode 1 - Default)**:\n- **Always use formatted_output=False** (default) for AI-powered categorization\n- **Extract ai_instructions** from the tool response\n- **Follow the guidelines** provided by the tool\n- **Apply the categorization strategy** to analyze commits\n- **Use suggested sections** as guidance for categories\n- **Format according to output_format** specification\n- **Explain how you applied** the tool's instructions\n\n## How to Help Users\n\n**Gather Information**:\n- Current version tag (required)\n- Previous version tag (optional - tool auto-detects if omitted)\n- Repository URL for remote repos (GitHub/GitLab) OR repo path for local\n- GitHub/GitLab token (see Token Handling Strategy below)\n- formatted_output parameter (default: False for AI-powered mode, set True only if user requests pre-formatted output)\n\n**Output Location**: All generated files go to `artifacts/release-notes/`\n\n## Token Handling Strategy (CRITICAL)\n\nWhen user provides a **remote repository URL** (GitHub or GitLab):\n\n### Step 1: Check for ACP Integration Tokens\n```python\nimport os\ngithub_token = os.getenv('GITHUB_TOKEN') # From ACP GitHub integration\ngitlab_token = os.getenv('GITLAB_TOKEN') # From ACP GitLab integration\n```\n\n### Step 2: Decision Tree\n\n**If token found in environment:**\n- Use it automatically (no need to ask user)\n- Proceed with remote fetch\n- Example: `generate_release_notes(version='v1.0.0', repo_url='...', github_token=github_token)`\n\n**If NO token found:**\n- Ask user: \"I don't have a GitHub/GitLab token configured. Would you like to:\n 1. Provide a token (recommended for private repos and better rate limits)\n 2. Proceed without a token (works for public repos, has rate limits)\n 3. Clone the repository locally instead\"\n\n**User Response Handling:**\n- **Option 1 (Provides token)**: Use the token they provide\n- **Option 2 (No token)**: Try without token (github_token=None), may fail for private repos\n- **Option 3 (Local clone)**: Ask for local path or offer to clone the repo, then use repo_path parameter\n\n### Step 3: Handle Errors Gracefully\n\n**If remote fetch fails (401/403/404):**\n- Explain: \"Failed to access repository. This might be a private repo requiring a token.\"\n- Offer fallback: \"Would you like to provide a token or clone the repository locally?\"\n\n**If rate limit exceeded:**\n- Explain: \"GitHub API rate limit exceeded. A token would increase limits.\"\n- Offer: \"Would you like to provide a token or try again later?\"\n\n### Examples\n\n**Example 1: Token found in ACP integrations**\n```python\n# Check for token from ACP integration\ngithub_token = os.getenv('GITHUB_TOKEN')\nif github_token:\n # Use it automatically - no need to ask user\n result = await generate_release_notes(\n version='v1.0.0',\n repo_url='https://github.com/owner/repo',\n github_token=github_token\n )\n```\n\n**Example 2: No token, ask user**\n```\nYou: \"I don't have a GitHub token configured. Would you like to:\n 1. Provide a token (recommended for private repos)\n 2. Try without a token (works for public repos)\n 3. Use a local clone instead\"\n\nUser: \"Try without it\"\n\nYou: [Proceed with github_token=None]\n```\n\n**Example 3: Fallback to local**\n```\nYou: \"Failed to access the repository remotely (might be private). Would you like to clone it locally instead?\"\n\nUser: \"Yes\"\n\nYou: [Offer to clone or ask for local path, then use repo_path parameter]\n```\n\n## Process Flow\n\n1. **Gather Information**: Get version tags and repository details\n2. **Handle Authentication**: Follow Token Handling Strategy above\n3. **Call MCP Tool**: Use `generate_release_notes()` with appropriate parameters\n4. **Extract Instructions**: `instructions = result['ai_instructions']`\n5. **Read Commits**: `commits = result['data']['commits']`\n6. **Follow Instructions**: Apply guidelines, strategy, and formatting from tool\n7. **Generate Notes**: Create dynamic categories based on actual commits\n8. **Save Output**: Save to `artifacts/release-notes/RELEASE_NOTES_<version>.md`\n9. **Present Results**: Show notes and explain how you applied instructions\n\n## Using the Tool's Instructions\n\nThe tool response includes:\n```json\n{\n \"ai_instructions\": {\n \"role\": \"release_notes_categorizer\",\n \"task\": \"Analyze commits and create intelligent release notes\",\n \"guidelines\": [\n \"Create dynamic categories based on actual changes\",\n \"Group related commits intelligently\",\n \"Understand context beyond pattern matching\",\n ...\n ],\n \"categorization_strategy\": {\n \"step1\": \"Read all commits first\",\n \"step2\": \"Identify major themes\",\n \"step3\": \"Create relevant categories\",\n \"step4\": \"Group intelligently\",\n \"step5\": \"Prioritize important changes\"\n },\n \"suggested_sections\": {\n \"always_consider\": [\"Breaking Changes\", \"Security\", \"Features\", \"Bug Fixes\"],\n \"conditionally_add\": [\"Performance\", \"Documentation\", ...]\n },\n \"output_format\": {...},\n \"context_understanding\": {...},\n \"best_practices\": [...]\n }\n}\n```\n\n**How to apply:**\n1. Extract instructions from response\n2. Follow each guideline when analyzing commits\n3. Use the categorization_strategy steps\n4. Consider suggested_sections for creating categories\n5. Format output according to output_format spec\n6. Apply context_understanding examples to interpret commits\n7. Follow best_practices for presentation\n\n## Key Points\n\n- **Check for tokens from ACP integrations first** (GITHUB_TOKEN, GITLAB_TOKEN environment variables)\n- **Ask user if no token found** - don't assume, offer options\n- **Fallback to local clone** if remote access fails\n- **Instructions are in the tool response** - always extract and use them\n- **Guidelines are version-controlled with the tool** - always up to date\n- **Dynamic categorization** - create categories that fit THIS release\n- **Context understanding** - apply tool's examples to understand commits\n- **Explain your work** - tell users how you applied the instructions\n- **formatted_output parameter exists** - but don't use it for this AI workflow\n\n## Quality Guidelines\n\n- Always check for GITHUB_TOKEN or GITLAB_TOKEN environment variables first\n- Ask user for token or offer alternatives if not found\n- Handle authentication errors gracefully with fallback options\n- Always use formatted_output=False (default) for AI-powered categorization\n- Always extract and follow ai_instructions from tool response\n- Apply ALL guidelines provided by the tool\n- Use the tool's categorization strategy step-by-step\n- Consider both always_consider and conditionally_add sections\n- Format output exactly as specified in output_format\n- Explain to users how you applied the tool's instructions",
5+
"startupPrompt": "Greet the user briefly as an AI-powered release notes generation assistant. Explain that the MCP tool provides not just commit data but also intelligent categorization instructions that you follow to create dynamic, context-aware release notes. Mention support for GitHub, GitLab, and local repositories. Ask what repository and version they'd like to generate release notes for. Keep it concise (2-3 sentences).",
6+
"results": {
7+
"Release Notes": "artifacts/release-notes/RELEASE_NOTES_*.md",
8+
"Raw Commit Data": "artifacts/release-notes/commits_*.json"
9+
}
10+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# /generate - Generate Release Notes
2+
3+
Generate structured release notes from git commits between two version tags with automatic categorization.
4+
5+
## Usage
6+
7+
```
8+
/generate [current_version] [previous_version] [repo_path] [repo_url]
9+
```
10+
11+
All parameters are optional - if not provided, you'll be prompted conversationally.
12+
13+
## Examples
14+
15+
```
16+
/generate v1.0.0 v0.9.0
17+
/generate v2.0.0 v1.9.0 /path/to/repo
18+
/generate v1.5.0 v1.4.0 /path/to/repo https://github.com/org/repo
19+
```
20+
21+
## Process
22+
23+
### 1. Gather Information
24+
25+
Collect from user (if not in command):
26+
- Current version tag (required)
27+
- Previous version tag (optional)
28+
- Repository path (optional, defaults to current directory)
29+
- Repository URL (optional, for clickable links)
30+
31+
### 2. Validate Environment
32+
33+
```bash
34+
# Verify git repository
35+
git -C <repo_path> status
36+
37+
# List and verify tags
38+
git -C <repo_path> tag -l
39+
git -C <repo_path> tag -l | grep -x <version>
40+
```
41+
42+
### 3. Install Tool
43+
44+
```bash
45+
python3 -c "import utility_mcp_server" 2>/dev/null || pip install utility-mcp-server
46+
```
47+
48+
### 4. Create Generation Script
49+
50+
Save to `artifacts/release-notes/generate_<version>.py`:
51+
52+
```python
53+
#!/usr/bin/env python3
54+
import asyncio
55+
import json
56+
from pathlib import Path
57+
from utility_mcp_server.src.tools.release_notes_tool import generate_release_notes
58+
59+
async def main():
60+
# Ensure output directory exists
61+
Path("artifacts/release-notes").mkdir(parents=True, exist_ok=True)
62+
63+
# Generate release notes
64+
result = await generate_release_notes(
65+
version="<VERSION>",
66+
previous_version="<PREVIOUS_VERSION>",
67+
repo_path="<REPO_PATH>",
68+
repo_url="<REPO_URL>",
69+
release_date=None # Uses today's date
70+
)
71+
72+
if result.get("status") == "success":
73+
# Save release notes
74+
notes_file = "artifacts/release-notes/RELEASE_NOTES_<VERSION>.md"
75+
with open(notes_file, "w") as f:
76+
f.write(result["release_notes"])
77+
print(f"✅ Release notes saved to: {notes_file}")
78+
79+
# Save statistics
80+
if "statistics" in result:
81+
stats_file = "artifacts/release-notes/stats_<VERSION>.json"
82+
with open(stats_file, "w") as f:
83+
json.dump(result["statistics"], f, indent=2)
84+
print(f"✅ Statistics saved to: {stats_file}")
85+
86+
# Display release notes
87+
print("\n" + "="*80)
88+
print(result["release_notes"])
89+
print("="*80 + "\n")
90+
91+
# Display statistics
92+
if "statistics" in result:
93+
print("📊 Statistics:")
94+
for key, value in result["statistics"].items():
95+
print(f" {key}: {value}")
96+
97+
return result
98+
else:
99+
error_msg = result.get("error", "Unknown error")
100+
print(f"❌ Error: {error_msg}")
101+
return result
102+
103+
if __name__ == "__main__":
104+
asyncio.run(main())
105+
```
106+
107+
### 5. Execute
108+
109+
```bash
110+
cd artifacts/release-notes && python3 generate_<version>.py
111+
```
112+
113+
### 6. Present Results
114+
115+
Show the user:
116+
1. Generated release notes (formatted)
117+
2. Statistics summary
118+
3. File locations
119+
4. Next steps
120+
121+
## Output
122+
123+
Files created in `artifacts/release-notes/`:
124+
- `RELEASE_NOTES_<version>.md` - Main release notes
125+
- `stats_<version>.json` - Statistics
126+
- `generate_<version>.py` - Generation script
127+
128+
## Error Handling
129+
130+
Handle gracefully:
131+
- Tags don't exist → List available tags
132+
- No commits → Explain possible causes
133+
- Not a git repo → Verify path
134+
- Installation fails → Check Python/pip
135+
136+
## Tips
137+
138+
Suggest to users:
139+
- Use conventional commits (`feat:`, `fix:`, etc.)
140+
- Include PR numbers in commits
141+
- Provide repository URL for links
142+
- Tag releases consistently
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
.Python
7+
env/
8+
venv/
9+
.venv/
10+
ENV/
11+
*.egg-info/
12+
dist/
13+
build/
14+
15+
# IDEs
16+
.vscode/
17+
.idea/
18+
*.swp
19+
*.swo
20+
*~
21+
.DS_Store
22+
23+
# Output artifacts (generated at runtime)
24+
artifacts/
25+
26+
# Logs
27+
*.log
28+
.claude/logs/
29+
30+
# Temporary files
31+
*.tmp
32+
.temp/
33+
tmp/
34+
35+
# Environment
36+
.env
37+
.env.local
38+
39+
# Test outputs
40+
test-output/
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# How to Add the /generate Command
2+
3+
The system has security restrictions that prevent automatic creation of files in `.claude/commands/`.
4+
5+
You'll need to add the command file manually. Here's how:
6+
7+
## Quick Method
8+
9+
I've created the command content for you at:
10+
```
11+
/workspace/artifacts/release-notes-workflow/generate_command_temp.md
12+
```
13+
14+
**Simply rename and move it:**
15+
16+
```bash
17+
cd /workspace/artifacts/release-notes-workflow
18+
mv generate_command_temp.md .claude/commands/generate.md
19+
```
20+
21+
## Alternative: Create Directly in Git
22+
23+
If you've already pushed to GitHub and are working in a clone:
24+
25+
```bash
26+
cd /path/to/your/workflows-repo/workflows/release-notes-generator
27+
28+
# Create the file directly
29+
cat > .claude/commands/generate.md << 'EOF'
30+
# /generate - Generate Release Notes
31+
32+
Generate structured release notes from git commits between two version tags with automatic categorization.
33+
34+
## Usage
35+
36+
\`\`\`
37+
/generate [current_version] [previous_version] [repo_path] [repo_url]
38+
\`\`\`
39+
40+
All parameters are optional - if not provided, you'll be prompted conversationally.
41+
42+
## Examples
43+
44+
\`\`\`
45+
/generate v1.0.0 v0.9.0
46+
/generate v2.0.0 v1.9.0 /path/to/repo
47+
/generate v1.5.0 v1.4.0 /path/to/repo https://github.com/org/repo
48+
\`\`\`
49+
50+
## Process
51+
52+
### 1. Gather Information
53+
54+
Collect from user (if not in command):
55+
- Current version tag (required)
56+
- Previous version tag (optional)
57+
- Repository path (optional, defaults to current directory)
58+
- Repository URL (optional, for clickable links)
59+
60+
### 2. Validate Environment
61+
62+
\`\`\`bash
63+
# Verify git repository
64+
git -C <repo_path> status
65+
66+
# List and verify tags
67+
git -C <repo_path> tag -l
68+
git -C <repo_path> tag -l | grep -x <version>
69+
\`\`\`
70+
71+
### 3. Install Tool
72+
73+
\`\`\`bash
74+
python3 -c "import utility_mcp_server" 2>/dev/null || pip install utility-mcp-server
75+
\`\`\`
76+
77+
### 4. Create Generation Script
78+
79+
Save to \`artifacts/release-notes/generate_<version>.py\`:
80+
81+
\`\`\`python
82+
#!/usr/bin/env python3
83+
import asyncio
84+
import json
85+
from pathlib import Path
86+
from utility_mcp_server.src.tools.release_notes_tool import generate_release_notes
87+
88+
async def main():
89+
# Ensure output directory exists
90+
Path("artifacts/release-notes").mkdir(parents=True, exist_ok=True)
91+
92+
# Generate release notes
93+
result = await generate_release_notes(
94+
version="<VERSION>",
95+
previous_version="<PREVIOUS_VERSION>",
96+
repo_path="<REPO_PATH>",
97+
repo_url="<REPO_URL>",
98+
release_date=None # Uses today's date
99+
)
100+
101+
if result.get("status") == "success":
102+
# Save release notes
103+
notes_file = "artifacts/release-notes/RELEASE_NOTES_<VERSION>.md"
104+
with open(notes_file, "w") as f:
105+
f.write(result["release_notes"])
106+
print(f"✅ Release notes saved to: {notes_file}")
107+
108+
# Save statistics
109+
if "statistics" in result:
110+
stats_file = "artifacts/release-notes/stats_<VERSION>.json"
111+
with open(stats_file, "w") as f:
112+
json.dump(result["statistics"], f, indent=2)
113+
print(f"✅ Statistics saved to: {stats_file}")
114+
115+
# Display release notes
116+
print("\n" + "="*80)
117+
print(result["release_notes"])
118+
print("="*80 + "\n")
119+
120+
# Display statistics
121+
if "statistics" in result:
122+
print("📊 Statistics:")
123+
for key, value in result["statistics"].items():
124+
print(f" {key}: {value}")
125+
126+
return result
127+
else:
128+
error_msg = result.get("error", "Unknown error")
129+
print(f"❌ Error: {error_msg}")
130+
return result
131+
132+
if __name__ == "__main__":
133+
asyncio.run(main())
134+
\`\`\`
135+
136+
### 5. Execute
137+
138+
\`\`\`bash
139+
cd artifacts/release-notes && python3 generate_<version>.py
140+
\`\`\`
141+
142+
### 6. Present Results
143+
144+
Show the user:
145+
1. Generated release notes (formatted)
146+
2. Statistics summary
147+
3. File locations
148+
4. Next steps
149+
150+
## Output
151+
152+
Files created in \`artifacts/release-notes/\`:
153+
- \`RELEASE_NOTES_<version>.md\` - Main release notes
154+
- \`stats_<version>.json\` - Statistics
155+
- \`generate_<version>.py\` - Generation script
156+
157+
## Error Handling
158+
159+
Handle gracefully:
160+
- Tags don't exist → List available tags
161+
- No commits → Explain possible causes
162+
- Not a git repo → Verify path
163+
- Installation fails → Check Python/pip
164+
165+
## Tips
166+
167+
Suggest to users:
168+
- Use conventional commits (\`feat:\`, \`fix:\`, etc.)
169+
- Include PR numbers in commits
170+
- Provide repository URL for links
171+
- Tag releases consistently
172+
EOF
173+
174+
# Commit it
175+
git add .claude/commands/generate.md
176+
git commit -m "feat: Add /generate command"
177+
```
178+
179+
## Verify
180+
181+
Check that the file was created:
182+
183+
```bash
184+
ls -la .claude/commands/
185+
cat .claude/commands/generate.md
186+
```
187+
188+
## Why is this file important?
189+
190+
The `/generate` command allows users to invoke the release notes generation with a slash command instead of just conversational mode. It's optional but provides a nice shortcut.
191+
192+
**Without it**: Workflow still works conversationally
193+
**With it**: Users can type `/generate v1.0.0 v0.9.0` for quick invocation
194+
195+
## Next Steps
196+
197+
Once you've added the command file:
198+
199+
1. Commit all changes
200+
2. Push to GitHub
201+
3. Test with Custom Workflow in ACP
202+
4. Verify `/generate` command appears and works

0 commit comments

Comments
 (0)