petdex-cc 0.1.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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +247 -0
  3. package/README_CN.md +247 -0
  4. package/dist/bin/cli.d.ts +3 -0
  5. package/dist/bin/cli.d.ts.map +1 -0
  6. package/dist/bin/cli.js +78 -0
  7. package/dist/bin/cli.js.map +1 -0
  8. package/dist/src/assets/tray-icon.png +0 -0
  9. package/dist/src/cli/config.d.ts +9 -0
  10. package/dist/src/cli/config.d.ts.map +1 -0
  11. package/dist/src/cli/config.js +41 -0
  12. package/dist/src/cli/config.js.map +1 -0
  13. package/dist/src/cli/install.d.ts +2 -0
  14. package/dist/src/cli/install.d.ts.map +1 -0
  15. package/dist/src/cli/install.js +62 -0
  16. package/dist/src/cli/install.js.map +1 -0
  17. package/dist/src/cli/list.d.ts +2 -0
  18. package/dist/src/cli/list.d.ts.map +1 -0
  19. package/dist/src/cli/list.js +20 -0
  20. package/dist/src/cli/list.js.map +1 -0
  21. package/dist/src/cli/start.d.ts +3 -0
  22. package/dist/src/cli/start.d.ts.map +1 -0
  23. package/dist/src/cli/start.js +37 -0
  24. package/dist/src/cli/start.js.map +1 -0
  25. package/dist/src/cli/status.d.ts +2 -0
  26. package/dist/src/cli/status.d.ts.map +1 -0
  27. package/dist/src/cli/status.js +8 -0
  28. package/dist/src/cli/status.js.map +1 -0
  29. package/dist/src/cli/stop.d.ts +2 -0
  30. package/dist/src/cli/stop.d.ts.map +1 -0
  31. package/dist/src/cli/stop.js +39 -0
  32. package/dist/src/cli/stop.js.map +1 -0
  33. package/dist/src/cli/switch.d.ts +2 -0
  34. package/dist/src/cli/switch.d.ts.map +1 -0
  35. package/dist/src/cli/switch.js +34 -0
  36. package/dist/src/cli/switch.js.map +1 -0
  37. package/dist/src/cli/uninstall.d.ts +2 -0
  38. package/dist/src/cli/uninstall.d.ts.map +1 -0
  39. package/dist/src/cli/uninstall.js +18 -0
  40. package/dist/src/cli/uninstall.js.map +1 -0
  41. package/dist/src/hooks/register.d.ts +3 -0
  42. package/dist/src/hooks/register.d.ts.map +1 -0
  43. package/dist/src/hooks/register.js +113 -0
  44. package/dist/src/hooks/register.js.map +1 -0
  45. package/dist/src/hooks/write-scripts.d.ts +2 -0
  46. package/dist/src/hooks/write-scripts.d.ts.map +1 -0
  47. package/dist/src/hooks/write-scripts.js +39 -0
  48. package/dist/src/hooks/write-scripts.js.map +1 -0
  49. package/dist/src/main/ai-speech.d.ts +22 -0
  50. package/dist/src/main/ai-speech.d.ts.map +1 -0
  51. package/dist/src/main/ai-speech.js +131 -0
  52. package/dist/src/main/ai-speech.js.map +1 -0
  53. package/dist/src/main/event-mapper.d.ts +10 -0
  54. package/dist/src/main/event-mapper.d.ts.map +1 -0
  55. package/dist/src/main/event-mapper.js +92 -0
  56. package/dist/src/main/event-mapper.js.map +1 -0
  57. package/dist/src/main/index.d.ts +2 -0
  58. package/dist/src/main/index.d.ts.map +1 -0
  59. package/dist/src/main/index.js +175 -0
  60. package/dist/src/main/index.js.map +1 -0
  61. package/dist/src/main/server.d.ts +8 -0
  62. package/dist/src/main/server.d.ts.map +1 -0
  63. package/dist/src/main/server.js +81 -0
  64. package/dist/src/main/server.js.map +1 -0
  65. package/dist/src/main/storage.d.ts +15 -0
  66. package/dist/src/main/storage.d.ts.map +1 -0
  67. package/dist/src/main/storage.js +90 -0
  68. package/dist/src/main/storage.js.map +1 -0
  69. package/dist/src/main/tray.d.ts +3 -0
  70. package/dist/src/main/tray.d.ts.map +1 -0
  71. package/dist/src/main/tray.js +156 -0
  72. package/dist/src/main/tray.js.map +1 -0
  73. package/dist/src/petdex-api/client.d.ts +21 -0
  74. package/dist/src/petdex-api/client.d.ts.map +1 -0
  75. package/dist/src/petdex-api/client.js +23 -0
  76. package/dist/src/petdex-api/client.js.map +1 -0
  77. package/dist/src/petdex-api/download.d.ts +8 -0
  78. package/dist/src/petdex-api/download.d.ts.map +1 -0
  79. package/dist/src/petdex-api/download.js +45 -0
  80. package/dist/src/petdex-api/download.js.map +1 -0
  81. package/dist/src/renderer/bubble.d.ts +30 -0
  82. package/dist/src/renderer/bubble.d.ts.map +1 -0
  83. package/dist/src/renderer/bubble.js +69 -0
  84. package/dist/src/renderer/bubble.js.map +1 -0
  85. package/dist/src/renderer/click-through.d.ts +21 -0
  86. package/dist/src/renderer/click-through.d.ts.map +1 -0
  87. package/dist/src/renderer/click-through.js +29 -0
  88. package/dist/src/renderer/click-through.js.map +1 -0
  89. package/dist/src/renderer/context-menu.d.ts +24 -0
  90. package/dist/src/renderer/context-menu.d.ts.map +1 -0
  91. package/dist/src/renderer/context-menu.js +83 -0
  92. package/dist/src/renderer/context-menu.js.map +1 -0
  93. package/dist/src/renderer/drag.d.ts +3 -0
  94. package/dist/src/renderer/drag.d.ts.map +1 -0
  95. package/dist/src/renderer/drag.js +57 -0
  96. package/dist/src/renderer/drag.js.map +1 -0
  97. package/dist/src/renderer/index.html +264 -0
  98. package/dist/src/renderer/pet-sprite.d.ts +25 -0
  99. package/dist/src/renderer/pet-sprite.d.ts.map +1 -0
  100. package/dist/src/renderer/pet-sprite.js +59 -0
  101. package/dist/src/renderer/pet-sprite.js.map +1 -0
  102. package/dist/src/renderer/renderer.d.ts +2 -0
  103. package/dist/src/renderer/renderer.d.ts.map +1 -0
  104. package/dist/src/renderer/renderer.js +244 -0
  105. package/dist/src/renderer/renderer.js.map +1 -0
  106. package/dist/src/renderer/wander.d.ts +8 -0
  107. package/dist/src/renderer/wander.d.ts.map +1 -0
  108. package/dist/src/renderer/wander.js +137 -0
  109. package/dist/src/renderer/wander.js.map +1 -0
  110. package/dist/src/shared/events.d.ts +62 -0
  111. package/dist/src/shared/events.d.ts.map +1 -0
  112. package/dist/src/shared/events.js +2 -0
  113. package/dist/src/shared/events.js.map +1 -0
  114. package/dist/src/shared/levels.d.ts +18 -0
  115. package/dist/src/shared/levels.d.ts.map +1 -0
  116. package/dist/src/shared/levels.js +20 -0
  117. package/dist/src/shared/levels.js.map +1 -0
  118. package/dist/src/shared/pet-states.d.ts +72 -0
  119. package/dist/src/shared/pet-states.d.ts.map +1 -0
  120. package/dist/src/shared/pet-states.js +20 -0
  121. package/dist/src/shared/pet-states.js.map +1 -0
  122. package/package.json +48 -0
  123. package/src/assets/tray-icon.png +0 -0
  124. package/src/hooks/bridge.ps1 +11 -0
  125. package/src/hooks/bridge.sh +9 -0
@@ -0,0 +1,90 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { homedir } from "node:os";
5
+ import machineId from "node-machine-id";
6
+ const { machineIdSync } = machineId;
7
+ const DATA_DIR = join(homedir(), ".petdex-cc", "data");
8
+ const STATE_FILE = join(DATA_DIR, "state.json");
9
+ const SIG_FILE = join(DATA_DIR, "state.sig");
10
+ function getHmacKey() {
11
+ return `petdex-cc-${machineIdSync()}`;
12
+ }
13
+ function signState(state) {
14
+ const key = getHmacKey();
15
+ return createHmac("sha256", key).update(JSON.stringify(state)).digest("hex");
16
+ }
17
+ function verifySignature(state, sig) {
18
+ const expected = signState(state);
19
+ if (expected.length !== sig.length)
20
+ return false;
21
+ try {
22
+ return timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ export function getDefaultState(slug = "") {
29
+ return {
30
+ petSlug: slug,
31
+ totalEvents: 0,
32
+ level: 1,
33
+ levelName: "Byte",
34
+ createdAt: new Date().toISOString(),
35
+ lastActiveAt: new Date().toISOString(),
36
+ version: 1,
37
+ };
38
+ }
39
+ export function loadState() {
40
+ if (!existsSync(STATE_FILE) || !existsSync(SIG_FILE)) {
41
+ return getDefaultState();
42
+ }
43
+ try {
44
+ const raw = readFileSync(STATE_FILE, "utf8");
45
+ const sig = readFileSync(SIG_FILE, "utf8").trim();
46
+ const state = JSON.parse(raw);
47
+ if (!verifySignature(state, sig)) {
48
+ return getDefaultState(state.petSlug);
49
+ }
50
+ return state;
51
+ }
52
+ catch {
53
+ return getDefaultState();
54
+ }
55
+ }
56
+ export function saveState(state) {
57
+ mkdirSync(DATA_DIR, { recursive: true });
58
+ const sig = signState(state);
59
+ writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
60
+ writeFileSync(SIG_FILE, sig);
61
+ }
62
+ export function incrementEvents(state, count = 1) {
63
+ const updated = {
64
+ ...state,
65
+ totalEvents: state.totalEvents + count,
66
+ lastActiveAt: new Date().toISOString(),
67
+ };
68
+ const levels = [
69
+ { level: 1, name: "Byte", threshold: 0 },
70
+ { level: 2, name: "Process", threshold: 50 },
71
+ { level: 3, name: "Thread", threshold: 200 },
72
+ { level: 4, name: "Module", threshold: 500 },
73
+ { level: 5, name: "Kernel", threshold: 1000 },
74
+ { level: 6, name: "Neural", threshold: 2000 },
75
+ { level: 7, name: "Quantum", threshold: 5000 },
76
+ { level: 8, name: "Singularity", threshold: 10000 },
77
+ ];
78
+ for (let i = levels.length - 1; i >= 0; i--) {
79
+ if (updated.totalEvents >= levels[i].threshold) {
80
+ updated.level = levels[i].level;
81
+ updated.levelName = levels[i].name;
82
+ break;
83
+ }
84
+ }
85
+ return updated;
86
+ }
87
+ export function detectLevelUp(oldState, newState) {
88
+ return newState.level > oldState.level;
89
+ }
90
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/main/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { BrowserWindow, Tray } from "electron";
2
+ export declare function createTray(mainWindow: BrowserWindow): Tray | null;
3
+ //# sourceMappingURL=tray.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tray.d.ts","sourceRoot":"","sources":["../../../src/main/tray.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,aAAa,EAAQ,IAAI,EAAe,MAAM,UAAU,CAAC;AAsGvE,wBAAgB,UAAU,CAAC,UAAU,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI,CA8DjE"}
@@ -0,0 +1,156 @@
1
+ import { join, dirname } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { app, Menu, Tray, nativeImage } from "electron";
4
+ let tray = null;
5
+ function generateTrayIcon() {
6
+ const S = 32;
7
+ const buf = Buffer.alloc(S * S * 4);
8
+ const cx = S / 2;
9
+ const cy = S / 2;
10
+ for (let y = 0; y < S; y++) {
11
+ for (let x = 0; x < S; x++) {
12
+ const i = (y * S + x) * 4;
13
+ const dx = x - cx + 0.5;
14
+ const dy = y - cy + 0.5;
15
+ const dist = Math.sqrt(dx * dx + dy * dy);
16
+ // Outer circle: cat face background
17
+ const outerR = 14;
18
+ if (dist <= outerR) {
19
+ // Gradient: top-left lighter, bottom-right darker
20
+ const t = (dx / outerR + dy / outerR) / 2;
21
+ const r = Math.round(139 + (1 - t) * 40);
22
+ const g = Math.round(92 + (1 - t) * 40);
23
+ const b = Math.round(246);
24
+ // Anti-aliased edge
25
+ const edge = Math.max(0, Math.min(1, outerR - dist));
26
+ const alpha = Math.round(edge * 255);
27
+ // Highlight spot (upper-left)
28
+ const hx = dx + 4, hy = dy + 4;
29
+ const hDist = Math.sqrt(hx * hx + hy * hy);
30
+ const highlight = Math.max(0, 1 - hDist / 8) * 0.25;
31
+ buf[i] = Math.min(255, Math.round(r + highlight * 80));
32
+ buf[i + 1] = Math.min(255, Math.round(g + highlight * 80));
33
+ buf[i + 2] = Math.min(255, Math.round(b + highlight * 40));
34
+ buf[i + 3] = alpha;
35
+ }
36
+ // Cat ears (two triangles)
37
+ const earPoints = [
38
+ // Left ear
39
+ [{ x: -9, y: -8 }, { x: -5, y: -15 }, { x: -2, y: -7 }],
40
+ // Right ear
41
+ [{ x: 2, y: -7 }, { x: 5, y: -15 }, { x: 9, y: -8 }],
42
+ ];
43
+ for (const ear of earPoints) {
44
+ const [a, b2, c] = ear;
45
+ const px = x - cx + 0.5, py = y - cy + 0.5;
46
+ // Point-in-triangle test
47
+ const d1 = (px - b2.x) * (a.y - b2.y) - (a.x - b2.x) * (py - b2.y);
48
+ const d2 = (px - c.x) * (b2.y - c.y) - (b2.x - c.x) * (py - c.y);
49
+ const d3 = (px - a.x) * (c.y - a.y) - (c.x - a.x) * (py - a.y);
50
+ const hasNeg = d1 < 0 || d2 < 0 || d3 < 0;
51
+ const hasPos = d1 > 0 || d2 > 0 || d3 > 0;
52
+ if (!(hasNeg && hasPos)) {
53
+ // Inside ear — slightly darker purple
54
+ buf[i] = 0x7c;
55
+ buf[i + 1] = 0x3a;
56
+ buf[i + 2] = 0xed;
57
+ buf[i + 3] = 0xff;
58
+ }
59
+ }
60
+ // Eyes (two small white circles)
61
+ const eyes = [{ x: -4.5, y: -1 }, { x: 4.5, y: -1 }];
62
+ for (const eye of eyes) {
63
+ const ed = Math.sqrt((dx - eye.x) ** 2 + (dy - eye.y) ** 2);
64
+ if (ed <= 2.2) {
65
+ const edge = Math.max(0, Math.min(1, 2.2 - ed));
66
+ buf[i] = 0xff;
67
+ buf[i + 1] = 0xff;
68
+ buf[i + 2] = 0xff;
69
+ buf[i + 3] = Math.max(buf[i + 3], Math.round(edge * 255));
70
+ }
71
+ // Pupils
72
+ const pd = Math.sqrt((dx - eye.x) ** 2 + (dy - eye.y + 0.3) ** 2);
73
+ if (pd <= 1.2) {
74
+ buf[i] = 0x2d;
75
+ buf[i + 1] = 0x1b;
76
+ buf[i + 2] = 0x69;
77
+ buf[i + 3] = 0xff;
78
+ }
79
+ }
80
+ // Mouth (small curved line)
81
+ const mouthY = 4;
82
+ if (Math.abs(dy - mouthY) < 1.2 && Math.abs(dx) < 4) {
83
+ const mouthCurve = (dx * dx) / 8;
84
+ if (dy > mouthY + mouthCurve - 1.5 && dy < mouthY + mouthCurve + 0.5) {
85
+ buf[i] = 0x3b;
86
+ buf[i + 1] = 0x1f;
87
+ buf[i + 2] = 0x6e;
88
+ buf[i + 3] = 0xff;
89
+ }
90
+ }
91
+ }
92
+ }
93
+ return nativeImage.createFromBuffer(buf, { width: S, height: S });
94
+ }
95
+ export function createTray(mainWindow) {
96
+ const __dirname = dirname(fileURLToPath(import.meta.url));
97
+ const iconPath = join(__dirname, "..", "assets", "tray-icon.png");
98
+ let icon;
99
+ try {
100
+ icon = nativeImage.createFromPath(iconPath);
101
+ if (icon.isEmpty())
102
+ throw new Error("empty");
103
+ }
104
+ catch {
105
+ icon = generateTrayIcon();
106
+ }
107
+ try {
108
+ tray = new Tray(icon);
109
+ }
110
+ catch (err) {
111
+ console.warn("Tray creation failed:", err);
112
+ return null;
113
+ }
114
+ tray.setToolTip("petdex-cc");
115
+ const contextMenu = Menu.buildFromTemplate([
116
+ {
117
+ label: "Show Pet",
118
+ click: () => mainWindow.show(),
119
+ },
120
+ {
121
+ label: "Hide Pet",
122
+ click: () => mainWindow.hide(),
123
+ },
124
+ { type: "separator" },
125
+ {
126
+ label: "About",
127
+ click: async () => {
128
+ const { dialog } = await import("electron");
129
+ dialog.showMessageBox({
130
+ type: "info",
131
+ title: "petdex-cc",
132
+ message: "petdex-cc v0.1.0",
133
+ detail: "Desktop pet companion for Claude Code.\nPets from https://petdex.crafter.run",
134
+ });
135
+ },
136
+ },
137
+ { type: "separator" },
138
+ {
139
+ label: "Quit",
140
+ click: () => {
141
+ app.quit();
142
+ },
143
+ },
144
+ ]);
145
+ tray.setContextMenu(contextMenu);
146
+ tray.on("click", () => {
147
+ if (mainWindow.isVisible()) {
148
+ mainWindow.hide();
149
+ }
150
+ else {
151
+ mainWindow.show();
152
+ }
153
+ });
154
+ return tray;
155
+ }
156
+ //# sourceMappingURL=tray.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tray.js","sourceRoot":"","sources":["../../../src/main/tray.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface PetManifestEntry {
2
+ id: string;
3
+ slug: string;
4
+ displayName: string;
5
+ description: string;
6
+ spritesheetUrl: string;
7
+ petJsonUrl: string;
8
+ zipUrl: string;
9
+ kind: string;
10
+ vibes: string[];
11
+ tags: string[];
12
+ dominantColor: string;
13
+ }
14
+ export declare function fetchManifest(): Promise<PetManifestEntry[]>;
15
+ export declare function findPetBySlug(slug: string): Promise<PetManifestEntry | null>;
16
+ export declare function listPets(): Promise<{
17
+ slug: string;
18
+ displayName: string;
19
+ kind: string;
20
+ }[]>;
21
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/petdex-api/client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAWjE;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAIlC;AAED,wBAAsB,QAAQ,IAAI,OAAO,CACvC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CACtD,CAOA"}
@@ -0,0 +1,23 @@
1
+ const MANIFEST_URL = "https://petdex.crafter.run/api/manifest";
2
+ export async function fetchManifest() {
3
+ const response = await fetch(MANIFEST_URL);
4
+ if (!response.ok) {
5
+ throw new Error(`Failed to fetch manifest: ${response.status} ${response.statusText}`);
6
+ }
7
+ const data = await response.json();
8
+ return (data.pets ?? data);
9
+ }
10
+ export async function findPetBySlug(slug) {
11
+ const manifest = await fetchManifest();
12
+ const lowerSlug = slug.toLowerCase();
13
+ return manifest.find((pet) => pet.slug.toLowerCase() === lowerSlug) ?? null;
14
+ }
15
+ export async function listPets() {
16
+ const manifest = await fetchManifest();
17
+ return manifest.map((pet) => ({
18
+ slug: pet.slug,
19
+ displayName: pet.displayName,
20
+ kind: pet.kind,
21
+ }));
22
+ }
23
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/petdex-api/client.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG,yCAAyC,CAAC;AAgB/D,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;IAE3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,6BAA6B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CACtE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAuB,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY;IAEZ,MAAM,QAAQ,GAAG,MAAM,aAAa,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,IAAI,IAAI,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;IAG5B,MAAM,QAAQ,GAAG,MAAM,aAAa,EAAE,CAAC;IACvC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC5B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,IAAI,EAAE,GAAG,CAAC,IAAI;KACf,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { PetManifestEntry } from "./client.js";
2
+ export declare function getPetDir(slug: string): string;
3
+ export declare function downloadPetAssets(pet: PetManifestEntry): Promise<{
4
+ spritesheetPath: string;
5
+ petJsonPath: string;
6
+ }>;
7
+ export declare function isPetDownloaded(slug: string): boolean;
8
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../../src/petdex-api/download.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAQD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B3D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAWrD"}
@@ -0,0 +1,45 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { homedir } from "node:os";
4
+ const PETDEX_DIR = path.join(homedir(), ".petdex-cc");
5
+ export function getPetDir(slug) {
6
+ return path.join(PETDEX_DIR, "pets", slug);
7
+ }
8
+ function resolveExtension(url) {
9
+ const pathname = new URL(url).pathname;
10
+ if (pathname.endsWith(".png"))
11
+ return ".png";
12
+ return ".webp";
13
+ }
14
+ export async function downloadPetAssets(pet) {
15
+ const petDir = getPetDir(pet.slug);
16
+ fs.mkdirSync(petDir, { recursive: true });
17
+ const spritesheetExt = resolveExtension(pet.spritesheetUrl);
18
+ const spritesheetPath = path.join(petDir, `spritesheet${spritesheetExt}`);
19
+ const petJsonPath = path.join(petDir, "pet.json");
20
+ // Download spritesheet
21
+ const spritesheetResponse = await fetch(pet.spritesheetUrl);
22
+ if (!spritesheetResponse.ok) {
23
+ throw new Error(`Failed to download spritesheet for ${pet.slug}: ${spritesheetResponse.status} ${spritesheetResponse.statusText}`);
24
+ }
25
+ const spritesheetBuffer = Buffer.from(await spritesheetResponse.arrayBuffer());
26
+ fs.writeFileSync(spritesheetPath, spritesheetBuffer);
27
+ // Download pet.json
28
+ const petJsonResponse = await fetch(pet.petJsonUrl);
29
+ if (!petJsonResponse.ok) {
30
+ throw new Error(`Failed to download pet.json for ${pet.slug}: ${petJsonResponse.status} ${petJsonResponse.statusText}`);
31
+ }
32
+ const petJsonBuffer = Buffer.from(await petJsonResponse.arrayBuffer());
33
+ fs.writeFileSync(petJsonPath, petJsonBuffer);
34
+ return { spritesheetPath, petJsonPath };
35
+ }
36
+ export function isPetDownloaded(slug) {
37
+ const petDir = getPetDir(slug);
38
+ if (!fs.existsSync(petDir))
39
+ return false;
40
+ const files = fs.readdirSync(petDir);
41
+ const hasSpritesheet = files.some((f) => f.startsWith("spritesheet.") && (f.endsWith(".webp") || f.endsWith(".png")));
42
+ const hasPetJson = files.includes("pet.json");
43
+ return hasSpritesheet && hasPetJson;
44
+ }
45
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../../src/petdex-api/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Speech bubble module.
3
+ *
4
+ * Manages the cartoon speech bubble displayed above the pet. Only one bubble
5
+ * is visible at a time; new bubbles immediately replace existing ones.
6
+ */
7
+ /**
8
+ * Truncates text to `maxLen` characters, appending "..." when truncated.
9
+ */
10
+ export declare function truncateText(text: string, maxLen?: number): string;
11
+ /**
12
+ * Immediately hides the speech bubble.
13
+ */
14
+ export declare function hideBubble(): void;
15
+ /**
16
+ * Shows a speech bubble with the given text for the specified duration.
17
+ *
18
+ * A new bubble replaces any currently-visible bubble. The bubble fades in
19
+ * over 200 ms and fades out after `durationMs`.
20
+ *
21
+ * @param text Text to display (will be truncated to 60 chars).
22
+ * @param durationMs How long to keep the bubble visible (default 3000 ms).
23
+ */
24
+ export declare function showBubble(text: string, durationMs?: number): void;
25
+ /**
26
+ * Shows an AI-generated speech bubble. These last 8 seconds, longer than
27
+ * regular event bubbles.
28
+ */
29
+ export declare function showAiBubble(text: string): void;
30
+ //# sourceMappingURL=bubble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bubble.d.ts","sourceRoot":"","sources":["../../../src/renderer/bubble.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAW,GAAG,MAAM,CAGtE;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CASjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAA4B,GAAG,IAAI,CAiBvF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE/C"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Speech bubble module.
3
+ *
4
+ * Manages the cartoon speech bubble displayed above the pet. Only one bubble
5
+ * is visible at a time; new bubbles immediately replace existing ones.
6
+ */
7
+ const BUBBLE_ELEMENT_ID = "bubble";
8
+ const HIDDEN_CLASS = "bubble-hidden";
9
+ const DEFAULT_DURATION_MS = 3000;
10
+ const AI_DURATION_MS = 8000;
11
+ const FADE_MS = 200;
12
+ let bubbleTimer = null;
13
+ function getBubble() {
14
+ return document.getElementById(BUBBLE_ELEMENT_ID);
15
+ }
16
+ /**
17
+ * Truncates text to `maxLen` characters, appending "..." when truncated.
18
+ */
19
+ export function truncateText(text, maxLen = 60) {
20
+ if (text.length <= maxLen)
21
+ return text;
22
+ return text.slice(0, maxLen - 3) + "...";
23
+ }
24
+ /**
25
+ * Immediately hides the speech bubble.
26
+ */
27
+ export function hideBubble() {
28
+ const el = getBubble();
29
+ if (el) {
30
+ el.classList.add(HIDDEN_CLASS);
31
+ }
32
+ if (bubbleTimer !== null) {
33
+ clearTimeout(bubbleTimer);
34
+ bubbleTimer = null;
35
+ }
36
+ }
37
+ /**
38
+ * Shows a speech bubble with the given text for the specified duration.
39
+ *
40
+ * A new bubble replaces any currently-visible bubble. The bubble fades in
41
+ * over 200 ms and fades out after `durationMs`.
42
+ *
43
+ * @param text Text to display (will be truncated to 60 chars).
44
+ * @param durationMs How long to keep the bubble visible (default 3000 ms).
45
+ */
46
+ export function showBubble(text, durationMs = DEFAULT_DURATION_MS) {
47
+ const el = getBubble();
48
+ if (!el)
49
+ return;
50
+ // Cancel any existing timer so the new bubble takes over.
51
+ if (bubbleTimer !== null) {
52
+ clearTimeout(bubbleTimer);
53
+ bubbleTimer = null;
54
+ }
55
+ el.textContent = truncateText(text);
56
+ el.classList.remove(HIDDEN_CLASS);
57
+ bubbleTimer = setTimeout(() => {
58
+ el.classList.add(HIDDEN_CLASS);
59
+ bubbleTimer = null;
60
+ }, durationMs);
61
+ }
62
+ /**
63
+ * Shows an AI-generated speech bubble. These last 8 seconds, longer than
64
+ * regular event bubbles.
65
+ */
66
+ export function showAiBubble(text) {
67
+ showBubble(text, AI_DURATION_MS);
68
+ }
69
+ //# sourceMappingURL=bubble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bubble.js","sourceRoot":"","sources":["../../../src/renderer/bubble.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AACnC,MAAM,YAAY,GAAG,eAAe,CAAC;AACrC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,MAAM,OAAO,GAAG,GAAG,CAAC;AAEpB,IAAI,WAAW,GAAyC,IAAI,CAAC;AAE7D,SAAS,SAAS;IAChB,OAAO,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB,EAAE;IAC5D,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IACvB,IAAI,EAAE,EAAE,CAAC;QACP,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,YAAY,CAAC,WAAW,CAAC,CAAC;QAC1B,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,aAAqB,mBAAmB;IAC/E,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE;QAAE,OAAO;IAEhB,0DAA0D;IAC1D,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,YAAY,CAAC,WAAW,CAAC,CAAC;QAC1B,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAElC,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE;QAC5B,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC/B,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC,EAAE,UAAU,CAAC,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,UAAU,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Click-through module.
3
+ *
4
+ * Makes the BrowserWindow click-through (transparent to mouse events) by
5
+ * default, and disables click-through only when the cursor is over the pet
6
+ * sprite area so the user can interact with the pet.
7
+ */
8
+ import type { BrowserWindow } from "electron";
9
+ /**
10
+ * Initialises click-through behaviour.
11
+ *
12
+ * - By default, `window.setIgnoreMouseEvents(true, { forward: true })` so
13
+ * clicks pass through transparent areas.
14
+ * - When the mouse enters the pet element bounds, click-through is disabled.
15
+ * - When the mouse leaves the pet element bounds, click-through is re-enabled.
16
+ *
17
+ * @param win The Electron BrowserWindow.
18
+ * @param petEl The pet sprite DOM element used for hit-testing.
19
+ */
20
+ export declare function initClickThrough(win: BrowserWindow, petEl: HTMLElement): void;
21
+ //# sourceMappingURL=click-through.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click-through.d.ts","sourceRoot":"","sources":["../../../src/renderer/click-through.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,WAAW,GACjB,IAAI,CAWN"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Click-through module.
3
+ *
4
+ * Makes the BrowserWindow click-through (transparent to mouse events) by
5
+ * default, and disables click-through only when the cursor is over the pet
6
+ * sprite area so the user can interact with the pet.
7
+ */
8
+ /**
9
+ * Initialises click-through behaviour.
10
+ *
11
+ * - By default, `window.setIgnoreMouseEvents(true, { forward: true })` so
12
+ * clicks pass through transparent areas.
13
+ * - When the mouse enters the pet element bounds, click-through is disabled.
14
+ * - When the mouse leaves the pet element bounds, click-through is re-enabled.
15
+ *
16
+ * @param win The Electron BrowserWindow.
17
+ * @param petEl The pet sprite DOM element used for hit-testing.
18
+ */
19
+ export function initClickThrough(win, petEl) {
20
+ // Default: click-through enabled.
21
+ win.setIgnoreMouseEvents(true, { forward: true });
22
+ petEl.addEventListener("mouseenter", () => {
23
+ win.setIgnoreMouseEvents(false);
24
+ });
25
+ petEl.addEventListener("mouseleave", () => {
26
+ win.setIgnoreMouseEvents(true, { forward: true });
27
+ });
28
+ }
29
+ //# sourceMappingURL=click-through.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click-through.js","sourceRoot":"","sources":["../../../src/renderer/click-through.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAkB,EAClB,KAAkB;IAElB,kCAAkC;IAClC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAElD,KAAK,CAAC,gBAAgB,CAAC,YAAY,EAAE,GAAG,EAAE;QACxC,GAAG,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,gBAAgB,CAAC,YAAY,EAAE,GAAG,EAAE;QACxC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Context menu module.
3
+ *
4
+ * Builds the right-click context menu for the pet. Electron Menu is
5
+ * available via the preload bridge in the renderer process.
6
+ */
7
+ import { BrowserWindow } from "electron";
8
+ /**
9
+ * Creates the pet context menu.
10
+ *
11
+ * Menu items:
12
+ * - "Show Pet" / "Hide Pet" toggle
13
+ * - Separator
14
+ * - "Switch Pet..."
15
+ * - "Settings..."
16
+ * - "About"
17
+ * - Separator
18
+ * - "Quit"
19
+ *
20
+ * @param win The BrowserWindow this menu controls.
21
+ * @returns An Electron Menu instance.
22
+ */
23
+ export declare function createContextMenu(win: BrowserWindow): Electron.Menu;
24
+ //# sourceMappingURL=context-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-menu.d.ts","sourceRoot":"","sources":["../../../src/renderer/context-menu.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAa,aAAa,EAAE,MAAM,UAAU,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,QAAQ,CAAC,IAAI,CA2DnE"}