roastbuddy 0.1.0__py3-none-any.whl

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.
roastbuddy/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """RoastBuddy - Your witty coding companion."""
2
+
3
+ __version__ = "0.1.0"
4
+ __author__ = "RoastBuddy Team"
5
+ __description__ = "A fun, interactive CLI companion that roasts and praises your code"
roastbuddy/cli.py ADDED
@@ -0,0 +1,113 @@
1
+ """Main CLI entry point for RoastBuddy."""
2
+
3
+ import click
4
+ from rich.console import Console
5
+
6
+ console = Console()
7
+
8
+
9
+ @click.group()
10
+ @click.version_option(version="0.1.0", prog_name="roastbuddy")
11
+ def main():
12
+ """šŸ”„ RoastBuddy - Your witty coding companion!
13
+
14
+ Roasts, praises, and tracks your development journey.
15
+ """
16
+ pass
17
+
18
+
19
+ @main.command()
20
+ @click.option("--path", default=".", help="Path to git repository")
21
+ def init(path):
22
+ """Initialize RoastBuddy in a git repository."""
23
+ from roastbuddy.core.initializer import initialize_roastbuddy
24
+
25
+ console.print("[bold cyan]šŸ”„ Initializing RoastBuddy...[/bold cyan]")
26
+ success = initialize_roastbuddy(path)
27
+
28
+ if success:
29
+ console.print("[bold green]āœ… RoastBuddy is ready to roast![/bold green]")
30
+ console.print("\nšŸ’” Try: [bold]roastbuddy status[/bold]")
31
+ else:
32
+ console.print("[bold red]āŒ Failed to initialize RoastBuddy[/bold red]")
33
+
34
+
35
+ @main.command()
36
+ def status():
37
+ """Show current streaks and recent activity."""
38
+ from roastbuddy.core.status import show_status
39
+
40
+ console.print("[bold cyan]šŸ“Š RoastBuddy Status[/bold cyan]\n")
41
+ show_status()
42
+
43
+
44
+ @main.command()
45
+ @click.option("--last", "-l", is_flag=True, help="Roast the last commit")
46
+ def roast(last):
47
+ """Roast your code with humor."""
48
+ from roastbuddy.core.roaster import roast_code
49
+
50
+ console.print("[bold red]šŸ”„ Preparing your roast...[/bold red]\n")
51
+ roast_code(last_commit=last)
52
+
53
+
54
+ @main.command()
55
+ @click.option("--last", "-l", is_flag=True, help="Praise the last commit")
56
+ def praise(last):
57
+ """Get some well-deserved praise!"""
58
+ from roastbuddy.core.roaster import praise_code
59
+
60
+ console.print("[bold green]✨ Preparing your praise...[/bold green]\n")
61
+ praise_code(last_commit=last)
62
+
63
+
64
+ @main.command()
65
+ @click.option("--type", "-t", type=click.Choice(["all", "clean", "daily", "test"]),
66
+ default="all", help="Streak type to display")
67
+ def streak(type):
68
+ """View your coding streaks."""
69
+ from roastbuddy.core.streaks import show_streaks
70
+
71
+ console.print("[bold magenta]šŸ”„ Your Coding Streaks[/bold magenta]\n")
72
+ show_streaks(streak_type=type)
73
+
74
+
75
+ @main.command()
76
+ @click.option("--limit", "-n", default=10, help="Number of entries to show")
77
+ def history(limit):
78
+ """View roast and praise history."""
79
+ from roastbuddy.core.history import show_history
80
+
81
+ console.print("[bold cyan]šŸ“œ RoastBuddy History[/bold cyan]\n")
82
+ show_history(limit=limit)
83
+
84
+
85
+ @main.command()
86
+ @click.option("--format", "-f", type=click.Choice(["linkedin", "twitter", "github"]),
87
+ default="linkedin", help="Output format")
88
+ def share(format):
89
+ """Generate shareable social media content."""
90
+ from roastbuddy.core.share import generate_shareable
91
+
92
+ console.print(f"[bold cyan]šŸ“¤ Generating {format} content...[/bold cyan]\n")
93
+ generate_shareable(format_type=format)
94
+
95
+
96
+ @main.command()
97
+ @click.option("--show", is_flag=True, help="Show current configuration")
98
+ @click.option("--set", "set_value", nargs=2, help="Set config value (key value)")
99
+ def config(show, set_value):
100
+ """Manage RoastBuddy configuration."""
101
+ from roastbuddy.core.config import show_config, set_config
102
+
103
+ if show:
104
+ show_config()
105
+ elif set_value:
106
+ key, value = set_value
107
+ set_config(key, value)
108
+ else:
109
+ console.print("[yellow]Use --show or --set to manage configuration[/yellow]")
110
+
111
+
112
+ if __name__ == "__main__":
113
+ main()
@@ -0,0 +1 @@
1
+ """Core __init__ file for roastbuddy.core package."""
@@ -0,0 +1,96 @@
1
+ """Configuration management for RoastBuddy."""
2
+
3
+ import os
4
+ import yaml
5
+ from pathlib import Path
6
+ from typing import Dict, Any
7
+ from rich.console import Console
8
+ from rich.table import Table
9
+
10
+ console = Console()
11
+
12
+ DEFAULT_CONFIG = {
13
+ "roast_intensity": "medium", # light, medium, spicy
14
+ "auto_roast_on_commit": False,
15
+ "use_copilot": "auto", # auto, always, never
16
+ "enable_streaks": True,
17
+ "show_emojis": True,
18
+ "color_output": True,
19
+ }
20
+
21
+ CONFIG_DIR = Path.home() / ".roastbuddy"
22
+ CONFIG_FILE = CONFIG_DIR / "config.yaml"
23
+
24
+
25
+ def get_config_dir() -> Path:
26
+ """Get or create the RoastBuddy config directory."""
27
+ CONFIG_DIR.mkdir(exist_ok=True)
28
+ return CONFIG_DIR
29
+
30
+
31
+ def get_config_file() -> Path:
32
+ """Get the config file path."""
33
+ return CONFIG_FILE
34
+
35
+
36
+ def load_config() -> Dict[str, Any]:
37
+ """Load configuration from file or return defaults."""
38
+ if not CONFIG_FILE.exists():
39
+ return DEFAULT_CONFIG.copy()
40
+
41
+ try:
42
+ with open(CONFIG_FILE, "r") as f:
43
+ config = yaml.safe_load(f) or {}
44
+ return {**DEFAULT_CONFIG, **config}
45
+ except Exception as e:
46
+ console.print(f"[yellow]Warning: Failed to load config: {e}[/yellow]")
47
+ return DEFAULT_CONFIG.copy()
48
+
49
+
50
+ def save_config(config: Dict[str, Any]) -> bool:
51
+ """Save configuration to file."""
52
+ try:
53
+ get_config_dir()
54
+ with open(CONFIG_FILE, "w") as f:
55
+ yaml.dump(config, f, default_flow_style=False)
56
+ return True
57
+ except Exception as e:
58
+ console.print(f"[red]Error saving config: {e}[/red]")
59
+ return False
60
+
61
+
62
+ def show_config():
63
+ """Display current configuration."""
64
+ config = load_config()
65
+
66
+ table = Table(title="RoastBuddy Configuration")
67
+ table.add_column("Setting", style="cyan")
68
+ table.add_column("Value", style="green")
69
+
70
+ for key, value in config.items():
71
+ table.add_row(key, str(value))
72
+
73
+ console.print(table)
74
+ console.print(f"\nšŸ“ Config file: [cyan]{CONFIG_FILE}[/cyan]")
75
+
76
+
77
+ def set_config(key: str, value: str):
78
+ """Set a configuration value."""
79
+ config = load_config()
80
+
81
+ # Type conversion
82
+ if value.lower() in ["true", "false"]:
83
+ value = value.lower() == "true"
84
+
85
+ config[key] = value
86
+
87
+ if save_config(config):
88
+ console.print(f"[green]āœ… Set {key} = {value}[/green]")
89
+ else:
90
+ console.print(f"[red]āŒ Failed to set configuration[/red]")
91
+
92
+
93
+ def get_config_value(key: str, default: Any = None) -> Any:
94
+ """Get a single configuration value."""
95
+ config = load_config()
96
+ return config.get(key, default)
@@ -0,0 +1,198 @@
1
+ """Database management for RoastBuddy."""
2
+
3
+ import sqlite3
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ from typing import Optional, Dict, Any, List
7
+ from roastbuddy.core.config import get_config_dir
8
+
9
+ DB_FILE = get_config_dir() / "roastbuddy.db"
10
+
11
+
12
+ def get_db_connection() -> sqlite3.Connection:
13
+ """Get a database connection."""
14
+ conn = sqlite3.connect(DB_FILE)
15
+ conn.row_factory = sqlite3.Row
16
+ return conn
17
+
18
+
19
+ def initialize_database():
20
+ """Initialize the database schema."""
21
+ conn = get_db_connection()
22
+ cursor = conn.cursor()
23
+
24
+ # Commits table
25
+ cursor.execute("""
26
+ CREATE TABLE IF NOT EXISTS commits (
27
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
28
+ commit_hash TEXT UNIQUE NOT NULL,
29
+ message TEXT NOT NULL,
30
+ author TEXT NOT NULL,
31
+ timestamp DATETIME NOT NULL,
32
+ files_changed INTEGER DEFAULT 0,
33
+ lines_added INTEGER DEFAULT 0,
34
+ lines_deleted INTEGER DEFAULT 0,
35
+ is_clean BOOLEAN DEFAULT 0,
36
+ repo_path TEXT NOT NULL
37
+ )
38
+ """)
39
+
40
+ # Streaks table
41
+ cursor.execute("""
42
+ CREATE TABLE IF NOT EXISTS streaks (
43
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
44
+ streak_type TEXT NOT NULL,
45
+ current_count INTEGER DEFAULT 0,
46
+ best_count INTEGER DEFAULT 0,
47
+ last_updated DATETIME NOT NULL,
48
+ repo_path TEXT NOT NULL
49
+ )
50
+ """)
51
+
52
+ # Roasts and praise history
53
+ cursor.execute("""
54
+ CREATE TABLE IF NOT EXISTS interactions (
55
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
56
+ interaction_type TEXT NOT NULL,
57
+ content TEXT NOT NULL,
58
+ commit_hash TEXT,
59
+ timestamp DATETIME NOT NULL,
60
+ source TEXT NOT NULL,
61
+ repo_path TEXT NOT NULL
62
+ )
63
+ """)
64
+
65
+ # Achievements/milestones
66
+ cursor.execute("""
67
+ CREATE TABLE IF NOT EXISTS achievements (
68
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
69
+ achievement_type TEXT NOT NULL,
70
+ description TEXT NOT NULL,
71
+ earned_at DATETIME NOT NULL,
72
+ repo_path TEXT NOT NULL
73
+ )
74
+ """)
75
+
76
+ conn.commit()
77
+ conn.close()
78
+
79
+
80
+ def add_commit_record(commit_data: Dict[str, Any]) -> bool:
81
+ """Add a commit record to the database."""
82
+ try:
83
+ conn = get_db_connection()
84
+ cursor = conn.cursor()
85
+
86
+ cursor.execute("""
87
+ INSERT OR REPLACE INTO commits
88
+ (commit_hash, message, author, timestamp, files_changed,
89
+ lines_added, lines_deleted, is_clean, repo_path)
90
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
91
+ """, (
92
+ commit_data.get("hash"),
93
+ commit_data.get("message"),
94
+ commit_data.get("author"),
95
+ commit_data.get("timestamp"),
96
+ commit_data.get("files_changed", 0),
97
+ commit_data.get("lines_added", 0),
98
+ commit_data.get("lines_deleted", 0),
99
+ commit_data.get("is_clean", False),
100
+ commit_data.get("repo_path"),
101
+ ))
102
+
103
+ conn.commit()
104
+ conn.close()
105
+ return True
106
+ except Exception as e:
107
+ print(f"Error adding commit: {e}")
108
+ return False
109
+
110
+
111
+ def add_interaction(interaction_type: str, content: str, commit_hash: Optional[str],
112
+ source: str, repo_path: str) -> bool:
113
+ """Add a roast/praise interaction to the database."""
114
+ try:
115
+ conn = get_db_connection()
116
+ cursor = conn.cursor()
117
+
118
+ cursor.execute("""
119
+ INSERT INTO interactions
120
+ (interaction_type, content, commit_hash, timestamp, source, repo_path)
121
+ VALUES (?, ?, ?, ?, ?, ?)
122
+ """, (
123
+ interaction_type,
124
+ content,
125
+ commit_hash,
126
+ datetime.now().isoformat(),
127
+ source,
128
+ repo_path
129
+ ))
130
+
131
+ conn.commit()
132
+ conn.close()
133
+ return True
134
+ except Exception as e:
135
+ print(f"Error adding interaction: {e}")
136
+ return False
137
+
138
+
139
+ def get_streak_data(streak_type: str, repo_path: str) -> Optional[Dict[str, Any]]:
140
+ """Get streak data for a specific type."""
141
+ conn = get_db_connection()
142
+ cursor = conn.cursor()
143
+
144
+ cursor.execute("""
145
+ SELECT * FROM streaks
146
+ WHERE streak_type = ? AND repo_path = ?
147
+ """, (streak_type, repo_path))
148
+
149
+ row = cursor.fetchone()
150
+ conn.close()
151
+
152
+ if row:
153
+ return dict(row)
154
+ return None
155
+
156
+
157
+ def update_streak(streak_type: str, current_count: int, best_count: int, repo_path: str) -> bool:
158
+ """Update or create a streak record."""
159
+ try:
160
+ conn = get_db_connection()
161
+ cursor = conn.cursor()
162
+
163
+ cursor.execute("""
164
+ INSERT OR REPLACE INTO streaks
165
+ (streak_type, current_count, best_count, last_updated, repo_path)
166
+ VALUES (?, ?, ?, ?, ?)
167
+ """, (
168
+ streak_type,
169
+ current_count,
170
+ best_count,
171
+ datetime.now().isoformat(),
172
+ repo_path
173
+ ))
174
+
175
+ conn.commit()
176
+ conn.close()
177
+ return True
178
+ except Exception as e:
179
+ print(f"Error updating streak: {e}")
180
+ return False
181
+
182
+
183
+ def get_recent_interactions(limit: int = 10, repo_path: str = ".") -> List[Dict[str, Any]]:
184
+ """Get recent roast/praise interactions."""
185
+ conn = get_db_connection()
186
+ cursor = conn.cursor()
187
+
188
+ cursor.execute("""
189
+ SELECT * FROM interactions
190
+ WHERE repo_path = ?
191
+ ORDER BY timestamp DESC
192
+ LIMIT ?
193
+ """, (repo_path, limit))
194
+
195
+ rows = cursor.fetchall()
196
+ conn.close()
197
+
198
+ return [dict(row) for row in rows]
@@ -0,0 +1,40 @@
1
+ """History display functionality."""
2
+
3
+ from rich.console import Console
4
+ from rich.panel import Panel
5
+ from rich.table import Table
6
+ from roastbuddy.core.database import get_recent_interactions
7
+ from roastbuddy.utils.git_utils import get_repo_path
8
+
9
+ console = Console()
10
+
11
+
12
+ def show_history(limit: int = 10):
13
+ """Show roast and praise history."""
14
+ repo_path = get_repo_path()
15
+ interactions = get_recent_interactions(limit=limit, repo_path=repo_path)
16
+
17
+ if not interactions:
18
+ console.print("[yellow]šŸ“œ No history yet![/yellow]")
19
+ console.print("[dim]Use [bold]roastbuddy roast[/bold] or [bold]roastbuddy praise[/bold] first![/dim]")
20
+ return
21
+
22
+ table = Table(title=f"šŸ“œ RoastBuddy History (last {len(interactions)})")
23
+ table.add_column("Type", style="cyan", width=8)
24
+ table.add_column("Content", style="white", width=60)
25
+ table.add_column("Source", style="dim", width=10)
26
+ table.add_column("Time", style="dim", width=16)
27
+
28
+ for interaction in interactions:
29
+ interaction_type = interaction["interaction_type"]
30
+ emoji = "šŸ”„" if interaction_type == "roast" else "✨"
31
+ type_str = f"{emoji} {interaction_type.title()}"
32
+
33
+ content = interaction["content"][:60] + "..." if len(interaction["content"]) > 60 else interaction["content"]
34
+
35
+ source = interaction["source"]
36
+ timestamp = interaction["timestamp"][:16] # Just date and time
37
+
38
+ table.add_row(type_str, content, source, timestamp)
39
+
40
+ console.print(table)
@@ -0,0 +1,61 @@
1
+ """Initializer for RoastBuddy."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from git import Repo, InvalidGitRepositoryError
6
+ from rich.console import Console
7
+ from roastbuddy.core.config import get_config_dir, save_config, DEFAULT_CONFIG
8
+ from roastbuddy.core.database import initialize_database
9
+
10
+ console = Console()
11
+
12
+
13
+ def is_git_repository(path: str) -> bool:
14
+ """Check if the path is a git repository."""
15
+ try:
16
+ Repo(path, search_parent_directories=True)
17
+ return True
18
+ except InvalidGitRepositoryError:
19
+ return False
20
+
21
+
22
+ def initialize_roastbuddy(path: str = ".") -> bool:
23
+ """Initialize RoastBuddy in a git repository."""
24
+ path = Path(path).resolve()
25
+
26
+ # Check if it's a git repository
27
+ if not is_git_repository(str(path)):
28
+ console.print(f"[red]āŒ {path} is not a git repository![/red]")
29
+ console.print("[yellow]šŸ’” Initialize git first: [bold]git init[/bold][/yellow]")
30
+ return False
31
+
32
+ try:
33
+ # Create config directory
34
+ config_dir = get_config_dir()
35
+ console.print(f"[dim]Creating config directory: {config_dir}[/dim]")
36
+
37
+ # Initialize database
38
+ console.print("[dim]Initializing database...[/dim]")
39
+ initialize_database()
40
+
41
+ # Save default configuration
42
+ console.print("[dim]Creating default configuration...[/dim]")
43
+ save_config(DEFAULT_CONFIG)
44
+
45
+ # Create .roastbuddy marker in repo
46
+ marker_file = path / ".roastbuddy"
47
+ if not marker_file.exists():
48
+ marker_file.touch()
49
+ console.print(f"[dim]Created repository marker: {marker_file}[/dim]")
50
+
51
+ console.print("\n[bold green]šŸŽ‰ RoastBuddy initialized successfully![/bold green]")
52
+ console.print("\n[cyan]Next steps:[/cyan]")
53
+ console.print(" • [bold]roastbuddy roast[/bold] - Get roasted!")
54
+ console.print(" • [bold]roastbuddy praise[/bold] - Get some praise")
55
+ console.print(" • [bold]roastbuddy status[/bold] - Check your stats")
56
+
57
+ return True
58
+
59
+ except Exception as e:
60
+ console.print(f"[red]āŒ Error during initialization: {e}[/red]")
61
+ return False
@@ -0,0 +1,130 @@
1
+ """Roasting and praising functionality."""
2
+
3
+ import random
4
+ from rich.console import Console
5
+ from rich.panel import Panel
6
+ from roastbuddy.utils.git_utils import find_git_repo, get_last_commit, get_repo_path
7
+ from roastbuddy.utils.copilot_utils import (
8
+ is_copilot_available,
9
+ generate_roast_with_copilot,
10
+ generate_praise_with_copilot,
11
+ suggest_copilot_install
12
+ )
13
+ from roastbuddy.templates.roast_templates import ROAST_TEMPLATES, get_roast_category
14
+ from roastbuddy.templates.praise_templates import PRAISE_TEMPLATES, get_praise_category
15
+ from roastbuddy.core.config import get_config_value
16
+ from roastbuddy.core.database import add_interaction
17
+
18
+ console = Console()
19
+
20
+
21
+ def roast_code(last_commit: bool = True):
22
+ """Generate a roast for the code."""
23
+ repo = find_git_repo()
24
+
25
+ if not repo:
26
+ console.print("[red]āŒ Not in a git repository![/red]")
27
+ console.print("[yellow]Initialize git first: [bold]git init[/bold][/yellow]")
28
+ return
29
+
30
+ commit_data = get_last_commit(repo)
31
+
32
+ if not commit_data:
33
+ console.print("[yellow]āš ļø No commits found yet![/yellow]")
34
+ console.print("[dim]Make your first commit and come back for a roast! šŸ”„[/dim]")
35
+ return
36
+
37
+ # Check if Copilot should be used
38
+ use_copilot = get_config_value("use_copilot", "auto")
39
+ copilot_available = is_copilot_available()
40
+
41
+ roast_text = None
42
+ source = "template"
43
+
44
+ # Try Copilot if configured
45
+ if use_copilot in ["auto", "always"] and copilot_available:
46
+ roast_text = generate_roast_with_copilot(commit_data)
47
+ source = "copilot"
48
+ if roast_text:
49
+ console.print("[dim]šŸ¤– Roast powered by GitHub Copilot[/dim]\n")
50
+
51
+ # Fallback to templates
52
+ if not roast_text:
53
+ if use_copilot == "always":
54
+ console.print("[yellow]āš ļø Copilot not available but set to 'always'[/yellow]")
55
+ suggest_copilot_install()
56
+ return
57
+
58
+ category = get_roast_category(commit_data)
59
+ roast_text = random.choice(ROAST_TEMPLATES.get(category, ROAST_TEMPLATES["default"]))
60
+
61
+ if not copilot_available and use_copilot == "auto":
62
+ console.print("[dim]šŸ’” Using built-in roasts (Copilot not available)[/dim]\n")
63
+
64
+ # Display the roast
65
+ console.print(Panel.fit(
66
+ f"[bold red]šŸ”„ Your Roast[/bold red]\n\n"
67
+ f"{roast_text}\n\n"
68
+ f"[dim]Commit: {commit_data['short_hash']} - {commit_data['message'][:50]}...[/dim]",
69
+ title="Roast",
70
+ border_style="red"
71
+ ))
72
+
73
+ # Save to database
74
+ add_interaction("roast", roast_text, commit_data["hash"], source, commit_data["repo_path"])
75
+
76
+
77
+ def praise_code(last_commit: bool = True):
78
+ """Generate praise for the code."""
79
+ repo = find_git_repo()
80
+
81
+ if not repo:
82
+ console.print("[red]āŒ Not in a git repository![/red]")
83
+ console.print("[yellow]Initialize git first: [bold]git init[/bold][/yellow]")
84
+ return
85
+
86
+ commit_data = get_last_commit(repo)
87
+
88
+ if not commit_data:
89
+ console.print("[yellow]āš ļø No commits found yet![/yellow]")
90
+ console.print("[dim]Make your first commit and come back for praise! ✨[/dim]")
91
+ return
92
+
93
+ # Check if Copilot should be used
94
+ use_copilot = get_config_value("use_copilot", "auto")
95
+ copilot_available = is_copilot_available()
96
+
97
+ praise_text = None
98
+ source = "template"
99
+
100
+ # Try Copilot if configured
101
+ if use_copilot in ["auto", "always"] and copilot_available:
102
+ praise_text = generate_praise_with_copilot(commit_data)
103
+ source = "copilot"
104
+ if praise_text:
105
+ console.print("[dim]šŸ¤– Praise powered by GitHub Copilot[/dim]\n")
106
+
107
+ # Fallback to templates
108
+ if not praise_text:
109
+ if use_copilot == "always":
110
+ console.print("[yellow]āš ļø Copilot not available but set to 'always'[/yellow]")
111
+ suggest_copilot_install()
112
+ return
113
+
114
+ category = get_praise_category(commit_data)
115
+ praise_text = random.choice(PRAISE_TEMPLATES.get(category, PRAISE_TEMPLATES["default"]))
116
+
117
+ if not copilot_available and use_copilot == "auto":
118
+ console.print("[dim]šŸ’” Using built-in praise (Copilot not available)[/dim]\n")
119
+
120
+ # Display the praise
121
+ console.print(Panel.fit(
122
+ f"[bold green]✨ Your Praise[/bold green]\n\n"
123
+ f"{praise_text}\n\n"
124
+ f"[dim]Commit: {commit_data['short_hash']} - {commit_data['message'][:50]}...[/dim]",
125
+ title="Praise",
126
+ border_style="green"
127
+ ))
128
+
129
+ # Save to database
130
+ add_interaction("praise", praise_text, commit_data["hash"], source, commit_data["repo_path"])
@@ -0,0 +1,18 @@
1
+ """Shareable content generation."""
2
+
3
+ from rich.console import Console
4
+ from rich.panel import Panel
5
+
6
+ console = Console()
7
+
8
+
9
+ def generate_shareable(format_type: str = "linkedin"):
10
+ """Generate shareable social media content."""
11
+ # TODO: Implement shareable content generation
12
+ console.print(Panel.fit(
13
+ f"[bold cyan]šŸ“¤ {format_type.title()} Content[/bold cyan]\n\n"
14
+ "[yellow]Shareable content generation coming soon![/yellow]\n"
15
+ "Will generate awesome posts for social media!",
16
+ title="Share",
17
+ border_style="cyan"
18
+ ))