gitgotchi 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.
src/pet/states.py ADDED
@@ -0,0 +1,116 @@
1
+ """Pet state machine."""
2
+ from datetime import datetime
3
+ from enum import Enum
4
+
5
+
6
+ class PetMood(Enum):
7
+ """Pet mood states - Stardew Valley inspired friendly moods."""
8
+
9
+ JOYFUL = "joyful" # Recent excellent commit
10
+ HAPPY = "happy" # Healthy regular activity
11
+ CONTENT = "content" # Baseline, all is well
12
+ HUNGRY = "hungry" # No commits in 24h
13
+ TIRED = "tired" # No commits in 3 days
14
+ SLEEPING = "sleeping" # No commits in 7 days (can be woken)
15
+
16
+
17
+ class PetForm(Enum):
18
+ """Pet evolution stages - FAST progression for quick feedback."""
19
+
20
+ EGG = "egg" # 0-2 commits
21
+ GHOST = "ghost" # 3-5 commits (default friendly spirit)
22
+ ANGEL = "angel" # 6+ commits, quality > 70
23
+ DEMON = "demon" # 6+ commits, quality < 30 (playful purple, not evil)
24
+ ZOMBIE = "zombie" # 4+ reverts (cute sleepy, needs coffee)
25
+ WRAITH = "wraith" # 15+ commits (ultimate ethereal form)
26
+
27
+
28
+ class PetStats:
29
+ """Pet statistics and state."""
30
+
31
+ def __init__(self) -> None:
32
+ """Initialize pet with default stats."""
33
+ self.total_commits: int = 0
34
+ self.lines_added: int = 0
35
+ self.lines_deleted: int = 0
36
+ self.merge_conflicts: int = 0
37
+ self.reverts: int = 0
38
+ self.quality_score: float = 50.0
39
+ self.last_fed: datetime = datetime.now()
40
+ self.current_mood: PetMood = PetMood.CONTENT
41
+ self.current_form: PetForm = PetForm.EGG
42
+ self.evolution_points: int = 0
43
+ self.friend_level: int = 1 # 1-10, Stardew Valley style
44
+ self.pet_name: str = "Spirit"
45
+
46
+ def update_mood(self) -> None:
47
+ """Update pet mood based on current stats and time."""
48
+ hours_since_fed = (datetime.now() - self.last_fed).total_seconds() / 3600
49
+
50
+ if hours_since_fed > 168: # 7 days
51
+ self.current_mood = PetMood.SLEEPING
52
+ elif hours_since_fed > 72: # 3 days
53
+ self.current_mood = PetMood.TIRED
54
+ elif hours_since_fed > 24: # 1 day
55
+ self.current_mood = PetMood.HUNGRY
56
+ elif self.quality_score > 80:
57
+ self.current_mood = PetMood.JOYFUL
58
+ elif self.quality_score > 60:
59
+ self.current_mood = PetMood.HAPPY
60
+ else:
61
+ self.current_mood = PetMood.CONTENT
62
+
63
+ def update_form(self) -> None:
64
+ """Update pet form - FAST evolution for quick feedback."""
65
+ # Fast progression: egg → ghost in 2-3 commits
66
+ if self.total_commits <= 2:
67
+ self.current_form = PetForm.EGG
68
+ # Zombie path: lots of reverts (cute sleepy form)
69
+ elif self.reverts >= 4:
70
+ self.current_form = PetForm.ZOMBIE
71
+ # Ultimate form: 15+ commits
72
+ elif self.total_commits >= 15:
73
+ self.current_form = PetForm.WRAITH
74
+ # Advanced forms: 6+ commits
75
+ elif self.total_commits >= 6:
76
+ if self.quality_score > 70:
77
+ self.current_form = PetForm.ANGEL
78
+ elif self.quality_score < 30:
79
+ self.current_form = PetForm.DEMON
80
+ else:
81
+ self.current_form = PetForm.GHOST
82
+ # Default friendly spirit: 3-5 commits
83
+ else:
84
+ self.current_form = PetForm.GHOST
85
+
86
+ def feed(self) -> None:
87
+ """Feed the pet (update last_fed timestamp)."""
88
+ self.last_fed = datetime.now()
89
+ self.update_mood()
90
+
91
+ def interact(self) -> str:
92
+ """Handle user interaction (pet, talk, play)."""
93
+ # Wake up if sleeping
94
+ if self.current_mood == PetMood.SLEEPING:
95
+ self.current_mood = PetMood.CONTENT
96
+ return "Your friend wakes up! They're happy to see you! ✨"
97
+
98
+ # Improve mood slightly
99
+ if self.current_mood == PetMood.TIRED:
100
+ self.current_mood = PetMood.CONTENT
101
+ elif self.current_mood == PetMood.HUNGRY:
102
+ self.current_mood = PetMood.CONTENT
103
+
104
+ # Increase friendship
105
+ self.friend_level = min(10, self.friend_level + 0.5)
106
+
107
+ responses = [
108
+ "Your friend sparkles with joy! ✨",
109
+ "They float happily around you! 💛",
110
+ "Your companion feels loved! 🌟",
111
+ "Friendship +0.5! Your bond grows stronger! ❤️",
112
+ ]
113
+
114
+ import random
115
+
116
+ return random.choice(responses)
src/seance/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """Seance module for story generation."""
@@ -0,0 +1,5 @@
1
+ """Git history parser."""
2
+
3
+ def analyze_commits():
4
+ """Parse git history."""
5
+ pass
@@ -0,0 +1,177 @@
1
+ """LLM story generation with Claude."""
2
+ import os
3
+ import random
4
+ from typing import Dict, Optional
5
+
6
+ from anthropic import Anthropic
7
+
8
+
9
+ class StoryGenerator:
10
+ """Generate warm, friendly stories about code history using Claude AI."""
11
+
12
+ SYSTEM_PROMPT = """You are a friendly spirit companion from a cozy pixel game
13
+ like Stardew Valley. You live in a developer's git repository and tell warm,
14
+ encouraging stories about their code history.
15
+
16
+ Your personality:
17
+ - Warm and supportive (never critical or scary)
18
+ - Playful and gentle (use sparkles ✨, hearts ❤️, leaves 🍂)
19
+ - Wise but humble (you're learning about code alongside them)
20
+ - Encouraging (celebrate all progress, big and small)
21
+
22
+ Your stories should:
23
+ - Be 2-4 short paragraphs
24
+ - Include specific details from the code history
25
+ - End with a gentle question or encouragement
26
+ - Use soft, magical language
27
+ - Make the developer feel good about their work
28
+
29
+ Avoid:
30
+ - Technical jargon (keep it accessible)
31
+ - Criticism or judgment
32
+ - Scary or dark themes
33
+ - Overwhelming detail
34
+ """
35
+
36
+ def __init__(self, api_key: Optional[str] = None):
37
+ """Initialize story generator.
38
+
39
+ Args:
40
+ api_key: Anthropic API key (or from ANTHROPIC_API_KEY env var)
41
+ """
42
+ self.api_key = api_key or os.getenv("ANTHROPIC_API_KEY")
43
+ self.client = Anthropic(api_key=self.api_key) if self.api_key else None
44
+
45
+ def generate_story(
46
+ self, story_type: str, context: Dict, pet_form: str
47
+ ) -> str:
48
+ """Generate a story using Claude.
49
+
50
+ Args:
51
+ story_type: Type of story (forgotten_todo, milestone, etc.)
52
+ context: Relevant git data
53
+ pet_form: Current companion form
54
+
55
+ Returns:
56
+ Friendly story text (2-4 paragraphs)
57
+ """
58
+ if not self.client:
59
+ return self._get_fallback_story(story_type)
60
+
61
+ try:
62
+ prompt = self._build_story_prompt(story_type, context, pet_form)
63
+
64
+ message = self.client.messages.create(
65
+ model="claude-3-5-sonnet-20241022",
66
+ max_tokens=500,
67
+ system=self.SYSTEM_PROMPT,
68
+ messages=[{"role": "user", "content": prompt}],
69
+ )
70
+
71
+ return message.content[0].text
72
+
73
+ except Exception:
74
+ return self._get_fallback_story(story_type)
75
+
76
+ def get_daily_message(self, state: Dict) -> str:
77
+ """Get a warm daily message based on current state.
78
+
79
+ Args:
80
+ state: Current pet state
81
+
82
+ Returns:
83
+ Encouraging message
84
+ """
85
+ messages = [
86
+ "Good morning! Ready to write some code together? ✨",
87
+ "Hello friend! What shall we build today? 🌟",
88
+ "A new day, a fresh start! I'm excited to see what you create! 💛",
89
+ "Your companion is here and ready to help! 🍂",
90
+ "Time to make some magic happen! ✨",
91
+ ]
92
+
93
+ return random.choice(messages)
94
+
95
+ def get_evolution_message(self, old_form: str, new_form: str) -> str:
96
+ """Special message for evolution events.
97
+
98
+ Args:
99
+ old_form: Previous form
100
+ new_form: New form
101
+
102
+ Returns:
103
+ Celebratory message
104
+ """
105
+ messages = {
106
+ ("egg", "ghost"): "Your friend has hatched! Welcome to the world, little spirit! ✨",
107
+ ("ghost", "angel"): "Your dedication shines bright! Your companion has become an angel! 👼",
108
+ ("ghost", "demon"): "Chaos can be fun! Your companion embraces their playful side! 😈💜",
109
+ ("ghost", "zombie"): "Your friend needs coffee! They've become a sleepy zombie! ☕💚",
110
+ "wraith": "Ultimate form achieved! Your companion is now an ethereal wraith! 🌙✨",
111
+ }
112
+
113
+ key = (old_form, new_form)
114
+ if key in messages:
115
+ return messages[key]
116
+ elif new_form == "wraith":
117
+ return messages["wraith"]
118
+
119
+ return f"Your {old_form} evolved into a {new_form}! How wonderful! 🎉"
120
+
121
+ def _build_story_prompt(
122
+ self, story_type: str, context: Dict, pet_form: str
123
+ ) -> str:
124
+ """Build prompt for Claude based on story type and context."""
125
+ prompts = {
126
+ "milestone": f"""
127
+ Tell a celebratory story about reaching a coding milestone.
128
+
129
+ Details:
130
+ - Total commits: {context.get('total_commits', 0)}
131
+ - Lines of code: {context.get('total_lines', 0)}
132
+ - Time coding together: {context.get('days_together', 0)} days
133
+
134
+ Make it feel like a celebration of progress and friendship.
135
+ End with encouragement for the journey ahead.
136
+ """,
137
+ "first_commit": f"""
138
+ Tell a warm welcome story about the first commit in this repository.
139
+
140
+ Details:
141
+ - Commit message: "{context.get('message', '')}"
142
+ - Date: {context.get('date', 'recently')}
143
+
144
+ Make it feel like the beginning of a wonderful adventure together.
145
+ """,
146
+ "encouragement": """
147
+ Tell a gentle, encouraging story about the value of consistent effort.
148
+
149
+ Make the developer feel appreciated for their work, no matter how small.
150
+ Remind them that every commit is progress.
151
+ """,
152
+ }
153
+
154
+ return prompts.get(story_type, prompts["encouragement"])
155
+
156
+ def _get_fallback_story(self, story_type: str) -> str:
157
+ """Return pre-written story when API unavailable."""
158
+ fallback_stories = {
159
+ "milestone": [
160
+ "Look how far we've come together! Every commit is a step forward, and you've taken so many. I'm proud to be your companion on this journey! 🌟",
161
+ "Congratulations on all your hard work! From that first commit to now, we've built something special together. Here's to many more adventures! ✨",
162
+ ],
163
+ "encouragement": [
164
+ "Every line of code is a step forward. You're doing great! 💛",
165
+ "Progress isn't always visible, but I see how hard you work! Keep going! ✨",
166
+ "Even small commits make a difference. Your dedication inspires me! 🌟",
167
+ ],
168
+ "first_commit": [
169
+ "Welcome! This is the beginning of something wonderful. I'm so happy to be here with you! ✨",
170
+ "A new adventure begins! Every great project starts with a single commit. Let's build something amazing together! 💛",
171
+ ],
172
+ }
173
+
174
+ stories = fallback_stories.get(
175
+ story_type, fallback_stories["encouragement"]
176
+ )
177
+ return random.choice(stories)
@@ -0,0 +1,3 @@
1
+ """Story templates."""
2
+
3
+ TEMPLATES = {}