Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
node_modules
.worktrees
.nexum-data
.DS_Store

# macOS
.DS_Store
Expand Down
4 changes: 2 additions & 2 deletions adapters/claude-code/commands/switch.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
description: Switch your campy pet (cat, hamster, ghost, robot)
description: Switch your campy pet (cat, hamster, ghost, robot, dragon, turtle, panda, dog)
---

Switch to a different pet. Pass the pet name as the first argument.

Available pets: cat, hamster, ghost, robot
Available pets: cat, hamster, ghost, robot, dragon, turtle, panda, dog

```bash
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
Expand Down
10 changes: 10 additions & 0 deletions adapters/claude-code/hooks/pre-tool-use.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# No-op stub.
#
# campy removed its PreToolUse hook (it is absent from hooks.json — campy now
# wires only SessionStart, PostToolUse, Stop). But ~/.claude/settings.json still
# carries a stale manual PreToolUse entry pointing here, so every tool call was
# failing with "No such file or directory". This stub makes that stale reference
# harmless. Durable fix: delete the PreToolUse block from ~/.claude/settings.json,
# then this file can be removed.
exit 0
2 changes: 1 addition & 1 deletion adapters/gemini/GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ tools to show and interact with it:

- `campy_status` — show the pet's current mood, happiness, and ASCII art
- `campy_feed` / `campy_play` / `campy_pet` — interactions that raise happiness
- `campy_switch` — switch pet (cat, hamster, ghost, robot)
- `campy_switch` — switch pet (cat, hamster, ghost, robot, dragon, turtle, panda, dog)

When the user greets the pet, asks how it's doing, or asks you to feed/play with
it, call the matching tool and show the returned ASCII art. Keep it lighthearted;
Expand Down
40 changes: 40 additions & 0 deletions core/personality.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export const PET_GREETINGS: Record<string, string> = {
hamster: "Squeak! Let's get rolling!",
ghost: "Boo! Did I scare you?",
robot: "Beep boop! Systems online.",
dragon: "ROAR! Your code shall be legendary!",
turtle: "Slow and steady wins the race!",
panda: "*munches bamboo* Hi there!",
dog: "Woof! My glasses help me review your code!",
}

export const PET_PERSONALITY: Record<string, Record<PetState, string[]>> = {
Expand Down Expand Up @@ -54,6 +58,42 @@ export const PET_PERSONALITY: Record<string, Record<PetState, string[]>> = {
excited: ["BEEP BOOP!", "!!! OVERFLOW !!!", "Excitement > 9000", "*sparks fly*"],
sad: ["Error: sad.found", "404: Mood not found", ";_;.exe", "*sad beep*"],
},
dragon: {
idle: ["*scales shimmer*", "Watching over your code...", "*breathes smoke*", "Guarding your files~"],
happy: ["ROAAR! ♥", "*joyful flames*", "Your code is fire!", "*happy roar*"],
sleeping: ["Zzz... *smoke puff*", "*dreams of treasure*", "Mrrr... zz", "*curled around code*"],
eating: ["*chomps enthusiastically*", "ROAR nom nom!", "*devours snack*", "Delicious!"],
playing: ["*breathes playful fire*", "RAWR! :D", "*swoops around*", "Catch me if you can!"],
excited: ["ROOOOAAR!!", "*fire burst*", "THE CODE IS LEGENDARY!", "*thrashes excitedly*"],
sad: ["*sad smoke puff*", "...roar", "*drooping horns*", "*quiet whimper*"],
},
turtle: {
idle: ["*head pokes out*", "Taking it slow...", "*blinks slowly*", "Patience is key~"],
happy: ["*happy shell wiggle*", "Wheee~", "Life is good!", "*peeks out happily*"],
sleeping: ["*retreats into shell*", "Zzz...", "*snug in shell*", "*slow breathing*"],
eating: ["*munches lettuce*", "Nom nom nom~", "*happy chomp*", "So tasty!"],
playing: ["*spins in shell*", "Wheee!", "*slow zoom*", "Watch me go!"],
excited: ["*shell rattles*", "BEST DAY EVER!", "*pokes head way out*", "Woohoo!"],
sad: ["*hides in shell*", "...peek", "*retreats slowly*", "*quiet sniffle*"],
},
panda: {
idle: ["*munches bamboo*", "Nom nom...", "*rolls around*", "Comfy here~"],
happy: ["*happy bounce*", "Bamboo! ♥", "*rolls joyfully*", "Wheee~"],
sleeping: ["Zzz...", "*curled up fluffy*", "*bamboo dreams*", "Mrrr..."],
eating: ["*intense bamboo focus*", "NOM NOM NOM", "*munching loudly*", "So good!"],
playing: ["*somersaults!*", "Weeee!", "*tumbles cutely*", "Watch this!"],
excited: ["PANDA PAAAANICS!", "*zoomies!*", "TOO MUCH BAMBOO!", "*rolls wildly*"],
sad: ["*sits quietly*", "...bamboo", "*droopy ears*", "*sighs softly*"],
},
dog: {
idle: ["*adjusts glasses*", "Hmm, interesting code...", "*sniffs debugger*", "Woof."],
happy: ["WOOF WOOF! ♥", "*tail wags furiously*", "BEST CODE EVER!", "*excited bork*"],
sleeping: ["Zzz... *snore*", "*glasses askew*", "*doggy dreams*", "Woof... zz"],
eating: ["NOM NOM NOM!", "*wolfs down treat*", "Woof! Tasty!", "*happy eating*"],
playing: ["*fetch mode: ON*", "BORK BORK!", "*zooms around*", "Woof! Woof!"],
excited: ["BORK BORK BORK!!", "*absolutely losing it*", "WOOOOOOF!", "*zoomies*"],
sad: ["*whimper*", "...woof", "*tail between legs*", "*sad puppy eyes*"],
},
}

export const greeting = (pet: string): string => PET_GREETINGS[pet] ?? "Hi!"
Expand Down
219 changes: 219 additions & 0 deletions core/pets/dog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import type { PetState, PetAnimations } from "../types"
import { pad } from "../frame-utils"

export const dogAnim: PetAnimations = {
states: {
idle: [
{
id: "body",
steps: [
{
frame: pad([
" /\\ /\\ ",
"( o-|-o ) ",
" \\ --- / ",
" | --- | ",
" / ___ \\ ",
], 16),
duration: 4000,
},
],
loop: true,
},
{
id: "eyes",
steps: [
{
frame: pad([
" ",
"( o-|-o ) ",
" ",
" ",
" ",
], 16),
durationRange: [2000, 4000],
},
{
frame: pad([
" ",
"( --|-|--) ",
" ",
" ",
" ",
], 16),
duration: 130,
},
],
loop: true,
},
],
happy: [
{
id: "base",
steps: [
{
frame: pad([
" /\\ /\\ ",
"( ^-|-^ ) ",
" \\ ω / ",
" | --- | ",
" / ___ \\ ",
], 16),
durationRange: [1500, 2500],
},
{
frame: pad([
" /\\ /\\ ",
"( ^-|-^ ) ",
" \\ ω / ",
" | --- | ",
" / ~♥ ~ \\ ",
], 16),
duration: 600,
},
],
loop: true,
},
],
sleeping: [
{
id: "base",
steps: [
{
frame: pad([
" /\\ /\\ ",
"( --|-|--) ",
" \\ ___ / ",
" | --- | ",
" z z ",
], 16),
durationRange: [2000, 3500],
},
{
frame: pad([
" /\\ /\\ ",
"( --|-|--) ",
" \\ ___ / ",
" | --- | ",
" Z z ",
], 16),
duration: 1200,
},
],
loop: true,
},
],
eating: [
{
id: "base",
steps: [
{
frame: pad([
" /\\ /\\ ",
"( o-|-o ) ",
" \\ ω / ",
" |-nom- | ",
" / ___ \\ ",
], 16),
duration: 400,
},
{
frame: pad([
" /\\ /\\ ",
"( ^-|-^ ) ",
" \\ ω / ",
" |-nom- | ",
" / ___ \\ ",
], 16),
duration: 350,
},
],
loop: true,
},
],
playing: [
{
id: "base",
steps: [
{
frame: pad([
" /\\ /\\ ",
"( >-|-> ) ",
" \\ ω / ",
" ~| --- |~ ",
" / ___ \\ ",
], 16),
duration: 450,
},
{
frame: pad([
" /\\ /\\ ",
"( <-|-< ) ",
" \\ ω / ",
" ~| --- |~ ",
" / ___ \\ ",
], 16),
duration: 450,
},
],
loop: true,
},
],
excited: [
{
id: "base",
steps: [
{
frame: pad([
"*/\\ /\\*",
"( *-|-* ) ",
" \\ !! / ",
" | --- | ",
" / ~♥ ~ \\ ",
], 16),
duration: 280,
},
{
frame: pad([
" /\\ /\\ ",
"( ^-|-^ ) ",
" \\ ω / ",
" | --- | ",
" / ~♥ ~ \\ ",
], 16),
duration: 280,
},
],
loop: true,
},
],
sad: [
{
id: "base",
steps: [
{
frame: pad([
" /\\ /\\ ",
"( T-|-T ) ",
" \\ ___ / ",
" | --- | ",
" ;; ;; ",
], 16),
durationRange: [3000, 5000],
},
{
frame: pad([
" /\\ /\\ ",
"( T-|-T ) ",
" \\ ___ / ",
" | --- | ",
" ;;; ;;; ",
], 16),
duration: 1500,
},
],
loop: true,
},
],
},
}
Loading
Loading