@linxin666/dsh-pet 0.1.20 → 0.2.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.
- package/README.i18n.yaml +2 -2
- package/README.md +17 -10
- package/README.zh.md +17 -10
- package/assets/whale/pet.json +9 -0
- package/lib/client.js +158 -26
- package/lib/client.js.map +1 -1
- package/lib/index.js +853 -41
- package/lib/invariant.js +1 -1
- package/lib/{state-Diiq8vjk.js → state-Ch3f4luZ.js} +51 -23
- package/lib/types/affinity.d.ts +4 -0
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +32 -6
- package/lib/types/chatter.d.ts +111 -0
- package/lib/types/chatter.d.ts.map +1 -0
- package/lib/types/chatter.js +666 -0
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +88 -14
- package/lib/types/client/PluginSettingsCard.d.ts +6 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +5 -3
- package/lib/types/client/sequences.d.ts +10 -0
- package/lib/types/client/sequences.d.ts.map +1 -0
- package/lib/types/client/sequences.js +20 -0
- package/lib/types/event-projection.d.ts +14 -1
- package/lib/types/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +38 -17
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +15 -7
- package/lib/types/persist.d.ts.map +1 -1
- package/lib/types/persist.js +3 -1
- package/lib/types/registry.d.ts +7 -1
- package/lib/types/registry.d.ts.map +1 -1
- package/lib/types/registry.js +36 -0
- package/lib/types/remarks.d.ts +2 -0
- package/lib/types/remarks.d.ts.map +1 -1
- package/lib/types/remarks.js +5 -0
- package/lib/types/service.d.ts +6 -0
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +15 -2
- package/lib/types/state.d.ts +7 -4
- package/lib/types/state.d.ts.map +1 -1
- package/lib/types/state.js +20 -20
- package/package.json +9 -9
- package/src/affinity.test.ts +4 -2
- package/src/affinity.ts +37 -6
- package/src/chatter.test.ts +154 -0
- package/src/chatter.ts +697 -0
- package/src/client/PetSprite.test.tsx +190 -1
- package/src/client/PetSprite.tsx +112 -25
- package/src/client/PluginSettingsCard.tsx +10 -0
- package/src/client/pet-css.test.ts +42 -0
- package/src/client/pet.module.css +154 -26
- package/src/client/sequences.test.ts +33 -0
- package/src/client/sequences.ts +33 -0
- package/src/event-projection.ts +49 -16
- package/src/ledger.test.ts +42 -1
- package/src/ledger.ts +15 -7
- package/src/persist.test.ts +18 -1
- package/src/persist.ts +3 -1
- package/src/registry.test.ts +50 -3
- package/src/registry.ts +47 -3
- package/src/remarks.ts +6 -0
- package/src/service.ts +27 -2
- package/src/state.test.ts +13 -0
- package/src/state.ts +24 -18
|
@@ -9,10 +9,12 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
9
9
|
* pet id), so one component renders every registry entry.
|
|
10
10
|
* @module @linxin666/dsh-pet/client/PetSprite
|
|
11
11
|
*/
|
|
12
|
-
import { useEffect, useRef, useState } from 'react';
|
|
12
|
+
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
import clsx from 'clsx';
|
|
15
15
|
import { framePosition, rowOfTrack, trimTrack } from './spritesheet.js';
|
|
16
|
+
import { sequenceFrameAt } from './sequences.js';
|
|
17
|
+
import { animationForPhase } from '../state.js';
|
|
16
18
|
import styles from './pet.module.css';
|
|
17
19
|
/** Clamp a drag offset inside the viewport with a margin. */
|
|
18
20
|
function clampOffset(value, max) {
|
|
@@ -28,10 +30,22 @@ export function PetSprite(props) {
|
|
|
28
30
|
const { snapshot, definition, display, feedback } = props;
|
|
29
31
|
const spriteRef = useRef(null);
|
|
30
32
|
const floatRef = useRef(null);
|
|
33
|
+
const panelRef = useRef(null);
|
|
34
|
+
// Whichever bubble surface is currently rendered (feedback, the session
|
|
35
|
+
// stack, or the legacy status bubble) — only one exists at a time.
|
|
36
|
+
const bubbleRef = useRef(null);
|
|
31
37
|
const [imageReady, setImageReady] = useState(false);
|
|
32
38
|
const [hovered, setHovered] = useState(false);
|
|
33
39
|
const [renaming, setRenaming] = useState(false);
|
|
40
|
+
const [panelAbove, setPanelAbove] = useState(false);
|
|
41
|
+
// Extra margin-bottom for the above-panel so it stacks clear of the
|
|
42
|
+
// bubbles instead of overlapping them (both anchor at the sprite's top).
|
|
43
|
+
const [panelLift, setPanelLift] = useState(0);
|
|
34
44
|
const [nameDraft, setNameDraft] = useState('');
|
|
45
|
+
// Explicit IME composition tracking: some input methods (WeChat IME on
|
|
46
|
+
// Windows) report keydowns with isComposing === false mid-composition, so
|
|
47
|
+
// the native flag alone is not a safe submit/cancel guard (#303).
|
|
48
|
+
const composingRef = useRef(false);
|
|
35
49
|
const [dragPos, setDragPos] = useState(null);
|
|
36
50
|
const dragRef = useRef(null);
|
|
37
51
|
const hideTimerRef = useRef(null);
|
|
@@ -44,6 +58,7 @@ export function PetSprite(props) {
|
|
|
44
58
|
const columns = definition.columns;
|
|
45
59
|
const rows = definition.rows;
|
|
46
60
|
const tracks = definition.tracks;
|
|
61
|
+
const sequences = definition.sequences;
|
|
47
62
|
// Load the atlas once; the definition carries the authoritative per-row
|
|
48
63
|
// frame counts and per-track durations, so nothing else is fetched.
|
|
49
64
|
useEffect(() => {
|
|
@@ -66,14 +81,17 @@ export function PetSprite(props) {
|
|
|
66
81
|
// its track's first frame instead of animating (presentation-only; the
|
|
67
82
|
// animation state machine is untouched).
|
|
68
83
|
const spriteScale = display.size / cell.height;
|
|
84
|
+
const phase = snapshot?.phase ?? 'idle';
|
|
69
85
|
const animation = snapshot?.animation ?? 'idle';
|
|
70
86
|
const scaleRef = useRef(spriteScale);
|
|
71
87
|
scaleRef.current = spriteScale;
|
|
72
88
|
useEffect(() => {
|
|
73
89
|
const reduceMotion = typeof window !== 'undefined'
|
|
74
90
|
&& window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches === true;
|
|
75
|
-
const
|
|
76
|
-
const
|
|
91
|
+
const sequence = animation === animationForPhase(phase) ? sequences?.[phase] : undefined;
|
|
92
|
+
const leadAnimation = sequence?.[0] ?? animation;
|
|
93
|
+
const row = rowOfTrack(leadAnimation);
|
|
94
|
+
const track = trimTrack(tracks[leadAnimation], rows[row] ?? tracks[leadAnimation].frames.length);
|
|
77
95
|
// Paint one static sprite frame up front either way, so the pet is never
|
|
78
96
|
// blank while the loop heat-up runs.
|
|
79
97
|
const leadCol = track.frames[0];
|
|
@@ -85,9 +103,23 @@ export function PetSprite(props) {
|
|
|
85
103
|
return;
|
|
86
104
|
let raf = 0;
|
|
87
105
|
let last = performance.now();
|
|
106
|
+
let sequenceElapsed = 0;
|
|
88
107
|
const tick = (ts) => {
|
|
89
108
|
const delta = ts - last;
|
|
90
109
|
last = ts;
|
|
110
|
+
if (sequence !== undefined) {
|
|
111
|
+
sequenceElapsed += delta;
|
|
112
|
+
const current = sequenceFrameAt(sequence, tracks, sequenceElapsed);
|
|
113
|
+
const currentRow = rowOfTrack(current.animation);
|
|
114
|
+
const currentTrack = trimTrack(tracks[current.animation], rows[currentRow] ?? tracks[current.animation].frames.length);
|
|
115
|
+
const col = currentTrack.frames[current.frameIndex];
|
|
116
|
+
const pos = framePosition(cell, columns, currentRow, col, scaleRef.current);
|
|
117
|
+
if (spriteRef.current !== null) {
|
|
118
|
+
spriteRef.current.style.backgroundPosition = pos.x + 'px ' + pos.y + 'px';
|
|
119
|
+
}
|
|
120
|
+
raf = requestAnimationFrame(tick);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
91
123
|
// row/track come from the effect scope: they were computed once above
|
|
92
124
|
// and this effect re-runs when animation/tracks/rows change, so the
|
|
93
125
|
// per-frame recompute (trimTrack slices fresh arrays) is pure waste.
|
|
@@ -121,7 +153,7 @@ export function PetSprite(props) {
|
|
|
121
153
|
};
|
|
122
154
|
raf = requestAnimationFrame(tick);
|
|
123
155
|
return () => cancelAnimationFrame(raf);
|
|
124
|
-
}, [animation, cell, columns, rows, tracks]);
|
|
156
|
+
}, [animation, phase, cell, columns, rows, tracks, sequences]);
|
|
125
157
|
// Auto-clear the feedback bubble after its CSS animation. The callback
|
|
126
158
|
// rides a ref so re-renders never reset the timer: the 2s poll rebuilds
|
|
127
159
|
// `props` every tick, and depending on it would starve the timeout.
|
|
@@ -175,35 +207,70 @@ export function PetSprite(props) {
|
|
|
175
207
|
const spriteHeight = Math.round(cell.height * spriteScale);
|
|
176
208
|
// Concurrent sessions each render their own bubble (stacked above the
|
|
177
209
|
// sprite); the legacy single 'bubble' is the fallback when the host serves
|
|
178
|
-
// no per-session list. The hover panel
|
|
179
|
-
// bubbles stay visible and clickable while hovering — no region swap.
|
|
210
|
+
// no per-session list. The hover panel normally sits below the sprite, so
|
|
211
|
+
// the bubbles stay visible and clickable while hovering — no region swap.
|
|
180
212
|
const sessionBubbles = snapshot?.sessions ?? [];
|
|
181
213
|
const statusBubble = feedback === null && sessionBubbles.length === 0
|
|
182
214
|
? snapshot?.bubble
|
|
183
215
|
: undefined;
|
|
216
|
+
// The display session's inner whisper (碎碎念) — short inner-voice copy
|
|
217
|
+
// woken by the model's output. Interaction feedback takes over the whole
|
|
218
|
+
// bubble area while it plays, so whispers yield to it like status copy.
|
|
219
|
+
const whisper = feedback === null ? snapshot?.whisper : undefined;
|
|
220
|
+
const bubblePresent = feedback !== null || sessionBubbles.length > 0 || statusBubble !== undefined || whisper !== undefined;
|
|
184
221
|
const displayName = snapshot?.name ?? definition.displayName;
|
|
222
|
+
useLayoutEffect(() => {
|
|
223
|
+
if (!hovered) {
|
|
224
|
+
setPanelAbove(false);
|
|
225
|
+
setPanelLift(0);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const updatePanelPlacement = () => {
|
|
229
|
+
const sprite = spriteRef.current;
|
|
230
|
+
const panel = panelRef.current;
|
|
231
|
+
if (sprite === null || panel === null)
|
|
232
|
+
return;
|
|
233
|
+
const availableBelow = window.innerHeight - sprite.getBoundingClientRect().bottom;
|
|
234
|
+
const above = availableBelow < panel.getBoundingClientRect().height + 8;
|
|
235
|
+
setPanelAbove(above);
|
|
236
|
+
// The fallback above-placement shares the sprite's top edge with the
|
|
237
|
+
// bubble(s); lift the panel by the bubble area's height so the two
|
|
238
|
+
// never overlap (8px base gap + 6px clearance above the top bubble).
|
|
239
|
+
const bubbleHeight = above ? bubbleRef.current?.getBoundingClientRect().height ?? 0 : 0;
|
|
240
|
+
setPanelLift(bubbleHeight > 0 ? Math.ceil(bubbleHeight) + 14 : 0);
|
|
241
|
+
};
|
|
242
|
+
updatePanelPlacement();
|
|
243
|
+
window.addEventListener('resize', updatePanelPlacement);
|
|
244
|
+
return () => window.removeEventListener('resize', updatePanelPlacement);
|
|
245
|
+
}, [hovered, renaming, pos.right, pos.bottom, display.size, bubblePresent, sessionBubbles.length, feedback]);
|
|
185
246
|
const float = (_jsxs("div", { ref: floatRef, className: styles.float, style: { right: pos.right, bottom: pos.bottom, zIndex: 2147483000 }, onPointerEnter: () => {
|
|
186
247
|
clearHideTimer();
|
|
187
248
|
setHovered(true);
|
|
188
249
|
}, onPointerLeave: (e) => {
|
|
189
|
-
// The panel renders OUTSIDE the container's box (absolute,
|
|
250
|
+
// The panel renders OUTSIDE the container's box (absolute, below
|
|
190
251
|
// the sprite), so moving onto it fires pointerleave on the container.
|
|
191
252
|
// Treat a target still inside the container's DOM (the overflowed
|
|
192
253
|
// panel) as "still hovering"; otherwise give the pointer a short
|
|
193
|
-
// grace period to reach the panel across the gap
|
|
254
|
+
// grace period to reach the panel across the gap below the sprite.
|
|
194
255
|
// The bridge ('.panel::after') keeps the pointer inside the hit
|
|
195
256
|
// area, and the grace period covers a slow mouse crossing the
|
|
196
257
|
// remaining sliver.
|
|
197
258
|
const next = e.relatedTarget;
|
|
198
259
|
if (next instanceof Node && floatRef.current?.contains(next))
|
|
199
260
|
return;
|
|
261
|
+
// Never auto-hide while the rename box is open: moving the pointer
|
|
262
|
+
// onto an IME candidate window (an OS-level window outside the
|
|
263
|
+
// webview) fires pointerleave, and unmounting the input mid-IME-
|
|
264
|
+
// composition crashes some input methods / the renderer (#303).
|
|
265
|
+
if (renaming)
|
|
266
|
+
return;
|
|
200
267
|
clearHideTimer();
|
|
201
268
|
hideTimerRef.current = window.setTimeout(() => setHovered(false), 300);
|
|
202
269
|
}, children: [_jsx("div", { ref: spriteRef, className: styles.sprite, style: {
|
|
203
270
|
width: spriteWidth,
|
|
204
271
|
height: spriteHeight,
|
|
205
272
|
backgroundImage: imageReady ? 'url(' + definition.atlasUrl + ')' : undefined,
|
|
206
|
-
backgroundSize: (cell.width * columns * spriteScale) + 'px ' + (cell.height * rows.length * spriteScale) + 'px',
|
|
273
|
+
backgroundSize: (cell.width * columns * spriteScale) + 'px ' + (cell.height * (definition.atlasRows ?? rows.length) * spriteScale) + 'px',
|
|
207
274
|
backgroundRepeat: 'no-repeat',
|
|
208
275
|
backgroundPosition: '0 0',
|
|
209
276
|
cursor: dragRef.current === null ? 'grab' : 'grabbing',
|
|
@@ -213,17 +280,21 @@ export function PetSprite(props) {
|
|
|
213
280
|
if (draggedRef.current)
|
|
214
281
|
return;
|
|
215
282
|
props.onPet();
|
|
216
|
-
}, role: "button", "aria-label": definition.displayName }), feedback !== null && (_jsx("div", { className: clsx(styles.bubble, feedback.kind === 'feed' ? styles.bubbleFeed : styles.bubblePet), children: feedback.text }, feedback.at)), feedback === null && sessionBubbles.length > 0 && (
|
|
283
|
+
}, role: "button", "aria-label": definition.displayName }), feedback !== null && (_jsx("div", { ref: bubbleRef, className: clsx(styles.bubble, feedback.kind === 'feed' ? styles.bubbleFeed : styles.bubblePet), children: feedback.text }, feedback.at)), feedback === null && (sessionBubbles.length > 0 || statusBubble !== undefined || whisper !== undefined) && (_jsxs("div", { ref: bubbleRef, className: styles.bubbleStack, children: [sessionBubbles.map(session => (_jsx("button", { type: "button", className: clsx(styles.bubble, styles.bubbleStatus, styles.bubbleClickable), title: props.t('pet.openSessionHint'), onClick: () => { props.onOpenSession(session.sessionId); }, children: session.bubble }, session.sessionId))), sessionBubbles.length === 0 && statusBubble !== undefined && (_jsx("div", { className: clsx(styles.bubble, styles.bubbleStatus), role: "status", "aria-live": "polite", children: statusBubble })), whisper !== undefined && (_jsx("div", { className: styles.bubbleWhisper, children: whisper }, whisper))] })), hovered && dragRef.current === null && (_jsx("div", { ref: panelRef, className: clsx(styles.panel, panelAbove && styles.panelAbove), "data-placement": panelAbove ? 'above' : 'below', style: panelAbove && panelLift > 0
|
|
284
|
+
? { marginBottom: panelLift }
|
|
285
|
+
: undefined, onPointerEnter: () => {
|
|
217
286
|
// Reaching the panel (or its bridge) must cancel any hide timer
|
|
218
287
|
// the container's pointerleave may have armed while the pointer
|
|
219
288
|
// crossed the sliver between the sprite and the panel.
|
|
220
289
|
clearHideTimer();
|
|
221
|
-
}, children: renaming ? (_jsxs("div", { className: styles.renameRow, children: [_jsx("input", { className: styles.nameInput, value: nameDraft, maxLength: 20, placeholder: props.t('pet.namePlaceholder'), autoFocus: true, onChange: (e) => setNameDraft(e.target.value), onKeyDown: (e) => {
|
|
290
|
+
}, children: renaming ? (_jsxs("div", { className: styles.renameRow, children: [_jsx("input", { className: styles.nameInput, value: nameDraft, maxLength: 20, placeholder: props.t('pet.namePlaceholder'), autoFocus: true, onChange: (e) => setNameDraft(e.target.value), onCompositionStart: () => { composingRef.current = true; }, onCompositionEnd: () => { composingRef.current = false; }, onKeyDown: (e) => {
|
|
222
291
|
// While an IME composition is active (e.g. selecting a
|
|
223
292
|
// Chinese candidate), Enter/Escape keydowns belong to the
|
|
224
293
|
// input method: ignore them so candidate selection can
|
|
225
|
-
// neither submit the draft nor close the rename box.
|
|
226
|
-
|
|
294
|
+
// neither submit the draft nor close the rename box. The
|
|
295
|
+
// explicit ref and the 'Process' key cover IMEs that mark
|
|
296
|
+
// composition keydowns with isComposing === false (#303).
|
|
297
|
+
if (composingRef.current || e.nativeEvent.isComposing || e.key === 'Process')
|
|
227
298
|
return;
|
|
228
299
|
if (e.key === 'Enter') {
|
|
229
300
|
const trimmed = nameDraft.trim();
|
|
@@ -241,7 +312,10 @@ export function PetSprite(props) {
|
|
|
241
312
|
props.onRename(trimmed);
|
|
242
313
|
setRenaming(false);
|
|
243
314
|
}
|
|
244
|
-
}, children: props.t('pet.confirm') })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.rankRow, children: [_jsx("span", { className: styles.nameCell, children: displayName }), _jsx("span", { children: props.t('pet.rank', { rank: snapshot?.affinity.rank ?? '?' }) })] }), _jsxs("div", { className: styles.rankRow, children: [_jsx("span", { children: props.t('pet.treats', { n: snapshot?.treats.stocked ?? 0 }) }), _jsx("span", { children: props.t('pet.points', { points: snapshot?.affinity.points ?? 0 }) })] }), _jsxs("div", { className: styles.actions, children: [_jsx("button", { type: "button", className: styles.action, onClick: props.onFeed, children: props.t('pet.feed') }), _jsx("button", { type: "button", className: styles.action, onClick: () => {
|
|
315
|
+
}, children: props.t('pet.confirm') })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.rankRow, children: [_jsx("span", { className: styles.nameCell, children: displayName }), _jsx("span", { className: styles.statRank, children: props.t('pet.rank', { rank: snapshot?.affinity.rank ?? '?' }) })] }), _jsxs("div", { className: styles.rankRow, children: [_jsx("span", { className: styles.statTreats, children: props.t('pet.treats', { n: snapshot?.treats.stocked ?? 0 }) }), _jsx("span", { className: styles.statPoints, children: props.t('pet.points', { points: snapshot?.affinity.points ?? 0 }) })] }), _jsxs("div", { className: styles.actions, children: [_jsx("button", { type: "button", className: styles.action, onClick: props.onFeed, children: props.t('pet.feed') }), _jsx("button", { type: "button", className: styles.action, onClick: () => {
|
|
316
|
+
// Cancel any pending hide so the rename box cannot
|
|
317
|
+
// unmount right as the user starts typing (#303).
|
|
318
|
+
clearHideTimer();
|
|
245
319
|
setNameDraft(displayName);
|
|
246
320
|
setRenaming(true);
|
|
247
321
|
}, children: props.t('pet.rename') }), _jsx("button", { type: "button", className: styles.action, onClick: props.onHide, children: props.t('pet.hide') })] })] })) }))] }));
|
|
@@ -39,6 +39,12 @@ export interface PluginSettingsCardProps<TKey extends string = string> {
|
|
|
39
39
|
* already provides the selection.
|
|
40
40
|
*/
|
|
41
41
|
alwaysOpen?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Hide the save/discard footer: cards whose body applies its own changes
|
|
44
|
+
* immediately (an embedded external settings section) have no staged
|
|
45
|
+
* edits, so the footer would sit there permanently disabled.
|
|
46
|
+
*/
|
|
47
|
+
hideFooter?: boolean;
|
|
42
48
|
/** The plugin's controls. */
|
|
43
49
|
children: ReactNode;
|
|
44
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,oGAAoG;AACpG,eAAO,MAAM,cAAc,YACzB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,CACT,CAAA;AAEV,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzD,oEAAoE;AACpE,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,GAAG,WAAW,CAAA;AAE9E,wDAAwD;AACxD,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,0CAA0C;IAC1C,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAA;IACnF,uCAAuC;IACvC,QAAQ,EAAE,IAAI,CAAA;IACd,4EAA4E;IAC5E,cAAc,EAAE,IAAI,CAAA;IACpB,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAA;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6BAA6B;IAC7B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,uBAAuB,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -52,9 +52,11 @@ export function PluginSettingsCard(props) {
|
|
|
52
52
|
: null] }));
|
|
53
53
|
}
|
|
54
54
|
return (_jsxs("li", { className: cardClass, children: [header, expanded
|
|
55
|
-
? (_jsxs("div", { className: css.body, children: [!state.writable ? _jsx("p", { className: css.readOnly, role: "status", children: props.t('settings.readOnly') }) : null, props.children,
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
? (_jsxs("div", { className: css.body, children: [!state.writable ? _jsx("p", { className: css.readOnly, role: "status", children: props.t('settings.readOnly') }) : null, props.children, props.hideFooter === true
|
|
56
|
+
? null
|
|
57
|
+
: (_jsxs("div", { className: css.footer, children: [state.failed
|
|
58
|
+
? (_jsxs("p", { className: css.failed, role: "status", children: [props.t('settings.saveFailed'), state.failedReason ? ' - ' + state.failedReason : ''] }))
|
|
59
|
+
: null, _jsx("button", { type: "button", className: css.discard, disabled: !state.dirty || state.saving, onClick: props.onDiscard, children: props.t('settings.discard') }), _jsx("button", { type: "button", className: css.save, disabled: blocked, onClick: props.onSave, children: props.t(!state.saving ? 'settings.save' : 'settings.saving') })] }))] }))
|
|
58
60
|
: null] }));
|
|
59
61
|
}
|
|
60
62
|
/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Pure timing helpers for manifest-defined scene animation sequences. */
|
|
2
|
+
import type { PetTrackDef } from '../registry.ts';
|
|
3
|
+
import type { PetAnimation } from '../state.ts';
|
|
4
|
+
export interface SequenceFrame {
|
|
5
|
+
animation: PetAnimation;
|
|
6
|
+
frameIndex: number;
|
|
7
|
+
}
|
|
8
|
+
/** Resolve the active track and frame after elapsed milliseconds of a looping sequence. */
|
|
9
|
+
export declare function sequenceFrameAt(sequence: readonly PetAnimation[], tracks: Record<PetAnimation, PetTrackDef>, elapsedMs: number): SequenceFrame;
|
|
10
|
+
//# sourceMappingURL=sequences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequences.d.ts","sourceRoot":"","sources":["../../../src/client/sequences.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,YAAY,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,EACzC,SAAS,EAAE,MAAM,GAChB,aAAa,CAiBf"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Pure timing helpers for manifest-defined scene animation sequences. */
|
|
2
|
+
/** Resolve the active track and frame after elapsed milliseconds of a looping sequence. */
|
|
3
|
+
export function sequenceFrameAt(sequence, tracks, elapsedMs) {
|
|
4
|
+
const itemDurations = sequence.map(animation => tracks[animation].durations.reduce((sum, value) => sum + value, 0));
|
|
5
|
+
const sequenceDuration = itemDurations.reduce((sum, value) => sum + value, 0);
|
|
6
|
+
let offset = Math.max(0, elapsedMs) % sequenceDuration;
|
|
7
|
+
let itemIndex = 0;
|
|
8
|
+
while (itemIndex < sequence.length - 1 && offset >= itemDurations[itemIndex]) {
|
|
9
|
+
offset -= itemDurations[itemIndex];
|
|
10
|
+
itemIndex += 1;
|
|
11
|
+
}
|
|
12
|
+
const animation = sequence[itemIndex];
|
|
13
|
+
const track = tracks[animation];
|
|
14
|
+
let frameIndex = 0;
|
|
15
|
+
while (frameIndex < track.frames.length - 1 && offset >= track.durations[frameIndex]) {
|
|
16
|
+
offset -= track.durations[frameIndex];
|
|
17
|
+
frameIndex += 1;
|
|
18
|
+
}
|
|
19
|
+
return { animation, frameIndex };
|
|
20
|
+
}
|
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
* vocabulary onto the pet's visual phases and carries an optional completed-
|
|
4
4
|
* turn reward for the ledger. Holds no state of its own; callers keep a
|
|
5
5
|
* {@link ProjectionRuntime} per session and feed events in arrival order.
|
|
6
|
+
*
|
|
7
|
+
* Status copy comes from the chatter voice (big rotating pools, per-tool
|
|
8
|
+
* families, real-argument hints), and streamed model output feeds the murmur
|
|
9
|
+
* engine so the pet can whisper its inner voice (碎碎念). The wall clock is
|
|
10
|
+
* injected by the caller, keeping every projection reproducible.
|
|
6
11
|
* @module @linxin666/dsh-pet/event-projection
|
|
7
12
|
*/
|
|
8
13
|
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
9
14
|
import type { PetStateInput } from './state.ts';
|
|
15
|
+
import { StatusVoice, WhisperEngine } from './chatter.ts';
|
|
10
16
|
/** Runtime shape of the optional legacy activity event. */
|
|
11
17
|
export interface ActivityStatusEventLike {
|
|
12
18
|
phase?: string;
|
|
@@ -18,11 +24,17 @@ export interface ProjectionRuntime {
|
|
|
18
24
|
activeTools: Set<string>;
|
|
19
25
|
officialEventsSeen: boolean;
|
|
20
26
|
stepHadFailure: boolean;
|
|
27
|
+
/** Round-robin status copy voice (scene-stable, cadence-rotated). */
|
|
28
|
+
voice: StatusVoice;
|
|
29
|
+
/** Inner-whisper engine fed by the model's own streamed output. */
|
|
30
|
+
whispers: WhisperEngine;
|
|
21
31
|
}
|
|
22
32
|
/** One official event projection, optionally carrying a completed turn reward. */
|
|
23
33
|
export interface PetActivityTransition {
|
|
24
34
|
input: PetStateInput;
|
|
25
35
|
completedTurn?: number;
|
|
36
|
+
/** A fresh inner whisper woken by this event's model output, when any. */
|
|
37
|
+
whisper?: string;
|
|
26
38
|
}
|
|
27
39
|
/** Fresh projection runtime for a newly seen session. */
|
|
28
40
|
export declare function emptyProjectionRuntime(): ProjectionRuntime;
|
|
@@ -31,6 +43,7 @@ export declare function isActivityPhase(phase: string): phase is PetStateInput['
|
|
|
31
43
|
/**
|
|
32
44
|
* Project the durable DSH session vocabulary into the pet's visual phases.
|
|
33
45
|
* Unknown and log-only events do not disturb the last meaningful activity.
|
|
46
|
+
* @param nowMs - injected wall clock for copy rotation and whisper pacing.
|
|
34
47
|
*/
|
|
35
|
-
export declare function projectOfficialEvent(event: SessionEvent, runtime: ProjectionRuntime): PetActivityTransition | undefined;
|
|
48
|
+
export declare function projectOfficialEvent(event: SessionEvent, runtime: ProjectionRuntime, nowMs?: number): PetActivityTransition | undefined;
|
|
36
49
|
//# sourceMappingURL=event-projection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-projection.d.ts","sourceRoot":"","sources":["../../src/event-projection.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"event-projection.d.ts","sourceRoot":"","sources":["../../src/event-projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,cAAc,CAAA;AAEtE,2DAA2D;AAC3D,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,cAAc,EAAE,OAAO,CAAA;IACvB,qEAAqE;IACrE,KAAK,EAAE,WAAW,CAAA;IAClB,mEAAmE;IACnE,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED,kFAAkF;AAClF,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,aAAa,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,yDAAyD;AACzD,wBAAgB,sBAAsB,IAAI,iBAAiB,CAQ1D;AAQD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAAC,OAAO,CAAC,CAE9E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,iBAAiB,EAC1B,KAAK,GAAE,MAAmB,GACzB,qBAAqB,GAAG,SAAS,CAwFnC"}
|
|
@@ -3,16 +3,28 @@
|
|
|
3
3
|
* vocabulary onto the pet's visual phases and carries an optional completed-
|
|
4
4
|
* turn reward for the ledger. Holds no state of its own; callers keep a
|
|
5
5
|
* {@link ProjectionRuntime} per session and feed events in arrival order.
|
|
6
|
+
*
|
|
7
|
+
* Status copy comes from the chatter voice (big rotating pools, per-tool
|
|
8
|
+
* families, real-argument hints), and streamed model output feeds the murmur
|
|
9
|
+
* engine so the pet can whisper its inner voice (碎碎念). The wall clock is
|
|
10
|
+
* injected by the caller, keeping every projection reproducible.
|
|
6
11
|
* @module @linxin666/dsh-pet/event-projection
|
|
7
12
|
*/
|
|
13
|
+
import { StatusVoice, toolArgHint, WhisperEngine } from './chatter.js';
|
|
8
14
|
/** Fresh projection runtime for a newly seen session. */
|
|
9
15
|
export function emptyProjectionRuntime() {
|
|
10
|
-
return {
|
|
16
|
+
return {
|
|
17
|
+
activeTools: new Set(),
|
|
18
|
+
officialEventsSeen: false,
|
|
19
|
+
stepHadFailure: false,
|
|
20
|
+
voice: new StatusVoice(),
|
|
21
|
+
whispers: new WhisperEngine(),
|
|
22
|
+
};
|
|
11
23
|
}
|
|
12
24
|
/** Keep tool names readable inside the compact status bubble. */
|
|
13
25
|
function displayToolName(name) {
|
|
14
26
|
const compact = name.replace(/\s+/g, ' ').trim() || '工具';
|
|
15
|
-
return compact.length <= 24 ? compact :
|
|
27
|
+
return compact.length <= 24 ? compact : compact.slice(0, 21) + '...';
|
|
16
28
|
}
|
|
17
29
|
/** Whether a legacy phase is part of the pet's supported vocabulary. */
|
|
18
30
|
export function isActivityPhase(phase) {
|
|
@@ -21,35 +33,44 @@ export function isActivityPhase(phase) {
|
|
|
21
33
|
/**
|
|
22
34
|
* Project the durable DSH session vocabulary into the pet's visual phases.
|
|
23
35
|
* Unknown and log-only events do not disturb the last meaningful activity.
|
|
36
|
+
* @param nowMs - injected wall clock for copy rotation and whisper pacing.
|
|
24
37
|
*/
|
|
25
|
-
export function projectOfficialEvent(event, runtime) {
|
|
38
|
+
export function projectOfficialEvent(event, runtime, nowMs = Date.now()) {
|
|
26
39
|
switch (event.type) {
|
|
27
40
|
case 'turn/start':
|
|
28
41
|
runtime.activeTools.clear();
|
|
29
42
|
runtime.stepHadFailure = false;
|
|
30
|
-
return { input: { phase: 'waiting', line: '
|
|
43
|
+
return { input: { phase: 'waiting', line: runtime.voice.scene('prepare', nowMs) } };
|
|
31
44
|
case 'step/start':
|
|
32
45
|
runtime.activeTools.clear();
|
|
33
46
|
runtime.stepHadFailure = false;
|
|
34
|
-
return { input: { phase: 'waiting', line: '
|
|
47
|
+
return { input: { phase: 'waiting', line: runtime.voice.scene('waiting', nowMs) } };
|
|
35
48
|
case 'assistant/chunk': {
|
|
36
49
|
const { chunk } = event.data;
|
|
37
50
|
if (chunk.type === 'reasoning-delta' && chunk.text.length > 0) {
|
|
38
|
-
|
|
51
|
+
const whisper = runtime.whispers.feed(chunk.text, nowMs);
|
|
52
|
+
return {
|
|
53
|
+
input: { phase: 'thinking', line: runtime.voice.scene('thinking', nowMs) },
|
|
54
|
+
...(whisper === undefined ? {} : { whisper }),
|
|
55
|
+
};
|
|
39
56
|
}
|
|
40
57
|
if (chunk.type === 'text-delta' && chunk.text.length > 0) {
|
|
41
|
-
|
|
58
|
+
const whisper = runtime.whispers.feed(chunk.text, nowMs);
|
|
59
|
+
return {
|
|
60
|
+
input: { phase: 'review', line: runtime.voice.scene('review', nowMs) },
|
|
61
|
+
...(whisper === undefined ? {} : { whisper }),
|
|
62
|
+
};
|
|
42
63
|
}
|
|
43
64
|
return undefined;
|
|
44
65
|
}
|
|
45
66
|
case 'assistant/message':
|
|
46
|
-
return { input: { phase: 'review', line: '
|
|
67
|
+
return { input: { phase: 'review', line: runtime.voice.scene('review', nowMs) } };
|
|
47
68
|
case 'tool/call':
|
|
48
69
|
runtime.activeTools.add(String(event.data.callId));
|
|
49
70
|
return {
|
|
50
71
|
input: {
|
|
51
72
|
phase: 'tool',
|
|
52
|
-
line:
|
|
73
|
+
line: runtime.voice.tool(event.data.name, displayToolName(event.data.name), toolArgHint(event.data.name, event.data.arguments), nowMs),
|
|
53
74
|
},
|
|
54
75
|
};
|
|
55
76
|
case 'tool/result': {
|
|
@@ -60,30 +81,30 @@ export function projectOfficialEvent(event, runtime) {
|
|
|
60
81
|
return {
|
|
61
82
|
input: {
|
|
62
83
|
phase: 'tool',
|
|
63
|
-
line:
|
|
84
|
+
line: runtime.voice.toolRemaining(runtime.activeTools.size, nowMs),
|
|
64
85
|
},
|
|
65
86
|
};
|
|
66
87
|
}
|
|
67
88
|
return runtime.stepHadFailure
|
|
68
|
-
? { input: { phase: 'failed', line: '
|
|
69
|
-
: { input: { phase: 'thinking', line: '
|
|
89
|
+
? { input: { phase: 'failed', line: runtime.voice.scene('toolFailed', nowMs) } }
|
|
90
|
+
: { input: { phase: 'thinking', line: runtime.voice.scene('toolResult', nowMs) } };
|
|
70
91
|
}
|
|
71
92
|
case 'turn/end': {
|
|
72
93
|
runtime.activeTools.clear();
|
|
73
94
|
switch (event.data.reason.kind) {
|
|
74
95
|
case 'completed':
|
|
75
96
|
return {
|
|
76
|
-
input: { phase: 'done', line: '
|
|
97
|
+
input: { phase: 'done', line: runtime.voice.scene('done', nowMs) },
|
|
77
98
|
completedTurn: event.data.turn,
|
|
78
99
|
};
|
|
79
100
|
case 'error':
|
|
80
|
-
return { input: { phase: 'failed', line: '
|
|
101
|
+
return { input: { phase: 'failed', line: runtime.voice.scene('failed', nowMs) } };
|
|
81
102
|
case 'max-tokens':
|
|
82
|
-
return { input: { phase: 'failed', line: '
|
|
103
|
+
return { input: { phase: 'failed', line: runtime.voice.scene('maxTokens', nowMs) } };
|
|
83
104
|
case 'interrupted':
|
|
84
|
-
return { input: { phase: 'failed', line: '
|
|
105
|
+
return { input: { phase: 'failed', line: runtime.voice.scene('interrupted', nowMs) } };
|
|
85
106
|
case 'blocked':
|
|
86
|
-
return { input: { phase: 'waiting', line: '
|
|
107
|
+
return { input: { phase: 'waiting', line: runtime.voice.scene('blocked', nowMs) } };
|
|
87
108
|
case 'aborted':
|
|
88
109
|
// A stopped session settles to idle without a bubble: the pet
|
|
89
110
|
// visibly calms down and the session drops out of the bubble stack.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAA;AACtB,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEhE,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,mFAAmF;IACnF,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB;AAED,wEAAwE;AACxE,MAAM,WAAW,uBAAuB;IACtC,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAA;IACb,6DAA6D;IAC7D,QAAQ,EAAE,eAAe,CAAA;CAC1B;AAED;;;;GAIG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAY;IAC3B,oFAAoF;IACpF,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,sBAAsB,CAAI;IAClC,OAAO,CAAC,KAAK,CAAQ;IAErB,YAAY,OAAO,EAAE,UAAU,EAAE,MAAM,GAAE,YAAiB,EAKzD;IAED,iDAAiD;IACjD,IAAI,QAAQ,IAAI,cAAc,CAE7B;IAED,qEAAqE;IACrE,IAAI,QAAQ,IAAI,UAAU,CAEzB;IAED,qCAAqC;IACrC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,+DAA+D;IAC/D,SAAS,IAAI,OAAO,CAInB;IAED;;;OAGG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAErC;IAED,mEAAmE;IACnE,UAAU,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAG1C;IAED,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI5B;IAED,0EAA0E;IAC1E,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAG5C;IAED;;;OAGG;IACH,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAErC;IAED;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWnC;IAED;;;;OAIG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAOlE;IAED,8EAA8E;IAC9E,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAOvC;IAED,OAAO,CAAC,eAAe;IASvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAA;AACtB,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEhE,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,mFAAmF;IACnF,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB;AAED,wEAAwE;AACxE,MAAM,WAAW,uBAAuB;IACtC,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAA;IACb,6DAA6D;IAC7D,QAAQ,EAAE,eAAe,CAAA;CAC1B;AAED;;;;GAIG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAY;IAC3B,oFAAoF;IACpF,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,sBAAsB,CAAI;IAClC,OAAO,CAAC,KAAK,CAAQ;IAErB,YAAY,OAAO,EAAE,UAAU,EAAE,MAAM,GAAE,YAAiB,EAKzD;IAED,iDAAiD;IACjD,IAAI,QAAQ,IAAI,cAAc,CAE7B;IAED,qEAAqE;IACrE,IAAI,QAAQ,IAAI,UAAU,CAEzB;IAED,qCAAqC;IACrC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,+DAA+D;IAC/D,SAAS,IAAI,OAAO,CAInB;IAED;;;OAGG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAErC;IAED,mEAAmE;IACnE,UAAU,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAG1C;IAED,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI5B;IAED,0EAA0E;IAC1E,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAG5C;IAED;;;OAGG;IACH,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAErC;IAED;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWnC;IAED;;;;OAIG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAOlE;IAED,8EAA8E;IAC9E,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAOvC;IAED,OAAO,CAAC,eAAe;IASvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,CAsCrE;IAED,kDAAkD;IAClD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAE3C;CACF"}
|
package/lib/types/ledger.js
CHANGED
|
@@ -135,12 +135,19 @@ export class PetLedger {
|
|
|
135
135
|
interact(kind, nowMs) {
|
|
136
136
|
if (kind === 'feed')
|
|
137
137
|
this.settleTreats(nowMs);
|
|
138
|
-
const
|
|
138
|
+
const before = this.current.affinity;
|
|
139
|
+
const outcome = applyInteraction(before, kind, nowMs, this.affinityConfig);
|
|
139
140
|
// Reactions come from the picker pools (custom per-pet slots override
|
|
140
141
|
// the built-in library per slot); outcome.reaction stays the fallback
|
|
141
142
|
// copy for direct applyInteraction callers.
|
|
142
143
|
if (kind === 'feed' && !outcome.accepted) {
|
|
143
|
-
|
|
144
|
+
this.current = { ...this.current, affinity: outcome.affinity };
|
|
145
|
+
this.dirty = true;
|
|
146
|
+
return {
|
|
147
|
+
reaction: this.picker.pickAt('feedCooldown', before.feedRejects),
|
|
148
|
+
delta: 0,
|
|
149
|
+
affinity: this.affinityView(nowMs),
|
|
150
|
+
};
|
|
144
151
|
}
|
|
145
152
|
if (kind === 'feed') {
|
|
146
153
|
const consume = consumeTreat(this.current.treats);
|
|
@@ -154,12 +161,13 @@ export class PetLedger {
|
|
|
154
161
|
this.current = { ...this.current, treats: consume.ledger };
|
|
155
162
|
this.dirty = true;
|
|
156
163
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
this.current = { ...this.current, affinity: outcome.affinity };
|
|
165
|
+
this.dirty = true;
|
|
166
|
+
const count = kind === 'pet'
|
|
167
|
+
? outcome.accepted ? before.pets : before.petRejects
|
|
168
|
+
: before.feeds;
|
|
161
169
|
return {
|
|
162
|
-
reaction: this.picker.
|
|
170
|
+
reaction: this.picker.pickAt(outcome.accepted ? kind : 'petCooldown', count),
|
|
163
171
|
delta: outcome.delta,
|
|
164
172
|
affinity: this.affinityView(nowMs),
|
|
165
173
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/persist.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAA+B,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAEpF,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;CACf;AAED,eAAO,MAAM,oBAAoB,EAAE,gBAKlC,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAEvC,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,QAAQ,EAAE,aAAa,CAAA;IACvB,gCAAgC;IAChC,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED,qEAAqE;AACrE,eAAO,MAAM,cAAc,eAAe,CAAA;AAE1C,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,uBAAQ,CAAA;AAErC,wBAAwB;AACxB,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC,wBAAgB,YAAY,IAAI,UAAU,CAQzC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AA4BD,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAqB,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/persist.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAA+B,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAEpF,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;CACf;AAED,eAAO,MAAM,oBAAoB,EAAE,gBAKlC,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAEvC,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,QAAQ,EAAE,aAAa,CAAA;IACvB,gCAAgC;IAChC,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED,qEAAqE;AACrE,eAAO,MAAM,cAAc,eAAe,CAAA;AAE1C,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,uBAAQ,CAAA;AAErC,wBAAwB;AACxB,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC,wBAAgB,YAAY,IAAI,UAAU,CAQzC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AA4BD,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAqB,GAAG,UAAU,CAmDrE;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,GAAE,MAAqB,GAAG,IAAI,CAMjF"}
|
package/lib/types/persist.js
CHANGED
|
@@ -13,7 +13,7 @@ export const defaultDisplayConfig = {
|
|
|
13
13
|
visible: true,
|
|
14
14
|
size: 160,
|
|
15
15
|
right: 24,
|
|
16
|
-
bottom:
|
|
16
|
+
bottom: 120,
|
|
17
17
|
};
|
|
18
18
|
/** Display value bounds (shared by load-time validation and setConfig). */
|
|
19
19
|
export const DISPLAY_SIZE_MIN = 32;
|
|
@@ -78,6 +78,8 @@ export function loadPetPersist(dir = petHomeDir()) {
|
|
|
78
78
|
lastFeedAt: clamp(finiteNum(rawAffinity.lastFeedAt, 0), Number.MAX_SAFE_INTEGER),
|
|
79
79
|
pets: clamp(finiteNum(rawAffinity.pets, 0), Number.MAX_SAFE_INTEGER),
|
|
80
80
|
feeds: clamp(finiteNum(rawAffinity.feeds, 0), Number.MAX_SAFE_INTEGER),
|
|
81
|
+
petRejects: clamp(finiteNum(rawAffinity.petRejects, 0), Number.MAX_SAFE_INTEGER),
|
|
82
|
+
feedRejects: clamp(finiteNum(rawAffinity.feedRejects, 0), Number.MAX_SAFE_INTEGER),
|
|
81
83
|
turns: clamp(finiteNum(rawAffinity.turns, 0), Number.MAX_SAFE_INTEGER),
|
|
82
84
|
};
|
|
83
85
|
const rawTreats = (parsed.treats ?? {});
|
package/lib/types/registry.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* whale-girl manifest overrides its own durations.
|
|
17
17
|
* @module @linxin666/dsh-pet/registry
|
|
18
18
|
*/
|
|
19
|
-
import type { PetAnimation } from './state.ts';
|
|
19
|
+
import type { ActivityPhase, PetAnimation } from './state.ts';
|
|
20
20
|
import { type PetRemarks, type PetRemarksManifest } from './remarks.ts';
|
|
21
21
|
/** Fixed row order of the 9-state animation contract. */
|
|
22
22
|
export declare const PET_ROW_ORDER: readonly PetAnimation[];
|
|
@@ -81,6 +81,8 @@ export interface PetManifest {
|
|
|
81
81
|
frames?: number[];
|
|
82
82
|
/** Optional per-track rhythm overrides; omitted tracks use the defaults. */
|
|
83
83
|
tracks?: Partial<Record<PetAnimation, PetTrackOverride>>;
|
|
84
|
+
/** Optional per-scene track sequences; every declared sequence has at least 5 items. */
|
|
85
|
+
sequences?: Partial<Record<ActivityPhase, PetAnimation[]>>;
|
|
84
86
|
/**
|
|
85
87
|
* Optional witty-remark overrides the pet speaks on interactions
|
|
86
88
|
* (community contributions use this to give their pet its own voice).
|
|
@@ -109,8 +111,12 @@ export interface PetDefinition {
|
|
|
109
111
|
columns: number;
|
|
110
112
|
/** Per-row frame counts (length 9, row order above). */
|
|
111
113
|
rows: number[];
|
|
114
|
+
/** Total atlas rows (9 for v1, 11 for v2 look-row atlases). */
|
|
115
|
+
atlasRows: number;
|
|
112
116
|
/** Fully resolved animation tracks (frames + durations + loop/fallback). */
|
|
113
117
|
tracks: Record<PetAnimation, PetTrackDef>;
|
|
118
|
+
/** Validated per-scene track sequences; omitted scenes keep single-track playback. */
|
|
119
|
+
sequences?: Partial<Record<ActivityPhase, PetAnimation[]>>;
|
|
114
120
|
/** Browser URL of the atlas (served by the host asset route). */
|
|
115
121
|
atlasUrl: string;
|
|
116
122
|
/** Browser URL of the manifest (served by the host asset route). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"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"}
|