@linxin666/dsh-pet 0.2.2 → 0.2.4

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/README.i18n.yaml +2 -2
  2. package/README.md +129 -3
  3. package/README.zh.md +129 -3
  4. package/assets/decorations/whale/decoration.json +20 -0
  5. package/assets/decorations/whale/whale-frames.png +0 -0
  6. package/assets/whale/pet.json +169 -20
  7. package/assets/whale-refined/pet.json +17 -2
  8. package/contracts/pet-manifest-v2.schema.json +281 -0
  9. package/contracts/status-decoration-v1.schema.json +144 -0
  10. package/contracts/voice-pack-v1.schema.json +234 -0
  11. package/lib/client.js +581 -38
  12. package/lib/client.js.map +1 -1
  13. package/lib/index.js +1684 -59
  14. package/lib/live2d-vendor.js +995 -0
  15. package/lib/live2d-vendor.js.map +1 -0
  16. package/lib/types/chatter.d.ts +61 -3
  17. package/lib/types/chatter.d.ts.map +1 -1
  18. package/lib/types/chatter.js +71 -12
  19. package/lib/types/client/PetDockEntry.d.ts.map +1 -1
  20. package/lib/types/client/PetDockEntry.js +2 -1
  21. package/lib/types/client/PetSettingsCard.d.ts +14 -0
  22. package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
  23. package/lib/types/client/PetSettingsCard.js +24 -1
  24. package/lib/types/client/PetSprite.d.ts +7 -1
  25. package/lib/types/client/PetSprite.d.ts.map +1 -1
  26. package/lib/types/client/PetSprite.js +120 -12
  27. package/lib/types/client/index.d.ts.map +1 -1
  28. package/lib/types/client/index.js +5 -0
  29. package/lib/types/client/locales.d.ts +14 -0
  30. package/lib/types/client/locales.d.ts.map +1 -1
  31. package/lib/types/client/locales.js +14 -0
  32. package/lib/types/client/phase-stream.d.ts +22 -0
  33. package/lib/types/client/phase-stream.d.ts.map +1 -0
  34. package/lib/types/client/phase-stream.js +28 -0
  35. package/lib/types/client/renderers/PetRendererSwitch.d.ts +25 -0
  36. package/lib/types/client/renderers/PetRendererSwitch.d.ts.map +1 -0
  37. package/lib/types/client/renderers/PetRendererSwitch.js +24 -0
  38. package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts +22 -0
  39. package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts.map +1 -0
  40. package/lib/types/client/renderers/live2d/Live2dVisualMount.js +75 -0
  41. package/lib/types/client/renderers/live2d/runtime.d.ts +89 -0
  42. package/lib/types/client/renderers/live2d/runtime.d.ts.map +1 -0
  43. package/lib/types/client/renderers/live2d/runtime.js +63 -0
  44. package/lib/types/client/renderers/live2d/vendor-entry.d.ts +15 -0
  45. package/lib/types/client/renderers/live2d/vendor-entry.d.ts.map +1 -0
  46. package/lib/types/client/renderers/live2d/vendor-entry.js +14 -0
  47. package/lib/types/client/renderers/live2d.d.ts +52 -0
  48. package/lib/types/client/renderers/live2d.d.ts.map +1 -0
  49. package/lib/types/client/renderers/live2d.js +192 -0
  50. package/lib/types/client/renderers/registry.d.ts +32 -0
  51. package/lib/types/client/renderers/registry.d.ts.map +1 -0
  52. package/lib/types/client/renderers/registry.js +49 -0
  53. package/lib/types/client/settings-form.d.ts.map +1 -1
  54. package/lib/types/client/settings-form.js +9 -6
  55. package/lib/types/contracts/renderer.d.ts +50 -0
  56. package/lib/types/contracts/renderer.d.ts.map +1 -0
  57. package/lib/types/contracts/renderer.js +15 -0
  58. package/lib/types/contracts/status-decoration.d.ts +85 -0
  59. package/lib/types/contracts/status-decoration.d.ts.map +1 -0
  60. package/lib/types/contracts/status-decoration.js +21 -0
  61. package/lib/types/decoration.d.ts +39 -0
  62. package/lib/types/decoration.d.ts.map +1 -0
  63. package/lib/types/decoration.js +210 -0
  64. package/lib/types/event-projection.d.ts +8 -3
  65. package/lib/types/event-projection.d.ts.map +1 -1
  66. package/lib/types/event-projection.js +9 -4
  67. package/lib/types/index.d.ts +2 -0
  68. package/lib/types/index.d.ts.map +1 -1
  69. package/lib/types/index.js +2 -0
  70. package/lib/types/manifest-v2.d.ts +129 -0
  71. package/lib/types/manifest-v2.d.ts.map +1 -0
  72. package/lib/types/manifest-v2.js +387 -0
  73. package/lib/types/model3.d.ts +26 -0
  74. package/lib/types/model3.d.ts.map +1 -0
  75. package/lib/types/model3.js +96 -0
  76. package/lib/types/registry.d.ts +112 -5
  77. package/lib/types/registry.d.ts.map +1 -1
  78. package/lib/types/registry.js +395 -38
  79. package/lib/types/routes.d.ts +39 -2
  80. package/lib/types/routes.d.ts.map +1 -1
  81. package/lib/types/routes.js +312 -13
  82. package/lib/types/service.d.ts +38 -1
  83. package/lib/types/service.d.ts.map +1 -1
  84. package/lib/types/service.js +46 -3
  85. package/lib/types/voice-pack.d.ts +98 -0
  86. package/lib/types/voice-pack.d.ts.map +1 -0
  87. package/lib/types/voice-pack.js +384 -0
  88. package/package.json +13 -10
  89. package/src/chatter.test.ts +89 -2
  90. package/src/chatter.ts +120 -14
  91. package/src/client/PetDockEntry.tsx +19 -11
  92. package/src/client/PetSettingsCard.tsx +57 -0
  93. package/src/client/PetSprite.test.tsx +265 -12
  94. package/src/client/PetSprite.tsx +165 -33
  95. package/src/client/index.ts +6 -0
  96. package/src/client/locales.ts +14 -0
  97. package/src/client/phase-stream.test.ts +76 -0
  98. package/src/client/phase-stream.ts +39 -0
  99. package/src/client/renderers/PetRendererSwitch.test.tsx +66 -0
  100. package/src/client/renderers/PetRendererSwitch.tsx +48 -0
  101. package/src/client/renderers/live2d/Live2dVisualMount.tsx +98 -0
  102. package/src/client/renderers/live2d/runtime.test.ts +61 -0
  103. package/src/client/renderers/live2d/runtime.ts +119 -0
  104. package/src/client/renderers/live2d/vendor-entry.ts +14 -0
  105. package/src/client/renderers/live2d.test.ts +263 -0
  106. package/src/client/renderers/live2d.ts +231 -0
  107. package/src/client/renderers/registry.ts +58 -0
  108. package/src/client/settings-form.ts +8 -6
  109. package/src/client/settings-section.module.css +23 -0
  110. package/src/contracts/renderer.ts +54 -0
  111. package/src/contracts/status-decoration.ts +78 -0
  112. package/src/decoration.test.ts +178 -0
  113. package/src/decoration.ts +220 -0
  114. package/src/event-projection.ts +10 -5
  115. package/src/index.ts +2 -0
  116. package/src/manifest-v2.test.ts +251 -0
  117. package/src/manifest-v2.ts +414 -0
  118. package/src/model3.test.ts +79 -0
  119. package/src/model3.ts +91 -0
  120. package/src/registry.test.ts +438 -2
  121. package/src/registry.ts +470 -38
  122. package/src/routes.ts +328 -14
  123. package/src/service.ts +65 -3
  124. package/src/voice-pack.test.ts +216 -0
  125. package/src/voice-pack.ts +413 -0
@@ -17,6 +17,11 @@
17
17
  * plugin has always shown, so existing installs keep their wording until the
18
18
  * scene cycles. No emoji anywhere (repository rule); ~ is the whale-girl's
19
19
  * signature.
20
+ *
21
+ * Since pet-center M4 (issue #677) every pool is overridable through a
22
+ * {@link VoicePoolsProvider}: the built-in pools are the fallback layer, and
23
+ * voice packs (per-pet voice.json / the global .voice.json) layer their
24
+ * pools on top at draw time.
20
25
  * @module @linxin666/dsh-pet/chatter
21
26
  */
22
27
  /** Status copy scenes — the situations a session bubble can report. */
@@ -27,6 +32,10 @@ export declare const STATUS_ROTATE_MS = 4000;
27
32
  export declare const STATUS_POOLS: Readonly<Record<StatusScene, readonly string[]>>;
28
33
  /** Tool families for friendlier per-tool status copy. */
29
34
  export type ToolCategory = 'read' | 'write' | 'edit' | 'shell' | 'grep' | 'find' | 'ls' | 'webSearch' | 'webFetch' | 'mcp' | 'memory' | 'subagent' | 'todo' | 'browser' | 'git' | 'ask' | 'generic';
35
+ /** Every status scene key, in declaration order (voice-pack key allow-list). */
36
+ export declare const STATUS_SCENES: readonly StatusScene[];
37
+ /** Every tool-family key, in declaration order (voice-pack key allow-list). */
38
+ export declare const TOOL_CATEGORIES: readonly ToolCategory[];
30
39
  /** Map a raw tool name onto its copy family (working-activity style regexes). */
31
40
  export declare function toolCategory(toolName: string): ToolCategory;
32
41
  /**
@@ -52,16 +61,23 @@ export declare function toolArgHint(toolName: string, argumentsJson: string): st
52
61
  * stretch keeps changing its wording.
53
62
  */
54
63
  export declare class StatusVoice {
64
+ private readonly pools;
55
65
  private readonly rotateMs;
56
66
  private readonly counters;
57
67
  private lastScene;
58
68
  private lastLine;
59
69
  private lastLineAt;
60
- constructor(rotateMs?: number);
70
+ constructor(pools?: VoicePoolsProvider, rotateMs?: number);
61
71
  /** Draw the next line of one pool, advancing its round-robin cursor. */
62
72
  private draw;
63
73
  /** Reuse the stable line or advance when the cadence elapsed. */
64
74
  private voice;
75
+ /**
76
+ * A scene's effective pool: the voice-pack override when it carries lines,
77
+ * else the built-in pool. Empty overrides fall back rather than blank the
78
+ * bubble — a scene line always renders.
79
+ */
80
+ private scenePool;
65
81
  /** Status line for a phase scene. */
66
82
  scene(scene: StatusScene, nowMs: number): string;
67
83
  /** Status line for a tool call, with the real-argument hint when known. */
@@ -85,22 +101,64 @@ export declare const WHISPER_TTL_MS = 8000;
85
101
  export declare const WHISPER_GENERIC_POOL: readonly string[];
86
102
  /** Keyword-triggered whisper rules, most specific moods first. */
87
103
  export declare const WHISPER_RULES: readonly WhisperRule[];
104
+ /**
105
+ * Voice-pack overrides (pet-center M4, issue #677): the content a voice
106
+ * pack can replace, one pool at a time. Every field is optional — missing
107
+ * keys inherit the built-in pools. Resolution happens at draw time through
108
+ * a provider function, so swapping pets (or editing the global file) re-
109
+ * voices live engines without rebuilding them.
110
+ *
111
+ * Override semantics:
112
+ * - status/tools/toolRemaining: a non-empty override replaces the built-in
113
+ * pool for that key; an empty override falls back to the built-in pool
114
+ * (a scene line always renders, so it can never be blanked).
115
+ * - whispers.generic / whispers.rules: the override REPLACES the built-in
116
+ * section; an empty array mutes that channel (ambient or keyword).
117
+ */
118
+ export interface VoicePackOverrides {
119
+ /** Status copy pools by scene; each key replaces that scene's pool. */
120
+ status?: Partial<Record<StatusScene, readonly string[]>>;
121
+ /** Tool copy pools by family; each key replaces that family's pool. */
122
+ tools?: Partial<Record<ToolCategory, readonly string[]>>;
123
+ /** The parallel-tools count line pool ({n} interpolates the count). */
124
+ toolRemaining?: readonly string[];
125
+ /** Murmur pools; each section replaces the built-in one as a whole. */
126
+ whispers?: {
127
+ /** Ambient inner-whisper pool (empty mutes ambient whispers). */
128
+ generic?: readonly string[];
129
+ /** Ordered keyword rules (empty disables keyword-triggered whispers). */
130
+ rules?: readonly WhisperRule[];
131
+ };
132
+ }
133
+ /** Read the current effective voice-pack overrides (draw-time resolution). */
134
+ export type VoicePoolsProvider = () => VoicePackOverrides;
135
+ /** The built-in voice pack: the plugin's default copy, unchanged since v1. */
136
+ export declare const BUILTIN_VOICE_PACK: VoicePackOverrides;
88
137
  /**
89
138
  * The murmur engine (碎碎念): watches the model's own output and lets the pet
90
139
  * whisper its inner voice. Two ways to earn a whisper:
91
140
  * - a keyword rule matches the fresh chunk text (themed whisper);
92
141
  * - enough output volume flowed by without one (ambient whisper).
93
142
  * A cooldown keeps whispers occasional; all picks are round-robin so tests
94
- * reproduce exact lines.
143
+ * reproduce exact lines. The voice-pack provider (pet-center M4) swaps the
144
+ * pools at draw time, so a pet switch re-voices live engines in place.
95
145
  */
96
146
  export declare class WhisperEngine {
147
+ private readonly pools;
97
148
  private readonly cooldownMs;
98
149
  private readonly charBudget;
99
150
  private readonly counters;
100
151
  private genericCursor;
101
152
  private lastWhisperAt;
102
153
  private charsSinceWhisper;
103
- constructor(cooldownMs?: number, charBudget?: number);
154
+ constructor(pools?: VoicePoolsProvider, cooldownMs?: number, charBudget?: number);
155
+ /**
156
+ * Effective keyword rules: an override replaces the built-in rules as a
157
+ * whole; an explicit empty array disables keyword-triggered whispers.
158
+ */
159
+ private rules;
160
+ /** Effective ambient pool (an explicit empty array mutes ambient whispers). */
161
+ private generic;
104
162
  /**
105
163
  * Feed one model-output chunk (reasoning or text). Returns the whisper to
106
164
  * show, or undefined when the moment stays quiet.
@@ -1 +1 @@
1
- {"version":3,"file":"chatter.d.ts","sourceRoot":"","sources":["../../src/chatter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chatter.d.ts","sourceRoot":"","sources":["../../src/chatter.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,11 @@
17
17
  * plugin has always shown, so existing installs keep their wording until the
18
18
  * scene cycles. No emoji anywhere (repository rule); ~ is the whale-girl's
19
19
  * signature.
20
+ *
21
+ * Since pet-center M4 (issue #677) every pool is overridable through a
22
+ * {@link VoicePoolsProvider}: the built-in pools are the fallback layer, and
23
+ * voice packs (per-pet voice.json / the global .voice.json) layer their
24
+ * pools on top at draw time.
20
25
  * @module @linxin666/dsh-pet/chatter
21
26
  */
22
27
  /** While a scene persists, its copy advances on this cadence (ms). */
@@ -156,6 +161,16 @@ export const STATUS_POOLS = {
156
161
  '蹲一个继续的指令',
157
162
  ],
158
163
  };
164
+ /** Every status scene key, in declaration order (voice-pack key allow-list). */
165
+ export const STATUS_SCENES = [
166
+ 'prepare', 'waiting', 'thinking', 'review', 'toolResult', 'done',
167
+ 'failed', 'toolFailed', 'maxTokens', 'interrupted', 'blocked',
168
+ ];
169
+ /** Every tool-family key, in declaration order (voice-pack key allow-list). */
170
+ export const TOOL_CATEGORIES = [
171
+ 'read', 'write', 'edit', 'shell', 'grep', 'find', 'ls', 'webSearch',
172
+ 'webFetch', 'mcp', 'memory', 'subagent', 'todo', 'browser', 'git', 'ask', 'generic',
173
+ ];
159
174
  /** Map a raw tool name onto its copy family (working-activity style regexes). */
160
175
  export function toolCategory(toolName) {
161
176
  const name = toolName.toLowerCase();
@@ -414,12 +429,16 @@ export function toolArgHint(toolName, argumentsJson) {
414
429
  * stretch keeps changing its wording.
415
430
  */
416
431
  export class StatusVoice {
432
+ pools;
417
433
  rotateMs;
418
434
  counters = new Map();
419
435
  lastScene = '';
420
436
  lastLine = '';
421
437
  lastLineAt = Number.NEGATIVE_INFINITY;
422
- constructor(rotateMs = STATUS_ROTATE_MS) {
438
+ constructor(pools = () => BUILTIN_VOICE_PACK, rotateMs = STATUS_ROTATE_MS) {
439
+ // Plain property assignment, not parameter properties: this module is
440
+ // imported by scripts/ under node's strip-only mode (pet-center M4).
441
+ this.pools = pools;
423
442
  this.rotateMs = rotateMs;
424
443
  }
425
444
  /** Draw the next line of one pool, advancing its round-robin cursor. */
@@ -437,22 +456,35 @@ export class StatusVoice {
437
456
  this.lastLineAt = nowMs;
438
457
  return this.lastLine;
439
458
  }
459
+ /**
460
+ * A scene's effective pool: the voice-pack override when it carries lines,
461
+ * else the built-in pool. Empty overrides fall back rather than blank the
462
+ * bubble — a scene line always renders.
463
+ */
464
+ scenePool(scene) {
465
+ const override = this.pools().status?.[scene];
466
+ return override !== undefined && override.length > 0 ? override : STATUS_POOLS[scene];
467
+ }
440
468
  /** Status line for a phase scene. */
441
469
  scene(scene, nowMs) {
442
- return this.voice('scene:' + scene, 'pool:' + scene, STATUS_POOLS[scene], nowMs);
470
+ return this.voice('scene:' + scene, 'pool:' + scene, this.scenePool(scene), nowMs);
443
471
  }
444
472
  /** Status line for a tool call, with the real-argument hint when known. */
445
473
  tool(toolName, displayName, hint, nowMs) {
446
474
  const category = toolCategory(toolName);
447
- const line = this.voice('tool:' + category, 'tool:' + category, TOOL_POOLS[category], nowMs);
475
+ const override = this.pools().tools?.[category];
476
+ const pool = override !== undefined && override.length > 0 ? override : TOOL_POOLS[category];
477
+ const line = this.voice('tool:' + category, 'tool:' + category, pool, nowMs);
448
478
  return line
449
- .replace('{tool}', displayName)
450
- .replace('{hint}', hint ?? displayName);
479
+ .replaceAll('{tool}', displayName)
480
+ .replaceAll('{hint}', hint ?? displayName);
451
481
  }
452
482
  /** Status line while sibling tools still run (always reflects the count). */
453
483
  toolRemaining(count, nowMs) {
454
- return this.voice('toolRemaining', 'toolRemaining', TOOL_REMAINING_POOL, nowMs)
455
- .replace('{n}', String(count));
484
+ const override = this.pools().toolRemaining;
485
+ const pool = override !== undefined && override.length > 0 ? override : TOOL_REMAINING_POOL;
486
+ return this.voice('toolRemaining', 'toolRemaining', pool, nowMs)
487
+ .replaceAll('{n}', String(count));
456
488
  }
457
489
  }
458
490
  /** Murmur pacing: cooldown between whispers and output volume that earns one. */
@@ -701,25 +733,48 @@ export const WHISPER_RULES = [
701
733
  ],
702
734
  },
703
735
  ];
736
+ /** The built-in voice pack: the plugin's default copy, unchanged since v1. */
737
+ export const BUILTIN_VOICE_PACK = {
738
+ status: STATUS_POOLS,
739
+ tools: TOOL_POOLS,
740
+ toolRemaining: TOOL_REMAINING_POOL,
741
+ whispers: { generic: WHISPER_GENERIC_POOL, rules: WHISPER_RULES },
742
+ };
704
743
  /**
705
744
  * The murmur engine (碎碎念): watches the model's own output and lets the pet
706
745
  * whisper its inner voice. Two ways to earn a whisper:
707
746
  * - a keyword rule matches the fresh chunk text (themed whisper);
708
747
  * - enough output volume flowed by without one (ambient whisper).
709
748
  * A cooldown keeps whispers occasional; all picks are round-robin so tests
710
- * reproduce exact lines.
749
+ * reproduce exact lines. The voice-pack provider (pet-center M4) swaps the
750
+ * pools at draw time, so a pet switch re-voices live engines in place.
711
751
  */
712
752
  export class WhisperEngine {
753
+ pools;
713
754
  cooldownMs;
714
755
  charBudget;
715
756
  counters = new Map();
716
757
  genericCursor = 0;
717
758
  lastWhisperAt = Number.NEGATIVE_INFINITY;
718
759
  charsSinceWhisper = 0;
719
- constructor(cooldownMs = WHISPER_COOLDOWN_MS, charBudget = WHISPER_CHAR_BUDGET) {
760
+ constructor(pools = () => BUILTIN_VOICE_PACK, cooldownMs = WHISPER_COOLDOWN_MS, charBudget = WHISPER_CHAR_BUDGET) {
761
+ this.pools = pools;
720
762
  this.cooldownMs = cooldownMs;
721
763
  this.charBudget = charBudget;
722
764
  }
765
+ /**
766
+ * Effective keyword rules: an override replaces the built-in rules as a
767
+ * whole; an explicit empty array disables keyword-triggered whispers.
768
+ */
769
+ rules() {
770
+ const override = this.pools().whispers?.rules;
771
+ return override === undefined ? WHISPER_RULES : override;
772
+ }
773
+ /** Effective ambient pool (an explicit empty array mutes ambient whispers). */
774
+ generic() {
775
+ const override = this.pools().whispers?.generic;
776
+ return override === undefined ? WHISPER_GENERIC_POOL : override;
777
+ }
723
778
  /**
724
779
  * Feed one model-output chunk (reasoning or text). Returns the whisper to
725
780
  * show, or undefined when the moment stays quiet.
@@ -733,8 +788,9 @@ export class WhisperEngine {
733
788
  return undefined;
734
789
  }
735
790
  const haystack = text.toLowerCase();
736
- for (let ruleIndex = 0; ruleIndex < WHISPER_RULES.length; ruleIndex += 1) {
737
- const rule = WHISPER_RULES[ruleIndex];
791
+ const rules = this.rules();
792
+ for (let ruleIndex = 0; ruleIndex < rules.length; ruleIndex += 1) {
793
+ const rule = rules[ruleIndex];
738
794
  if (!rule.keywords.some(keyword => haystack.includes(keyword)))
739
795
  continue;
740
796
  const index = (this.counters.get(ruleIndex) ?? 0) % rule.pool.length;
@@ -744,7 +800,10 @@ export class WhisperEngine {
744
800
  this.charsSinceWhisper += text.length;
745
801
  if (this.charsSinceWhisper < this.charBudget)
746
802
  return undefined;
747
- const line = WHISPER_GENERIC_POOL[this.genericCursor % WHISPER_GENERIC_POOL.length];
803
+ const generic = this.generic();
804
+ if (generic.length === 0)
805
+ return undefined;
806
+ const line = generic[this.genericCursor % generic.length];
748
807
  this.genericCursor += 1;
749
808
  return this.speak(line, nowMs);
750
809
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PetDockEntry.d.ts","sourceRoot":"","sources":["../../../src/client/PetDockEntry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAmC,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,KAAK,EAAE,gBAAgB,CAAA;IACvB,kFAAkF;IAClF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAA;IACf,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,2DAA2D;IAC3D,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,iCAAiC;IACjC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAC3B,WAAW,GACT,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAI1B;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAsDnE"}
1
+ {"version":3,"file":"PetDockEntry.d.ts","sourceRoot":"","sources":["../../../src/client/PetDockEntry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAmC,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGtD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,KAAK,EAAE,gBAAgB,CAAA;IACvB,kFAAkF;IAClF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAA;IACf,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,2DAA2D;IAC3D,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,iCAAiC;IACjC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAC3B,WAAW,GACT,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAI1B;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CA6DnE"}
@@ -13,6 +13,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
13
13
  */
14
14
  import { useEffect, useSyncExternalStore } from 'react';
15
15
  import { PetSprite } from './PetSprite.js';
16
+ import { PetRendererSwitch } from './renderers/PetRendererSwitch.js';
16
17
  import styles from './pet.module.css';
17
18
  const DEFAULT_DISPLAY = { visible: true, size: 160, right: 24, bottom: 20 };
18
19
  /**
@@ -35,7 +36,7 @@ export function PetDockEntry(props) {
35
36
  if (visible) {
36
37
  return (_jsx("span", { "data-pet-dock": true, "data-testid": "pet-dock", children: snapshot === null || definition === null
37
38
  ? null
38
- : (_jsx(PetSprite, { snapshot: snapshot, definition: definition, display: snapshot.display, feedback: feedback, onPet: props.pet, onFeed: props.feed, onHide: props.hide, onDragEnd: props.dragEnd, onRename: props.rename, onOpenSession: props.openSession, onFeedbackDone: props.feedbackDone, t: props.t })) }));
39
+ : (_jsx(PetRendererSwitch, { definition: definition, phase: snapshot?.phase ?? 'idle', onPet: props.pet, t: props.t, children: _jsx(PetSprite, { snapshot: snapshot, definition: definition, display: snapshot.display, feedback: feedback, onPet: props.pet, onFeed: props.feed, onHide: props.hide, onDragEnd: props.dragEnd, onRename: props.rename, onOpenSession: props.openSession, onFeedbackDone: props.feedbackDone, t: props.t }) })) }));
39
40
  }
40
41
  const display = snapshot?.display ?? DEFAULT_DISPLAY;
41
42
  return (_jsx("button", { type: "button", className: styles.summon, style: {
@@ -24,6 +24,8 @@ export interface PetSettings {
24
24
  bottom?: number;
25
25
  /** Selected pet id (a registry entry). */
26
26
  petId?: string;
27
+ /** Status-decoration master switch (pet-center M5, #567). */
28
+ decorationEnabled?: boolean;
27
29
  }
28
30
  /** What the pet settings card renders. */
29
31
  export interface PetSettingsCardState extends CardShell {
@@ -39,11 +41,15 @@ export interface PetSettingsCardState extends CardShell {
39
41
  bottom: CardFieldState;
40
42
  /** Selected pet. */
41
43
  petId: CardFieldState;
44
+ /** Status-decoration master switch. */
45
+ decorationEnabled: CardFieldState;
42
46
  /** Pet choices (registry ids + display names), loaded from the host. */
43
47
  petChoices: readonly {
44
48
  value: string;
45
49
  label: string;
46
50
  }[];
51
+ /** Registry diagnostics (v1 migration hints, invalid entries), host-served. */
52
+ petDiagnostics: readonly PetDiagnosticView[];
47
53
  }
48
54
  /** The registration-side face the card's slot entry injects. */
49
55
  export interface PetSettingsCardFace extends CardActions {
@@ -52,16 +58,24 @@ export interface PetSettingsCardFace extends CardActions {
52
58
  petSettingsCard: SnapshotStore<PetSettingsCardState>;
53
59
  };
54
60
  }
61
+ /** One registry diagnostic as served by '/api/pet/diagnostics' (#623). */
62
+ export interface PetDiagnosticView {
63
+ level: 'error' | 'warning';
64
+ message: string;
65
+ }
55
66
  /** Bridges the 'pet' scope onto the card's staged form. */
56
67
  export declare class PetSettingsCardController {
57
68
  private readonly form;
58
69
  private readonly store;
59
70
  private readonly petChoices;
60
71
  private readonly petLabels;
72
+ private diagnostics;
61
73
  private loaded;
62
74
  private attempts;
63
75
  /** @param scope - the bound settings scope for the 'pet' namespace. */
64
76
  constructor(scope: SettingsScope<PetSettings>);
77
+ /** Fetch registry diagnostics once (soft-fail: an empty list on error). */
78
+ private loadDiagnostics;
65
79
  /** Resolve the registry choices once (retried a few times on failure). */
66
80
  private loadPets;
67
81
  private projection;
@@ -1 +1 @@
1
- {"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAI1F,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAG1J,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qBAAqB;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,4BAA4B;IAC5B,OAAO,EAAE,cAAc,CAAA;IACvB,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,iBAAiB;IACjB,IAAI,EAAE,cAAc,CAAA;IACpB,mBAAmB;IACnB,KAAK,EAAE,cAAc,CAAA;IACrB,oBAAoB;IACpB,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB;IACpB,KAAK,EAAE,cAAc,CAAA;IACrB,wEAAwE;IACxE,UAAU,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CACxD;AAED,gEAAgE;AAChE,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,KAAK,EAAE;QACL,iEAAiE;QACjE,eAAe,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;KACrD,CAAA;CACF;AAeD,2DAA2D;AAC3D,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAI3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAI;IAEpB,uEAAuE;IACvE,YAAY,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,EAW5C;IAED,0EAA0E;YAC5D,QAAQ;IAgBtB,OAAO,CAAC,UAAU;IAalB;;;OAGG;IACH,MAAM,IAAI,mBAAmB,CAE5B;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAEd;CACF;AAED,0DAA0D;AAC1D,MAAM,MAAM,oBAAoB,GAC9B,WAAW,CAAC,KAAK,CAAC,GAChB,UAAU,CAAC,mBAAmB,CAAC,CAAA;AAEnC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,+BAuF1D;AAED,8DAA8D;AAC9D,MAAM,MAAM,uBAAuB,GACjC,YAAY,CAAC,kBAAkB,CAAC,GAC9B,WAAW,CAAC,KAAK,CAAC,GAClB,UAAU,CAAC,mBAAmB,CAAC,CAAA;AAEnC,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,SAAS,CAO5E"}
1
+ {"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"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"}
@@ -9,6 +9,14 @@ async function fetchPetChoices() {
9
9
  throw new Error('pet pets failed: ' + response.status);
10
10
  return (await response.json());
11
11
  }
12
+ /** Fetch the registry diagnostics (v1 migration hints, invalid entries). */
13
+ async function fetchPetDiagnostics() {
14
+ const response = await fetch('/api/pet/diagnostics');
15
+ if (!response.ok)
16
+ throw new Error('pet diagnostics failed: ' + response.status);
17
+ const body = (await response.json());
18
+ return body.diagnostics ?? [];
19
+ }
12
20
  /** Bridges the 'pet' scope onto the card's staged form. */
13
21
  export class PetSettingsCardController {
14
22
  form;
@@ -18,12 +26,14 @@ export class PetSettingsCardController {
18
26
  // without rebuilding the form.
19
27
  petChoices = [];
20
28
  petLabels = new Map();
29
+ diagnostics = [];
21
30
  loaded = false;
22
31
  attempts = 0;
23
32
  /** @param scope - the bound settings scope for the 'pet' namespace. */
24
33
  constructor(scope) {
25
34
  this.form = new CardForm(scope, [
26
35
  booleanField('enabled'),
36
+ booleanField('decorationEnabled'),
27
37
  booleanField('visible'),
28
38
  numberField('size'),
29
39
  numberField('right'),
@@ -32,6 +42,17 @@ export class PetSettingsCardController {
32
42
  ]);
33
43
  this.store = this.form.bind(() => this.projection());
34
44
  void this.loadPets();
45
+ void this.loadDiagnostics();
46
+ }
47
+ /** Fetch registry diagnostics once (soft-fail: an empty list on error). */
48
+ async loadDiagnostics() {
49
+ try {
50
+ this.diagnostics = await fetchPetDiagnostics();
51
+ this.store.set(this.projection());
52
+ }
53
+ catch {
54
+ this.diagnostics = [];
55
+ }
35
56
  }
36
57
  /** Resolve the registry choices once (retried a few times on failure). */
37
58
  async loadPets() {
@@ -56,12 +77,14 @@ export class PetSettingsCardController {
56
77
  return {
57
78
  ...this.form.shell(),
58
79
  enabled: this.form.field('enabled'),
80
+ decorationEnabled: this.form.field('decorationEnabled'),
59
81
  visible: this.form.field('visible'),
60
82
  size: this.form.field('size'),
61
83
  right: this.form.field('right'),
62
84
  bottom: this.form.field('bottom'),
63
85
  petId: this.form.field('petId'),
64
86
  petChoices: this.petChoices.map(id => ({ value: id, label: this.petLabels.get(id) ?? id })),
87
+ petDiagnostics: this.diagnostics,
65
88
  };
66
89
  }
67
90
  /**
@@ -94,7 +117,7 @@ export function PetSettingsCard(props) {
94
117
  invalidLabel: t('settings.invalidNumber'),
95
118
  disabled,
96
119
  };
97
- return (_jsxs(PluginSettingsCard, { t: t, titleKey: "settings.title", descriptionKey: "settings.description", state: state, onSave: props.save, onDiscard: props.discard, alwaysOpen: true, children: [_jsx(BooleanField, { id: "settings-pet-enabled", label: t('settings.enabled'), hint: t('settings.enabledHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.enabled, onEdit: (text) => { props.edit('enabled', text); }, onReset: () => { props.resetField('enabled'); } }), _jsx(ChoiceField, { id: "settings-pet-pet", label: t('settings.pet'), hint: t('settings.petHint'), inheritLabel: t('settings.inherit'), ...fieldProps, ...state.petId, choices: state.petChoices, onEdit: (text) => { props.edit('petId', text); }, onReset: () => { props.resetField('petId'); } }), _jsx(BooleanField, { id: "settings-pet-visible", label: t('settings.visible'), hint: t('settings.visibleHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.visible, onEdit: (text) => { props.edit('visible', text); }, onReset: () => { props.resetField('visible'); } }), _jsx(ValueField, { id: "settings-pet-size", label: t('settings.size'), hint: t('settings.sizeHint'), numeric: true, ...fieldProps, ...state.size, onEdit: (text) => { props.edit('size', text); }, onReset: () => { props.resetField('size'); } }), _jsx(ValueField, { id: "settings-pet-right", label: t('settings.right'), hint: t('settings.rightHint'), numeric: true, ...fieldProps, ...state.right, onEdit: (text) => { props.edit('right', text); }, onReset: () => { props.resetField('right'); } }), _jsx(ValueField, { id: "settings-pet-bottom", label: t('settings.bottom'), hint: t('settings.bottomHint'), numeric: true, ...fieldProps, ...state.bottom, onEdit: (text) => { props.edit('bottom', text); }, onReset: () => { props.resetField('bottom'); } })] }));
120
+ return (_jsxs(PluginSettingsCard, { t: t, titleKey: "settings.title", descriptionKey: "settings.description", state: state, onSave: props.save, onDiscard: props.discard, alwaysOpen: true, children: [_jsx(BooleanField, { id: "settings-pet-enabled", label: t('settings.enabled'), hint: t('settings.enabledHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.enabled, onEdit: (text) => { props.edit('enabled', text); }, onReset: () => { props.resetField('enabled'); } }), _jsx(BooleanField, { id: "settings-pet-decoration", label: t('settings.decoration'), hint: t('settings.decorationHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.decorationEnabled, onEdit: (text) => { props.edit('decorationEnabled', text); }, onReset: () => { props.resetField('decorationEnabled'); } }), _jsx(ChoiceField, { id: "settings-pet-pet", label: t('settings.pet'), hint: t('settings.petHint'), inheritLabel: t('settings.inherit'), ...fieldProps, ...state.petId, choices: state.petChoices, onEdit: (text) => { props.edit('petId', text); }, onReset: () => { props.resetField('petId'); } }), state.petDiagnostics.length === 0 ? null : (_jsxs("li", { className: sectionCss.diagnostics, "data-dsh-part": "diagnostics", children: [_jsx("span", { className: sectionCss.diagnosticsTitle, children: t('settings.diagnosticsTitle') }), _jsx("ul", { children: state.petDiagnostics.map((diagnostic, index) => (_jsx("li", { "data-level": diagnostic.level, children: diagnostic.message }, index))) })] })), _jsx(BooleanField, { id: "settings-pet-visible", label: t('settings.visible'), hint: t('settings.visibleHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.visible, onEdit: (text) => { props.edit('visible', text); }, onReset: () => { props.resetField('visible'); } }), _jsx(ValueField, { id: "settings-pet-size", label: t('settings.size'), hint: t('settings.sizeHint'), numeric: true, ...fieldProps, ...state.size, onEdit: (text) => { props.edit('size', text); }, onReset: () => { props.resetField('size'); } }), _jsx(ValueField, { id: "settings-pet-right", label: t('settings.right'), hint: t('settings.rightHint'), numeric: true, ...fieldProps, ...state.right, onEdit: (text) => { props.edit('right', text); }, onReset: () => { props.resetField('right'); } }), _jsx(ValueField, { id: "settings-pet-bottom", label: t('settings.bottom'), hint: t('settings.bottomHint'), numeric: true, ...fieldProps, ...state.bottom, onEdit: (text) => { props.edit('bottom', text); }, onReset: () => { props.resetField('bottom'); } })] }));
98
121
  }
99
122
  /** Render the pet settings card as a first-level settings page. */
100
123
  export function PetSettingsSection(props) {
@@ -8,7 +8,7 @@
8
8
  * pet id), so one component renders every registry entry.
9
9
  * @module @linxin666/dsh-pet/client/PetSprite
10
10
  */
11
- import type { ReactPortal } from 'react';
11
+ import type { ReactNode, ReactPortal } from 'react';
12
12
  import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
13
13
  import type { PetDisplayConfig } from '../persist.ts';
14
14
  import type { PetStateView } from '../service.ts';
@@ -39,6 +39,12 @@ export interface PetSpriteProps {
39
39
  onOpenSession: (sessionId: string) => void;
40
40
  /** Clear the reaction bubble (after its CSS animation). */
41
41
  onFeedbackDone: () => void;
42
+ /**
43
+ * Custom visual replacing the sprite2d atlas animation (pet-center M3).
44
+ * The chrome (drag, bubbles, panel, tap economy) is untouched: the visual
45
+ * renders inside the sprite box, and the atlas load + frame loop skip.
46
+ */
47
+ visual?: ReactNode;
42
48
  /** Locale translate seat (namespace-bound). */
43
49
  t: TranslateNS<typeof NS>;
44
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PetSprite.d.ts","sourceRoot":"","sources":["../../../src/client/PetSprite.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAoD,WAAW,EAAE,MAAM,OAAO,CAAA;AAG1F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,UAAU,EAAE,aAAa,CAAA;IACzB,qDAAqD;IACrD,OAAO,EAAE,gBAAgB,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,4DAA4D;IAC5D,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,2DAA2D;IAC3D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,+CAA+C;IAC/C,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,WAAW,CAud5D"}
1
+ {"version":3,"file":"PetSprite.d.ts","sourceRoot":"","sources":["../../../src/client/PetSprite.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAkE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAGnH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,UAAU,EAAE,aAAa,CAAA;IACzB,qDAAqD;IACrD,OAAO,EAAE,gBAAgB,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,4DAA4D;IAC5D,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,2DAA2D;IAC3D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,+CAA+C;IAC/C,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;CAC1B;AAkFD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,WAAW,CAygB5D"}