@ramarivera/coding-buddy 0.4.0-alpha.9 → 0.7.0

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.
Files changed (94) hide show
  1. package/.claude-plugin/marketplace.json +45 -0
  2. package/.claude-plugin/plugin.json +30 -0
  3. package/LICENSE +1 -1
  4. package/README.md +96 -45
  5. package/adapters/omp/commands.ts +201 -0
  6. package/adapters/omp/context.ts +22 -0
  7. package/adapters/omp/events.ts +551 -0
  8. package/adapters/omp/identity.ts +10 -0
  9. package/adapters/omp/index.ts +39 -0
  10. package/adapters/omp/logger.ts +52 -0
  11. package/adapters/omp/prompt.ts +60 -0
  12. package/adapters/omp/renderers.ts +73 -0
  13. package/adapters/omp/storage.ts +25 -0
  14. package/adapters/omp/ui.ts +85 -0
  15. package/adapters/pi/commands.ts +64 -37
  16. package/adapters/pi/events.ts +147 -72
  17. package/adapters/pi/index.ts +9 -4
  18. package/adapters/pi/storage.ts +14 -285
  19. package/adapters/pi/ui.ts +56 -5
  20. package/adapters/shared/file-storage.ts +526 -0
  21. package/{adapters/claude/install → cli}/backup.ts +130 -33
  22. package/cli/buddy-shell.ts +1 -1
  23. package/{adapters/claude/install → cli}/disable.ts +19 -32
  24. package/cli/doctor.ts +231 -0
  25. package/{adapters/claude/install → cli}/hunt.ts +7 -9
  26. package/cli/index.ts +30 -26
  27. package/{adapters/claude/install → cli}/install.ts +65 -83
  28. package/{adapters/claude/install → cli}/pick.ts +136 -57
  29. package/{adapters/claude/install → cli}/settings.ts +2 -2
  30. package/{adapters/claude/install → cli}/show.ts +4 -4
  31. package/{adapters/claude/install → cli}/test-statusline.sh +2 -2
  32. package/{adapters/claude/install → cli}/test-statusline.ts +21 -11
  33. package/cli/tui.tsx +106 -17
  34. package/{adapters/claude/install → cli}/uninstall.ts +40 -47
  35. package/cli/upgrade.ts +46 -13
  36. package/cli/validate-species.ts +209 -0
  37. package/cli/verify.ts +3 -3
  38. package/core/achievements.ts +12 -20
  39. package/core/art-data.ts +26 -0
  40. package/core/command-service.ts +99 -97
  41. package/core/engine.ts +83 -1
  42. package/core/ports.ts +10 -0
  43. package/core/reactions.ts +533 -95
  44. package/core/slot-slug.ts +22 -0
  45. package/{adapters/claude/hooks → hooks}/buddy-comment.sh +22 -9
  46. package/hooks/file-type-react.sh +403 -0
  47. package/hooks/hooks.json +52 -0
  48. package/hooks/mood-react.sh +210 -0
  49. package/{adapters/claude/hooks → hooks}/name-react.sh +3 -4
  50. package/hooks/react.sh +1364 -0
  51. package/hooks/suggest.sh +55 -0
  52. package/package.json +70 -31
  53. package/scripts/gen-emoji-widths.ts +34 -0
  54. package/scripts/paths.sh +33 -2
  55. package/scripts/postinstall.cjs +42 -0
  56. package/scripts/snapshot-statusline.sh +54 -0
  57. package/server/achievements.ts +1419 -15
  58. package/server/art.ts +450 -1
  59. package/server/award-xp.ts +48 -0
  60. package/server/check-suggestions.ts +102 -0
  61. package/server/consolidate.ts +33 -0
  62. package/{adapters/claude/server → server}/index.ts +556 -95
  63. package/server/mcp-launcher.sh +16 -6
  64. package/server/memory.ts +404 -0
  65. package/server/mood.ts +254 -0
  66. package/server/path.ts +70 -18
  67. package/server/shift-mood.ts +43 -0
  68. package/server/state.ts +552 -3
  69. package/server/suggestions.ts +335 -0
  70. package/server/theme.ts +53 -0
  71. package/server/xp.ts +435 -0
  72. package/{adapters/claude/skills → skills}/buddy/SKILL.md +36 -7
  73. package/statusline/buddy-status.sh +402 -0
  74. package/statusline/combined-status.sh +135 -0
  75. package/statusline/emoji-widths.data +4 -0
  76. package/adapters/claude/hooks/hooks.json +0 -35
  77. package/adapters/claude/hooks/react.sh +0 -207
  78. package/adapters/claude/install/doctor.ts +0 -172
  79. package/adapters/claude/plugin/marketplace.json +0 -40
  80. package/adapters/claude/plugin/plugin.json +0 -26
  81. package/adapters/claude/rendering/art.ts +0 -264
  82. package/adapters/claude/server/instructions.ts +0 -24
  83. package/adapters/claude/server/path.ts +0 -12
  84. package/adapters/claude/server/resources.ts +0 -38
  85. package/adapters/claude/statusline/buddy-status.sh +0 -408
  86. package/adapters/claude/storage/achievements.ts +0 -253
  87. package/adapters/claude/storage/identity.ts +0 -13
  88. package/adapters/claude/storage/paths.ts +0 -33
  89. package/adapters/claude/storage/settings.ts +0 -91
  90. package/adapters/claude/storage/state.ts +0 -365
  91. package/adapters/pi/README.md +0 -83
  92. package/adapters/pi/tools.ts +0 -6
  93. package/server/engine.ts +0 -1
  94. package/server/reactions.ts +0 -1
package/core/engine.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * claude-buddy engine — deterministic companion generation
2
+ * coding-buddy engine — deterministic companion generation
3
3
  * Matches Claude Code's exact algorithm: wyhash → mulberry32 → species/stats
4
4
  */
5
5
 
@@ -24,6 +24,8 @@ export const SPECIES = [
24
24
  "rabbit",
25
25
  "mushroom",
26
26
  "chonk",
27
+ "wyvern",
28
+ "pikachu",
27
29
  ] as const;
28
30
 
29
31
  export type Species = (typeof SPECIES)[number];
@@ -296,6 +298,84 @@ export function generateBones(userId: string, salt: string = SALT): BuddyBones {
296
298
  return { rarity, species, eye, hat, shiny, stats, peak, dump };
297
299
  }
298
300
 
301
+ // ─── Personality ────────────────────────────────────────────────────────────
302
+
303
+ const PEAK_PHRASES: Record<StatName, string[]> = {
304
+ DEBUGGING: [
305
+ "spots segfaults before the stack unwinds",
306
+ "can read a backtrace like a map",
307
+ "finds the off-by-one before the tests do",
308
+ ],
309
+ PATIENCE: [
310
+ "outlasts any flaky test suite",
311
+ "waits for the slow CI build without complaint",
312
+ "never merges before the green check",
313
+ ],
314
+ CHAOS: [
315
+ "treats breaking changes as a love language",
316
+ "rewrites the Makefile on a Tuesday for fun",
317
+ "thrives wherever the incident channel is loudest",
318
+ ],
319
+ WISDOM: [
320
+ "has seen this bug before — in three other repos",
321
+ "quotes the relevant RFC from memory",
322
+ "recognizes the abstraction that will outlive its author",
323
+ ],
324
+ SNARK: [
325
+ "leaves code review comments that linger",
326
+ "finds the edge case you forgot and mentions it twice",
327
+ "names things with uncomfortable accuracy",
328
+ ],
329
+ };
330
+
331
+ const DUMP_PHRASES: Record<StatName, string[]> = {
332
+ DEBUGGING: [
333
+ "occasionally ships the workaround instead of the fix",
334
+ "skips the repro step",
335
+ "trusts the logs a little too much",
336
+ ],
337
+ PATIENCE: [
338
+ "starts the rebase before the review is done",
339
+ "has been known to close slow issues as stale",
340
+ "has been known to force-push main",
341
+ ],
342
+ CHAOS: [
343
+ "prefers everything to stay exactly where it is",
344
+ "dislikes surprise refactors",
345
+ "writes very thorough migration guides",
346
+ ],
347
+ WISDOM: [
348
+ "sometimes reinvents the wheel with enthusiasm",
349
+ "skips the existing prior art",
350
+ "learns by doing, not by reading",
351
+ ],
352
+ SNARK: [
353
+ "only leaves encouraging comments",
354
+ "approves PRs with genuine warmth",
355
+ "never says what it actually thinks",
356
+ ],
357
+ };
358
+
359
+ const RARITY_CLOSER: Record<string, string[]> = {
360
+ common: ["Gets the job done.", "Reliable, if unassuming."],
361
+ uncommon: ["Has a few tricks up its sleeve.", "Worth keeping around."],
362
+ rare: ["Not to be underestimated.", "Earns its keep."],
363
+ epic: ["Commands quiet respect.", "The kind of companion repos are built around."],
364
+ legendary: ["The kind you find once, if you're lucky.", "Leaves every codebase better than it found it."],
365
+ };
366
+
367
+ export function generatePersonality(bones: BuddyBones, userId: string): string {
368
+ const seed = parseInt(userId.slice(0, 8), 16);
369
+ const pickPhrase = <T>(arr: T[], salt: number = 0): T => arr[(seed + salt) % arr.length];
370
+
371
+ const shiny = bones.shiny ? " Shimmers faintly in dark mode." : "";
372
+ const peak = pickPhrase(PEAK_PHRASES[bones.peak]);
373
+ const dump = pickPhrase(DUMP_PHRASES[bones.dump], 1);
374
+ const closer = pickPhrase(RARITY_CLOSER[bones.rarity] ?? ["Gets the job done."], 2);
375
+
376
+ return `A ${bones.rarity} ${bones.species} that ${peak}.${shiny} ${closer} Though it ${dump}.`;
377
+ }
378
+
299
379
  // ─── ASCII Art ──────────────────────────────────────────────────────────────
300
380
 
301
381
  const FACE_TEMPLATES: Record<Species, string> = {
@@ -317,6 +397,8 @@ const FACE_TEMPLATES: Record<Species, string> = {
317
397
  rabbit: "({E}..{E})",
318
398
  mushroom: "|{E} {E}|",
319
399
  chonk: "({E}.{E})",
400
+ wyvern: "\\ {E}' '{E} /",
401
+ pikachu: "({E}ω{E})",
320
402
  };
321
403
 
322
404
  export function renderFace(species: Species, eye: Eye): string {
package/core/ports.ts CHANGED
@@ -5,6 +5,7 @@ import type {
5
5
  ReactionState,
6
6
  UnlockedAchievement,
7
7
  } from "./model.ts";
8
+ import type { Achievement } from "./achievements.ts";
8
9
 
9
10
  export interface IdentityProvider {
10
11
  getStableUserId(): string;
@@ -13,12 +14,17 @@ export interface IdentityProvider {
13
14
  export interface BuddyRepository {
14
15
  loadActive(): Companion | null;
15
16
  saveActive(companion: Companion): void;
17
+ updateActive(transform: (companion: Companion) => Companion): Companion;
16
18
  loadSlot(slot: string): Companion | null;
17
19
  saveSlot(slot: string, companion: Companion): void;
18
20
  deleteSlot(slot: string): void;
19
21
  listSlots(): Array<{ slot: string; companion: Companion }>;
20
22
  loadActiveSlot(): string | null;
21
23
  saveActiveSlot(slot: string): void;
24
+ ensureCompanion(
25
+ userId: string,
26
+ create: (existingSlots: string[]) => { companion: Companion; slot: string },
27
+ ): { companion: Companion; slot: string; created: boolean };
22
28
  }
23
29
 
24
30
  export interface ReactionRepository {
@@ -37,4 +43,8 @@ export interface BuddyEventRepository {
37
43
  loadUnlocked(): UnlockedAchievement[];
38
44
  saveUnlocked(unlocked: UnlockedAchievement[]): void;
39
45
  trackActiveDay(): void;
46
+ unlockAchievements(
47
+ slot: string | undefined,
48
+ evaluate: (counters: EventCounters, unlockedIds: Set<string>) => Achievement[],
49
+ ): Achievement[];
40
50
  }