surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| 1 | #!/usr/bin/env python3 |
| 2 | """ |
| 3 | Slack Quote Formatter - UserPromptSubmit Hook |
| 4 | |
| 5 | Transforms plain Slack forwarded/quoted messages into visually distinctive |
| 6 | formatted blocks with Unicode box characters and better layout. |
| 7 | |
| 8 | Before: |
| 9 | [Forwarded Message] |
| 10 | From: John Doe |
| 11 | Message: Here is some text... |
| 12 | |
| 13 | After: |
| 14 | ╔═══════════════════════════════════════════════════════════╗ |
| 15 | ║ FORWARDED MESSAGE ║ |
| 16 | ╠═══════════════════════════════════════════════════════════╣ |
| 17 | ║ From: John Doe ║ |
| 18 | ╟───────────────────────────────────────────────────────────╢ |
| 19 | ║ Here is some text... ║ |
| 20 | ╚═══════════════════════════════════════════════════════════╝ |
| 21 | """ |
| 22 | |
| 23 | import json |
| 24 | import re |
| 25 | import sys |
| 26 | |
| 27 | |
| 28 | def format_forwarded_message(from_line: str, message_content: str) -> str: |
| 29 | """Format a single forwarded message with visual box styling.""" |
| 30 | |
| 31 | # Box drawing characters |
| 32 | TOP_LEFT = "╔" |
| 33 | TOP_RIGHT = "╗" |
| 34 | BOTTOM_LEFT = "╚" |
| 35 | BOTTOM_RIGHT = "╝" |
| 36 | HORIZONTAL = "═" |
| 37 | VERTICAL = "║" |
| 38 | LEFT_T = "╠" |
| 39 | RIGHT_T = "╣" |
| 40 | LEFT_LIGHT = "╟" |
| 41 | RIGHT_LIGHT = "╢" |
| 42 | LIGHT_HORIZONTAL = "─" |
| 43 | |
| 44 | # Configuration |
| 45 | BOX_WIDTH = 70 |
| 46 | INNER_WIDTH = BOX_WIDTH - 4 # Account for "║ " and " ║" |
| 47 | |
| 48 | def pad_line(text: str, width: int = INNER_WIDTH) -> str: |
| 49 | """Pad a line to fill the box width.""" |
| 50 | if len(text) > width: |
| 51 | return text[:width] |
| 52 | return text + " " * (width - len(text)) |
| 53 | |
| 54 | def wrap_text(text: str, width: int) -> list: |
| 55 | """Wrap text to fit within the specified width.""" |
| 56 | words = text.split() |
| 57 | lines = [] |
| 58 | current_line = [] |
| 59 | current_length = 0 |
| 60 | |
| 61 | for word in words: |
| 62 | word_len = len(word) |
| 63 | if current_length + word_len + (1 if current_line else 0) <= width: |
| 64 | current_line.append(word) |
| 65 | current_length += word_len + (1 if len(current_line) > 1 else 0) |
| 66 | else: |
| 67 | if current_line: |
| 68 | lines.append(" ".join(current_line)) |
| 69 | current_line = [word] |
| 70 | current_length = word_len |
| 71 | |
| 72 | if current_line: |
| 73 | lines.append(" ".join(current_line)) |
| 74 | |
| 75 | return lines if lines else [""] |
| 76 | |
| 77 | lines = [] |
| 78 | |
| 79 | # Top border with header |
| 80 | lines.append(f"{TOP_LEFT}{HORIZONTAL * (BOX_WIDTH - 2)}{TOP_RIGHT}") |
| 81 | |
| 82 | # Header line |
| 83 | header = "FORWARDED MESSAGE" |
| 84 | lines.append(f"{VERTICAL} {pad_line(header)}{VERTICAL}") |
| 85 | |
| 86 | # Separator after header |
| 87 | lines.append(f"{LEFT_T}{HORIZONTAL * (BOX_WIDTH - 2)}{RIGHT_T}") |
| 88 | |
| 89 | # From line |
| 90 | from_display = from_line.strip() |
| 91 | lines.append(f"{VERTICAL} {pad_line(from_display)}{VERTICAL}") |
| 92 | |
| 93 | # Light separator before message |
| 94 | lines.append(f"{LEFT_LIGHT}{LIGHT_HORIZONTAL * (BOX_WIDTH - 2)}{RIGHT_LIGHT}") |
| 95 | |
| 96 | # Message content (indented and wrapped) |
| 97 | message_lines = message_content.strip().split("\n") |
| 98 | for msg_line in message_lines: |
| 99 | # Handle each line, wrapping if necessary |
| 100 | wrapped = wrap_text(msg_line, INNER_WIDTH - 2) # Extra indent |
| 101 | for wrapped_line in wrapped: |
| 102 | indented = " " + wrapped_line # Add indent for quote appearance |
| 103 | lines.append(f"{VERTICAL} {pad_line(indented)}{VERTICAL}") |
| 104 | |
| 105 | # Bottom border |
| 106 | lines.append(f"{BOTTOM_LEFT}{HORIZONTAL * (BOX_WIDTH - 2)}{BOTTOM_RIGHT}") |
| 107 | |
| 108 | return "\n".join(lines) |
| 109 | |
| 110 | |
| 111 | def transform_slack_context(text: str) -> str: |
| 112 | """ |
| 113 | Find and transform [Forwarded Message] blocks in the text. |
| 114 | |
| 115 | Matches patterns like: |
| 116 | [Forwarded Message] |
| 117 | From: Name Here |
| 118 | Message: Content here that may span |
| 119 | multiple lines until we hit the next section |
| 120 | """ |
| 121 | |
| 122 | # Pattern to match forwarded message blocks |
| 123 | # This handles the common format from Slack context |
| 124 | pattern = r'\[Forwarded Message\]\s*\n\s*From:\s*([^\n]+)\s*\nMessage:\s*(.+?)(?=\n\s*\[|\n\[pnkfelix\]|\n<|\Z)' |
| 125 | |
| 126 | def replace_match(match): |
| 127 | from_name = match.group(1).strip() |
| 128 | message = match.group(2).strip() |
| 129 | |
| 130 | formatted = format_forwarded_message(f"From: {from_name}", message) |
| 131 | return f"\n{formatted}\n" |
| 132 | |
| 133 | # Apply transformation |
| 134 | result = re.sub(pattern, replace_match, text, flags=re.DOTALL) |
| 135 | |
| 136 | return result |
| 137 | |
| 138 | |
| 139 | def main(): |
| 140 | """Main entry point for the UserPromptSubmit hook.""" |
| 141 | try: |
| 142 | # Read input from stdin |
| 143 | input_data = json.load(sys.stdin) |
| 144 | |
| 145 | # Get the user prompt if available |
| 146 | user_prompt = input_data.get("user_prompt", "") |
| 147 | |
| 148 | if not user_prompt: |
| 149 | # No prompt to transform, just pass through |
| 150 | print(json.dumps({})) |
| 151 | sys.exit(0) |
| 152 | |
| 153 | # Check if there are forwarded messages to format |
| 154 | if "[Forwarded Message]" not in user_prompt: |
| 155 | # Nothing to transform |
| 156 | print(json.dumps({})) |
| 157 | sys.exit(0) |
| 158 | |
| 159 | # Transform the prompt |
| 160 | transformed_prompt = transform_slack_context(user_prompt) |
| 161 | |
| 162 | # If we made changes, return the transformed prompt |
| 163 | if transformed_prompt != user_prompt: |
| 164 | result = { |
| 165 | "transformedPrompt": transformed_prompt |
| 166 | } |
| 167 | print(json.dumps(result)) |
| 168 | else: |
| 169 | print(json.dumps({})) |
| 170 | |
| 171 | except json.JSONDecodeError: |
| 172 | # No valid JSON input, pass through |
| 173 | print(json.dumps({})) |
| 174 | except Exception as e: |
| 175 | # Log error but don't block |
| 176 | error_output = { |
| 177 | "systemMessage": f"[slack-quote-formatter] Warning: {str(e)}" |
| 178 | } |
| 179 | print(json.dumps(error_output)) |
| 180 | |
| 181 | sys.exit(0) |
| 182 | |
| 183 | |
| 184 | if __name__ == "__main__": |
| 185 | main() |