@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.
- package/README.i18n.yaml +2 -2
- package/README.md +129 -3
- package/README.zh.md +129 -3
- package/assets/decorations/whale/decoration.json +20 -0
- package/assets/decorations/whale/whale-frames.png +0 -0
- package/assets/whale/pet.json +169 -20
- package/assets/whale-refined/pet.json +17 -2
- package/contracts/pet-manifest-v2.schema.json +281 -0
- package/contracts/status-decoration-v1.schema.json +144 -0
- package/contracts/voice-pack-v1.schema.json +234 -0
- package/lib/client.js +581 -38
- package/lib/client.js.map +1 -1
- package/lib/index.js +1684 -59
- package/lib/live2d-vendor.js +995 -0
- package/lib/live2d-vendor.js.map +1 -0
- package/lib/types/chatter.d.ts +61 -3
- package/lib/types/chatter.d.ts.map +1 -1
- package/lib/types/chatter.js +71 -12
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +2 -1
- package/lib/types/client/PetSettingsCard.d.ts +14 -0
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +24 -1
- package/lib/types/client/PetSprite.d.ts +7 -1
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +120 -12
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +5 -0
- package/lib/types/client/locales.d.ts +14 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +14 -0
- package/lib/types/client/phase-stream.d.ts +22 -0
- package/lib/types/client/phase-stream.d.ts.map +1 -0
- package/lib/types/client/phase-stream.js +28 -0
- package/lib/types/client/renderers/PetRendererSwitch.d.ts +25 -0
- package/lib/types/client/renderers/PetRendererSwitch.d.ts.map +1 -0
- package/lib/types/client/renderers/PetRendererSwitch.js +24 -0
- package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts +22 -0
- package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d/Live2dVisualMount.js +75 -0
- package/lib/types/client/renderers/live2d/runtime.d.ts +89 -0
- package/lib/types/client/renderers/live2d/runtime.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d/runtime.js +63 -0
- package/lib/types/client/renderers/live2d/vendor-entry.d.ts +15 -0
- package/lib/types/client/renderers/live2d/vendor-entry.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d/vendor-entry.js +14 -0
- package/lib/types/client/renderers/live2d.d.ts +52 -0
- package/lib/types/client/renderers/live2d.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d.js +192 -0
- package/lib/types/client/renderers/registry.d.ts +32 -0
- package/lib/types/client/renderers/registry.d.ts.map +1 -0
- package/lib/types/client/renderers/registry.js +49 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +9 -6
- package/lib/types/contracts/renderer.d.ts +50 -0
- package/lib/types/contracts/renderer.d.ts.map +1 -0
- package/lib/types/contracts/renderer.js +15 -0
- package/lib/types/contracts/status-decoration.d.ts +85 -0
- package/lib/types/contracts/status-decoration.d.ts.map +1 -0
- package/lib/types/contracts/status-decoration.js +21 -0
- package/lib/types/decoration.d.ts +39 -0
- package/lib/types/decoration.d.ts.map +1 -0
- package/lib/types/decoration.js +210 -0
- package/lib/types/event-projection.d.ts +8 -3
- package/lib/types/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +9 -4
- package/lib/types/index.d.ts +2 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +2 -0
- package/lib/types/manifest-v2.d.ts +129 -0
- package/lib/types/manifest-v2.d.ts.map +1 -0
- package/lib/types/manifest-v2.js +387 -0
- package/lib/types/model3.d.ts +26 -0
- package/lib/types/model3.d.ts.map +1 -0
- package/lib/types/model3.js +96 -0
- package/lib/types/registry.d.ts +112 -5
- package/lib/types/registry.d.ts.map +1 -1
- package/lib/types/registry.js +395 -38
- package/lib/types/routes.d.ts +39 -2
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +312 -13
- package/lib/types/service.d.ts +38 -1
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +46 -3
- package/lib/types/voice-pack.d.ts +98 -0
- package/lib/types/voice-pack.d.ts.map +1 -0
- package/lib/types/voice-pack.js +384 -0
- package/package.json +13 -10
- package/src/chatter.test.ts +89 -2
- package/src/chatter.ts +120 -14
- package/src/client/PetDockEntry.tsx +19 -11
- package/src/client/PetSettingsCard.tsx +57 -0
- package/src/client/PetSprite.test.tsx +265 -12
- package/src/client/PetSprite.tsx +165 -33
- package/src/client/index.ts +6 -0
- package/src/client/locales.ts +14 -0
- package/src/client/phase-stream.test.ts +76 -0
- package/src/client/phase-stream.ts +39 -0
- package/src/client/renderers/PetRendererSwitch.test.tsx +66 -0
- package/src/client/renderers/PetRendererSwitch.tsx +48 -0
- package/src/client/renderers/live2d/Live2dVisualMount.tsx +98 -0
- package/src/client/renderers/live2d/runtime.test.ts +61 -0
- package/src/client/renderers/live2d/runtime.ts +119 -0
- package/src/client/renderers/live2d/vendor-entry.ts +14 -0
- package/src/client/renderers/live2d.test.ts +263 -0
- package/src/client/renderers/live2d.ts +231 -0
- package/src/client/renderers/registry.ts +58 -0
- package/src/client/settings-form.ts +8 -6
- package/src/client/settings-section.module.css +23 -0
- package/src/contracts/renderer.ts +54 -0
- package/src/contracts/status-decoration.ts +78 -0
- package/src/decoration.test.ts +178 -0
- package/src/decoration.ts +220 -0
- package/src/event-projection.ts +10 -5
- package/src/index.ts +2 -0
- package/src/manifest-v2.test.ts +251 -0
- package/src/manifest-v2.ts +414 -0
- package/src/model3.test.ts +79 -0
- package/src/model3.ts +91 -0
- package/src/registry.test.ts +438 -2
- package/src/registry.ts +470 -38
- package/src/routes.ts +328 -14
- package/src/service.ts +65 -3
- package/src/voice-pack.test.ts +216 -0
- package/src/voice-pack.ts +413 -0
package/lib/types/chatter.d.ts
CHANGED
|
@@ -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":"AAAA
|
|
1
|
+
{"version":3,"file":"chatter.d.ts","sourceRoot":"","sources":["../../src/chatter.ts"],"names":[],"mappings":"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"}
|
package/lib/types/chatter.js
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
-
.
|
|
450
|
-
.
|
|
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
|
-
|
|
455
|
-
|
|
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
|
-
|
|
737
|
-
|
|
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
|
|
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;
|
|
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;
|
|
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,
|
|
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"}
|