diff --git a/.bash_aliases.d/ai-providers.sh b/.bash_aliases.d/ai-providers.sh index 299cc7c0..420a3e67 100644 --- a/.bash_aliases.d/ai-providers.sh +++ b/.bash_aliases.d/ai-providers.sh @@ -1,4 +1,13 @@ DOT_DEN="${DOT_DEN:-$HOME/ppv/pillars/dotfiles}" alias claude='claude --mcp-config "$DOT_DEN/mcp/mcp.json" --add-dir "$DOT_DEN/knowledge"' -alias q='q --mcp-config "$DOT_DEN/mcp/mcp.json" --add-dir "$DOT_DEN/knowledge"' \ No newline at end of file + +# Amazon Q trusted tools (mirrors Claude's .claude/settings.json trusted tools) +TRUSTED_TOOLS="mcp__git__git_status,mcp__git__git_diff,mcp__git__git_diff_staged,mcp__git__git_diff_unstaged,mcp__git__git_log,mcp__git__git_show,mcp__git__git_fetch,mcp__git__git_branch,mcp__git__git_blame,mcp__git__git_describe,mcp__git__git_shortlog,mcp__git__git_reflog,mcp__git__git_worktree_list,mcp__git__git_remote,mcp__git__git_add,mcp__git__git_commit,mcp__git__git_checkout,mcp__git__git_create_branch,mcp__git__git_stash,mcp__git__git_stash_pop,mcp__github-read,mcp__brave-search,mcp__filesystem,mcp__awslabs.aws-documentation-mcp-server,mcp__gdrive" + +# Add work-specific tools if on work machine +if [ "${WORK_MACHINE:-false}" = "true" ]; then + TRUSTED_TOOLS="$TRUSTED_TOOLS,mcp__atlassian,mcp__gitlab" +fi + +alias q='q chat --trust-tools="$TRUSTED_TOOLS" --mcp-config "$DOT_DEN/mcp/mcp.json" --add-dir "$DOT_DEN/knowledge"' \ No newline at end of file diff --git a/README.md b/README.md index da6fb894..80d3df8c 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,15 @@ The dotfiles include pre-configured MCP servers for: Work-specific servers (Atlassian, GitLab) require `WORK_MACHINE=true` in `~/.bash_exports.local`. +### Claude Model Preferences + +Personal machines automatically use the Opus model (claude-opus-4-20250514) for maximum capability. This is controlled by the `WORK_MACHINE` environment variable: + +- **Personal machines**: Set `WORK_MACHINE="false"` in `~/.bash_exports.local` → Opus model by default +- **Work machines**: Set `WORK_MACHINE="true"` → Standard model selection + +No manual model switching required - the correct model is automatically selected based on your machine type. + ## Secret Management Sensitive information like API tokens are stored in `~/.bash_secrets` (not tracked in git). diff --git a/knowledge/procedures/mcp-prompts.md b/knowledge/procedures/mcp-prompts.md index 3abd5247..916554cd 100644 --- a/knowledge/procedures/mcp-prompts.md +++ b/knowledge/procedures/mcp-prompts.md @@ -1,6 +1,9 @@ # MCP Prompts -To add prompts to Amazon Q CLI, add them to your MCP servers. +**Amazon Q CLI:** `'@close-issue 934'` (single quotes required) +**Claude Code:** `/close-issue 934` (slash commands, better autocomplete) + +Both use the same MCP servers from `mcp/mcp.json` - just different syntax. → [MCP Prompts PoC](~/ppv/pillars/dotfiles/mcp/prompts/README.md) diff --git a/mcp/servers/git-mcp-server/src/mcp_server_git/server.py b/mcp/servers/git-mcp-server/src/mcp_server_git/server.py index 39a423c7..d3624ce0 100644 --- a/mcp/servers/git-mcp-server/src/mcp_server_git/server.py +++ b/mcp/servers/git-mcp-server/src/mcp_server_git/server.py @@ -1,5 +1,6 @@ import logging import os +import re from enum import Enum from pathlib import Path from typing import Sequence @@ -1836,6 +1837,17 @@ async def list_prompts() -> list[Prompt]: required=False ) ] + ), + Prompt( + name="close-issue", + description="Complete and implement a GitHub issue with git workflow", + arguments=[ + PromptArgument( + name="issue_number", + description="GitHub issue number to close", + required=True + ) + ] ) ] @@ -2021,6 +2033,77 @@ async def get_prompt(name: str, arguments: dict | None = None) -> GetPromptResul ] ) + elif name == "close-issue": + # Extract issue number from arguments + issue_number = arguments.get("issue_number") if arguments else None + + if not issue_number: + return GetPromptResult( + description="Error: issue_number is required", + messages=[ + PromptMessage( + role="user", + content=TextContent( + type="text", + text="Error: issue_number argument is required for close-issue prompt" + ) + ) + ] + ) + + # Read the close-issue template + try: + # Try to get dotfiles path from environment or use relative path + dot_den = os.getenv("DOT_DEN") + if dot_den: + dotfiles_path = Path(dot_den) + else: + # Try to find dotfiles relative to current working directory + cwd = Path.cwd() + if "dotfiles" in str(cwd): + # Find the dotfiles root + dotfiles_path = cwd + while dotfiles_path.name != "dotfiles" and dotfiles_path.parent != dotfiles_path: + dotfiles_path = dotfiles_path.parent + else: + # Fallback to home directory location + dotfiles_path = Path.home() / "ppv" / "pillars" / "dotfiles" + + template_path = dotfiles_path / "commands" / "templates" / "close-issue.md" + with open(template_path, 'r') as f: + template_content = f.read() + + # Replace the placeholder with the actual issue number + prompt_text = template_content.replace("{{ ISSUE_NUMBER }}", str(issue_number)) + + # Process INJECT directives + inject_pattern = r'\{\{ INJECT:([^}]+) \}\}' + + def process_inject(match): + inject_path = match.group(1) + knowledge_base = dotfiles_path / "knowledge" + full_path = knowledge_base / inject_path + try: + with open(full_path, 'r') as f: + return f.read() + except Exception: + return f"[Unable to inject {inject_path}]" + + prompt_text = re.sub(inject_pattern, process_inject, prompt_text) + + except Exception as e: + prompt_text = f"Error reading close-issue template: {str(e)}" + + return GetPromptResult( + description=f"Complete and implement GitHub issue #{issue_number}", + messages=[ + PromptMessage( + role="user", + content=TextContent(type="text", text=prompt_text) + ) + ] + ) + else: return GetPromptResult( description=f"Unknown prompt: {name}", @@ -2029,7 +2112,7 @@ async def get_prompt(name: str, arguments: dict | None = None) -> GetPromptResul role="user", content=TextContent( type="text", - text=f"Unknown prompt: {name}. Available prompts: commit-message, pr-description" + text=f"Unknown prompt: {name}. Available prompts: commit-message, pr-description, close-issue" ) ) ]