@linxin666/dsh-pet 0.3.5 → 0.3.6
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/contracts/voice-pack-v1.schema.json +30 -0
- package/cordis.patch.yml +1 -1
- package/lib/client.js +144 -16
- package/lib/client.js.map +1 -1
- package/lib/index.js +56 -17
- package/lib/invariant.js +1 -1
- package/lib/{state-DrMX22GL.js → state-NvDEoCln.js} +5 -2
- package/lib/types/access.d.ts +5 -4
- package/lib/types/access.d.ts.map +1 -1
- package/lib/types/access.js +2 -12
- package/lib/types/affinity.d.ts +2 -0
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +12 -0
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +7 -1
- package/lib/types/client/locales.d.ts +18 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +18 -0
- package/lib/types/client/renderers/frames2d.d.ts +12 -0
- package/lib/types/client/renderers/frames2d.d.ts.map +1 -1
- package/lib/types/client/renderers/frames2d.js +143 -18
- package/lib/types/ledger.d.ts +4 -2
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +4 -4
- package/lib/types/pair-access.d.ts +35 -0
- package/lib/types/pair-access.d.ts.map +1 -0
- package/lib/types/pair-access.js +19 -0
- package/lib/types/remarks.d.ts +1 -1
- package/lib/types/remarks.d.ts.map +1 -1
- package/lib/types/remarks.js +11 -2
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +4 -1
- package/lib/types/voice-pack.d.ts +5 -0
- package/lib/types/voice-pack.d.ts.map +1 -1
- package/lib/types/voice-pack.js +36 -2
- package/package.json +1 -1
- package/src/access.ts +7 -27
- package/src/affinity.ts +13 -0
- package/src/client/PetSprite.test.tsx +18 -0
- package/src/client/PetSprite.tsx +9 -1
- package/src/client/locales.ts +18 -0
- package/src/client/renderers/frames2d.test.ts +101 -0
- package/src/client/renderers/frames2d.ts +138 -18
- package/src/ledger.ts +6 -4
- package/src/pair-access.ts +49 -0
- package/src/remarks.test.ts +10 -0
- package/src/remarks.ts +9 -2
- package/src/service.ts +4 -1
- package/src/voice-pack.test.ts +39 -0
- package/src/voice-pack.ts +37 -2
package/lib/types/ledger.js
CHANGED
|
@@ -27,7 +27,7 @@ export class PetLedger {
|
|
|
27
27
|
constructor(persist, config = {}) {
|
|
28
28
|
this.affinityConfig = { ...defaultAffinityConfig, ...(config.affinity ?? {}) };
|
|
29
29
|
this.treatConfig = { ...defaultTreatConfig, ...(config.treats ?? {}) };
|
|
30
|
-
this.picker = new RemarkPicker(config.remarks);
|
|
30
|
+
this.picker = new RemarkPicker(config.remarks, config.voiceRemarks);
|
|
31
31
|
this.current = persist;
|
|
32
32
|
}
|
|
33
33
|
/** Affinity cooldown/rank tuning (read-only). */
|
|
@@ -79,10 +79,10 @@ export class PetLedger {
|
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* Swap the reaction pools to another pet's custom remarks (called on pet
|
|
82
|
-
* selection). Slots the pet does not declare fall back to built-ins.
|
|
82
|
+
* selection). Slots the pet does not declare fall back to voice packs or built-ins.
|
|
83
83
|
*/
|
|
84
|
-
setRemarks(remarks) {
|
|
85
|
-
this.picker = new RemarkPicker(remarks);
|
|
84
|
+
setRemarks(remarks, voiceRemarks) {
|
|
85
|
+
this.picker = new RemarkPicker(remarks, voiceRemarks);
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
88
|
* Settle the treat economy (work + time output since the last settlement).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pairing trust fence shared by plugins that expose host routes: loopback
|
|
3
|
+
* (the desktop) always passes; a live paired-device cookie is an additional
|
|
4
|
+
* allow path when remote-web-ui is loaded. The consuming plugin never
|
|
5
|
+
* depends on that plugin — without the service the fence stays
|
|
6
|
+
* loopback-only.
|
|
7
|
+
*
|
|
8
|
+
* Per-package wrappers (access.ts) call this with their own name so each
|
|
9
|
+
* plugin keeps a self-describing export; the security decision lives only
|
|
10
|
+
* here.
|
|
11
|
+
*/
|
|
12
|
+
import type { IncomingMessage } from 'node:http';
|
|
13
|
+
/** Structural pairing lookup (no package dependency on remote-web-ui). */
|
|
14
|
+
interface PairingAccess {
|
|
15
|
+
isPairedDevice(request: IncomingMessage): boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Structural host-context shape: shared sources carry no @deepseek-ai
|
|
19
|
+
* dependency (the shared package must typecheck standalone), so the fence
|
|
20
|
+
* reads only the two members it needs; cordis Context satisfies this.
|
|
21
|
+
* ctx.get is optional on the test harness; production Context always has it.
|
|
22
|
+
*/
|
|
23
|
+
interface LookupCtx {
|
|
24
|
+
get?(name: string, strict?: boolean): unknown;
|
|
25
|
+
remoteWebUiPairing?: PairingAccess;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Whether this request may enter the plugin's host routes.
|
|
29
|
+
* @param ctx - host context; may expose remoteWebUiPairing.
|
|
30
|
+
* @param request - the incoming HTTP request.
|
|
31
|
+
* @returns true for loopback, or a live paired-device cookie.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isPairedOrLoopbackAllowed(ctx: LookupCtx, request: IncomingMessage): boolean;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=pair-access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pair-access.d.ts","sourceRoot":"","sources":["../../src/pair-access.ts"],"names":[],"mappings":"AACA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAGhD,0EAA0E;AAC1E,UAAU,aAAa;IACrB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAA;CAClD;AAED;;;;;GAKG;AACH,UAAU,SAAS;IACjB,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;IAC7C,kBAAkB,CAAC,EAAE,aAAa,CAAA;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAK3F"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isLoopbackRequest } from "./loopback.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether this request may enter the plugin's host routes.
|
|
4
|
+
* @param ctx - host context; may expose remoteWebUiPairing.
|
|
5
|
+
* @param request - the incoming HTTP request.
|
|
6
|
+
* @returns true for loopback, or a live paired-device cookie.
|
|
7
|
+
*/
|
|
8
|
+
export function isPairedOrLoopbackAllowed(ctx, request) {
|
|
9
|
+
if (isLoopbackRequest(request))
|
|
10
|
+
return true;
|
|
11
|
+
const fromGet = typeof ctx.get === 'function' ? ctx.get('remoteWebUiPairing', false) : undefined;
|
|
12
|
+
const pairing = (isPairingAccess(fromGet) ? fromGet : ctx.remoteWebUiPairing);
|
|
13
|
+
return pairing?.isPairedDevice(request) === true;
|
|
14
|
+
}
|
|
15
|
+
function isPairingAccess(value) {
|
|
16
|
+
return value !== undefined
|
|
17
|
+
&& value !== null
|
|
18
|
+
&& typeof value.isPairedDevice === 'function';
|
|
19
|
+
}
|
package/lib/types/remarks.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export declare function normalizePetRemarks(raw: unknown, onWarning?: (message:
|
|
|
47
47
|
export declare class RemarkPicker {
|
|
48
48
|
private readonly counters;
|
|
49
49
|
private readonly pools;
|
|
50
|
-
constructor(overrides?: PetRemarks);
|
|
50
|
+
constructor(overrides?: PetRemarks, voiceOverrides?: PetRemarks);
|
|
51
51
|
/** The effective pool for one slot (custom override or built-in). */
|
|
52
52
|
pool(kind: RemarkKind): readonly string[];
|
|
53
53
|
/** The next line for one slot (round-robin within its pool). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remarks.d.ts","sourceRoot":"","sources":["../../src/remarks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,aAAa,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,CAAA;AAErF,4CAA4C;AAC5C,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAM7C,CAAA;AAED,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;AAE9D,yEAAyE;AACzE,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAA;AAE/E,2EAA2E;AAC3E,eAAO,MAAM,eAAe,MAAM,CAAA;AAClC,sCAAsC;AACtC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC,CA2F3E,CAAA;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,SAAS,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,GAC9C,UAAU,GAAG,SAAS,CAyBxB;AAED;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;gBAEjD,SAAS,CAAC,EAAE,UAAU;
|
|
1
|
+
{"version":3,"file":"remarks.d.ts","sourceRoot":"","sources":["../../src/remarks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,aAAa,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,CAAA;AAErF,4CAA4C;AAC5C,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAM7C,CAAA;AAED,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;AAE9D,yEAAyE;AACzE,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAA;AAE/E,2EAA2E;AAC3E,eAAO,MAAM,eAAe,MAAM,CAAA;AAClC,sCAAsC;AACtC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC,CA2F3E,CAAA;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,SAAS,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,GAC9C,UAAU,GAAG,SAAS,CAyBxB;AAED;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;gBAEjD,SAAS,CAAC,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,UAAU;IAe/D,qEAAqE;IACrE,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,MAAM,EAAE;IAIzC,gEAAgE;IAChE,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAO9B,wFAAwF;IACxF,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;CAIhD"}
|
package/lib/types/remarks.js
CHANGED
|
@@ -166,11 +166,20 @@ export function normalizePetRemarks(raw, onWarning = () => { }) {
|
|
|
166
166
|
export class RemarkPicker {
|
|
167
167
|
counters = new Map();
|
|
168
168
|
pools;
|
|
169
|
-
constructor(overrides) {
|
|
169
|
+
constructor(overrides, voiceOverrides) {
|
|
170
170
|
this.pools = {};
|
|
171
171
|
for (const kind of REMARK_KINDS) {
|
|
172
172
|
const custom = overrides?.[kind];
|
|
173
|
-
|
|
173
|
+
const voice = voiceOverrides?.[kind];
|
|
174
|
+
if (custom !== undefined && custom.length > 0) {
|
|
175
|
+
this.pools[kind] = custom;
|
|
176
|
+
}
|
|
177
|
+
else if (voice !== undefined && voice.length > 0) {
|
|
178
|
+
this.pools[kind] = voice;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.pools[kind] = BUILTIN_REMARKS[kind];
|
|
182
|
+
}
|
|
174
183
|
}
|
|
175
184
|
}
|
|
176
185
|
/** The effective pool for one slot (custom override or built-in). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"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"}
|
package/lib/types/service.js
CHANGED
|
@@ -81,10 +81,12 @@ export class PetService extends Service {
|
|
|
81
81
|
persist = { ...persist, petId: this.registry.defaultEntry().id };
|
|
82
82
|
}
|
|
83
83
|
const selected = this.registry.byId(persist.petId) ?? this.registry.defaultEntry();
|
|
84
|
+
const voiceRemarks = mergeVoicePacks(this.registry.globalVoice, selected.voice)?.remarks;
|
|
84
85
|
const ledgerConfig = {
|
|
85
86
|
affinity: config.affinity,
|
|
86
87
|
treats: config.treats,
|
|
87
88
|
remarks: selected.remarks,
|
|
89
|
+
voiceRemarks,
|
|
88
90
|
};
|
|
89
91
|
this.ledger = new PetLedger(persist, ledgerConfig);
|
|
90
92
|
this.stateConfig = { ...defaultPetStateConfig, ...(config.state ?? {}) };
|
|
@@ -164,7 +166,8 @@ export class PetService extends Service {
|
|
|
164
166
|
if (entry === undefined)
|
|
165
167
|
return { ok: false, error: 'unknown-pet' };
|
|
166
168
|
this.ledger.setPetId(entry.id);
|
|
167
|
-
this.
|
|
169
|
+
const voiceRemarks = mergeVoicePacks(this.registry.globalVoice, entry.voice)?.remarks;
|
|
170
|
+
this.ledger.setRemarks(entry.remarks, voiceRemarks);
|
|
168
171
|
this.flush();
|
|
169
172
|
this.syncSettingsFromPet();
|
|
170
173
|
return { ok: true, petId: entry.id };
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* @module @linxin666/dsh-pet/voice-pack
|
|
29
29
|
*/
|
|
30
30
|
import { type VoicePackOverrides, type WhisperCategory, type WhisperResult } from './chatter.ts';
|
|
31
|
+
import { type PetRemarks } from './remarks.ts';
|
|
31
32
|
/** Schema version this module normalizes (optional field; missing = 1). */
|
|
32
33
|
export declare const VOICE_PACK_V1: 1;
|
|
33
34
|
/** Hover-panel action buttons a pack can show or hide (canonical order). */
|
|
@@ -54,6 +55,10 @@ export interface VoicePack {
|
|
|
54
55
|
overrides: VoicePackOverrides;
|
|
55
56
|
/** Hover-panel chrome, when the pack declares any. */
|
|
56
57
|
panel?: PetPanelView;
|
|
58
|
+
/** Pat/feed interaction remark pools (issue #1226). */
|
|
59
|
+
remarks?: PetRemarks;
|
|
60
|
+
/** Affinity rank name overrides (issue #1226). */
|
|
61
|
+
ranks?: Record<string, string>;
|
|
57
62
|
}
|
|
58
63
|
/** Hard caps shared by every pool slot (mirrors the remarks discipline). */
|
|
59
64
|
export declare const VOICE_POOL_LINES_MAX = 64;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-pack.d.ts","sourceRoot":"","sources":["../../src/voice-pack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"voice-pack.d.ts","sourceRoot":"","sources":["../../src/voice-pack.ts"],"names":[],"mappings":"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"}
|
package/lib/types/voice-pack.js
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* @module @linxin666/dsh-pet/voice-pack
|
|
29
29
|
*/
|
|
30
30
|
import { STATUS_SCENES, TOOL_CATEGORIES, WHISPER_CATEGORIES, WHISPER_RESULTS, } from "./chatter.js";
|
|
31
|
+
import { normalizePetRemarks } from "./remarks.js";
|
|
31
32
|
/** Schema version this module normalizes (optional field; missing = 1). */
|
|
32
33
|
export const VOICE_PACK_V1 = 1;
|
|
33
34
|
/** Hover-panel action buttons a pack can show or hide (canonical order). */
|
|
@@ -225,7 +226,7 @@ export function normalizePanel(raw, onWarning = () => { }) {
|
|
|
225
226
|
return panel;
|
|
226
227
|
}
|
|
227
228
|
/** Voice-pack top-level fields ('$schema' mirrors the schema twin; drift-locked in tests). */
|
|
228
|
-
export const VOICE_PACK_KEYS = new Set(['$schema', 'voicePackVersion', 'status', 'tools', 'toolRemaining', 'whispers', 'panel']);
|
|
229
|
+
export const VOICE_PACK_KEYS = new Set(['$schema', 'voicePackVersion', 'status', 'tools', 'toolRemaining', 'whispers', 'panel', 'remarks', 'ranks']);
|
|
229
230
|
/** Allowed whisper-section fields (drift-locked in tests). */
|
|
230
231
|
export const WHISPER_KEYS = new Set(['categories', 'results']);
|
|
231
232
|
/**
|
|
@@ -318,14 +319,37 @@ export function normalizeVoicePack(raw, onWarning = () => { }) {
|
|
|
318
319
|
}
|
|
319
320
|
}
|
|
320
321
|
const panel = raw.panel === undefined ? undefined : normalizePanel(raw.panel, onWarning);
|
|
322
|
+
const remarks = raw.remarks === undefined ? undefined : normalizePetRemarks(raw.remarks, onWarning);
|
|
323
|
+
const ranksRaw = raw.ranks;
|
|
324
|
+
let ranks;
|
|
325
|
+
if (ranksRaw !== undefined) {
|
|
326
|
+
if (!isRecord(ranksRaw)) {
|
|
327
|
+
onWarning('ranks must be an object');
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
const out = {};
|
|
331
|
+
for (const [key, value] of Object.entries(ranksRaw)) {
|
|
332
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
333
|
+
out[key] = value.trim().slice(0, VOICE_STAT_MAX);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
onWarning('invalid rank name for ' + key);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (Object.keys(out).length > 0)
|
|
340
|
+
ranks = out;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
321
343
|
if (overrides.status === undefined && overrides.tools === undefined
|
|
322
344
|
&& overrides.toolRemaining === undefined && overrides.whispers === undefined
|
|
323
|
-
&& panel === undefined) {
|
|
345
|
+
&& panel === undefined && remarks === undefined && ranks === undefined) {
|
|
324
346
|
return undefined;
|
|
325
347
|
}
|
|
326
348
|
return {
|
|
327
349
|
overrides,
|
|
328
350
|
...(panel === undefined ? {} : { panel }),
|
|
351
|
+
...(remarks === undefined ? {} : { remarks }),
|
|
352
|
+
...(ranks === undefined ? {} : { ranks }),
|
|
329
353
|
};
|
|
330
354
|
}
|
|
331
355
|
/**
|
|
@@ -338,6 +362,8 @@ export function mergeVoicePacks(...layers) {
|
|
|
338
362
|
const overrides = {};
|
|
339
363
|
const labels = {};
|
|
340
364
|
const stats = {};
|
|
365
|
+
let remarks;
|
|
366
|
+
let ranks;
|
|
341
367
|
let actions;
|
|
342
368
|
let panelSeen = false;
|
|
343
369
|
let any = false;
|
|
@@ -365,6 +391,12 @@ export function mergeVoicePacks(...layers) {
|
|
|
365
391
|
if (layer.panel.actions !== undefined)
|
|
366
392
|
actions = layer.panel.actions;
|
|
367
393
|
}
|
|
394
|
+
if (layer.remarks !== undefined) {
|
|
395
|
+
remarks = { ...(remarks ?? {}), ...layer.remarks };
|
|
396
|
+
}
|
|
397
|
+
if (layer.ranks !== undefined) {
|
|
398
|
+
ranks = { ...(ranks ?? {}), ...layer.ranks };
|
|
399
|
+
}
|
|
368
400
|
}
|
|
369
401
|
if (!any)
|
|
370
402
|
return undefined;
|
|
@@ -377,5 +409,7 @@ export function mergeVoicePacks(...layers) {
|
|
|
377
409
|
return {
|
|
378
410
|
overrides,
|
|
379
411
|
...(panelSeen && !panelEmpty ? { panel } : {}),
|
|
412
|
+
...(remarks !== undefined ? { remarks } : {}),
|
|
413
|
+
...(ranks !== undefined ? { ranks } : {}),
|
|
380
414
|
};
|
|
381
415
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linxin666/dsh-pet",
|
|
3
3
|
"description": "Multi-pet companion plugin for the dsh web GUI: a registry-driven floating pet that reacts to model activity, with per-pet naming, petting/feeding interactions and an affinity score",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.6",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0"
|
package/src/access.ts
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pet trust fence: loopback (the desktop) always passes; a live
|
|
3
|
-
* cookie is an additional allow path when remote-web-ui is
|
|
4
|
-
* never depends on that plugin — without the service the
|
|
5
|
-
* loopback-only
|
|
2
|
+
* Pet trust fence: loopback (the desktop) always passes; a live
|
|
3
|
+
* paired-device cookie is an additional allow path when remote-web-ui is
|
|
4
|
+
* loaded. The pet never depends on that plugin — without the service the
|
|
5
|
+
* fence stays loopback-only. The decision logic lives in the generated
|
|
6
|
+
* pair-access.ts copy (shared by git-graph / pet / skill-explorer).
|
|
6
7
|
*/
|
|
7
8
|
import type { IncomingMessage } from 'node:http'
|
|
8
9
|
import type { Context } from '@deepseek-ai/cordis'
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
/** Structural pairing lookup (no package dependency on remote-web-ui). */
|
|
12
|
-
interface PairingAccess {
|
|
13
|
-
isPairedDevice(request: IncomingMessage): boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** ctx.get is optional on the test harness; production Context always has it. */
|
|
17
|
-
type LookupCtx = Context & {
|
|
18
|
-
get?(name: string, strict?: boolean): unknown
|
|
19
|
-
remoteWebUiPairing?: PairingAccess
|
|
20
|
-
}
|
|
10
|
+
import { isPairedOrLoopbackAllowed } from './pair-access.ts'
|
|
21
11
|
|
|
22
12
|
/**
|
|
23
13
|
* Whether this request may enter any /api/pet or /pet asset route.
|
|
@@ -26,15 +16,5 @@ type LookupCtx = Context & {
|
|
|
26
16
|
* @returns true for loopback, or a live paired-device cookie.
|
|
27
17
|
*/
|
|
28
18
|
export function isPetAllowed(ctx: Context, request: IncomingMessage): boolean {
|
|
29
|
-
|
|
30
|
-
const bag = ctx as LookupCtx
|
|
31
|
-
const fromGet = typeof bag.get === 'function' ? bag.get('remoteWebUiPairing', false) : undefined
|
|
32
|
-
const pairing = (isPairingAccess(fromGet) ? fromGet : bag.remoteWebUiPairing)
|
|
33
|
-
return pairing?.isPairedDevice(request) === true
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function isPairingAccess(value: unknown): value is PairingAccess {
|
|
37
|
-
return value !== undefined
|
|
38
|
-
&& value !== null
|
|
39
|
-
&& typeof (value as PairingAccess).isPairedDevice === 'function'
|
|
19
|
+
return isPairedOrLoopbackAllowed(ctx, request)
|
|
40
20
|
}
|
package/src/affinity.ts
CHANGED
|
@@ -56,6 +56,19 @@ export const AFFINITY_RANKS = [
|
|
|
56
56
|
{ min: 100_000, name: '鲸生共渡', emoji: '*********' },
|
|
57
57
|
] as const
|
|
58
58
|
|
|
59
|
+
/** English translations for the 9 built-in affinity rank names (#1226). */
|
|
60
|
+
export const AFFINITY_RANKS_EN: Readonly<Record<string, string>> = {
|
|
61
|
+
'幼鲸': 'Baby Whale',
|
|
62
|
+
'伙伴': 'Companion',
|
|
63
|
+
'挚友': 'Close Friend',
|
|
64
|
+
'深海羁绊': 'Deep Sea Bond',
|
|
65
|
+
'心有灵犀': 'Kindred Spirit',
|
|
66
|
+
'传说羁绊': 'Legendary Bond',
|
|
67
|
+
'神话羁绊': 'Mythic Bond',
|
|
68
|
+
'永恒之契': 'Eternal Covenant',
|
|
69
|
+
'鲸生共渡': 'Lifelong Companion',
|
|
70
|
+
}
|
|
71
|
+
|
|
59
72
|
/** Interaction tuning (all in points / ms). */
|
|
60
73
|
export interface AffinityConfig {
|
|
61
74
|
/** Points per completed turn. */
|
|
@@ -176,6 +176,24 @@ describe('PetSprite hide control (#1126)', () => {
|
|
|
176
176
|
})
|
|
177
177
|
})
|
|
178
178
|
|
|
179
|
+
describe('PetSprite affinity rank localization (#1226)', () => {
|
|
180
|
+
it('localizes the rank name in the hover panel when document language is en', () => {
|
|
181
|
+
document.documentElement.lang = 'en'
|
|
182
|
+
try {
|
|
183
|
+
renderPet({
|
|
184
|
+
snapshot: {
|
|
185
|
+
...snapshot,
|
|
186
|
+
affinity: { ...snapshot.affinity, rank: '幼鲸' },
|
|
187
|
+
},
|
|
188
|
+
})
|
|
189
|
+
fireEvent.pointerOver(screen.getByRole('button', { name: '鲸鱼娘' }))
|
|
190
|
+
expect(screen.getByText('Affinity Baby Whale')).toBeTruthy()
|
|
191
|
+
} finally {
|
|
192
|
+
document.documentElement.lang = 'zh'
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
|
|
179
197
|
describe('PetSprite rename input', () => {
|
|
180
198
|
it('submits the draft on Enter outside composition', () => {
|
|
181
199
|
const { onRename } = renderPet()
|
package/src/client/PetSprite.tsx
CHANGED
|
@@ -685,7 +685,15 @@ export function PetSprite(props: PetSpriteProps): ReactPortal {
|
|
|
685
685
|
<>
|
|
686
686
|
<div className={styles.rankRow}>
|
|
687
687
|
<span className={styles.nameCell}>{displayName}</span>
|
|
688
|
-
<span className={styles.statRank}>
|
|
688
|
+
<span className={styles.statRank}>
|
|
689
|
+
{(() => {
|
|
690
|
+
const rawRank = snapshot?.affinity.rank ?? '?'
|
|
691
|
+
const rankKey = `pet.rank.name.${rawRank}`
|
|
692
|
+
const localized = props.t(rankKey as any)
|
|
693
|
+
const rankName = localized !== rankKey ? localized : rawRank
|
|
694
|
+
return panelStat('rank', 'pet.rank', { rank: rankName })
|
|
695
|
+
})()}
|
|
696
|
+
</span>
|
|
689
697
|
</div>
|
|
690
698
|
<div className={styles.rankRow}>
|
|
691
699
|
<span className={styles.statTreats}>{panelStat('treats', 'pet.treats', { n: snapshot?.treats.stocked ?? 0 })}</span>
|
package/src/client/locales.ts
CHANGED
|
@@ -15,6 +15,15 @@ export const zh = {
|
|
|
15
15
|
'pet.namePlaceholder': '输入新名字',
|
|
16
16
|
'pet.summon': '召唤{name}',
|
|
17
17
|
'pet.rank': '亲密度 {rank}',
|
|
18
|
+
'pet.rank.name.幼鲸': '幼鲸',
|
|
19
|
+
'pet.rank.name.伙伴': '伙伴',
|
|
20
|
+
'pet.rank.name.挚友': '挚友',
|
|
21
|
+
'pet.rank.name.深海羁绊': '深海羁绊',
|
|
22
|
+
'pet.rank.name.心有灵犀': '心有灵犀',
|
|
23
|
+
'pet.rank.name.传说羁绊': '传说羁绊',
|
|
24
|
+
'pet.rank.name.神话羁绊': '神话羁绊',
|
|
25
|
+
'pet.rank.name.永恒之契': '永恒之契',
|
|
26
|
+
'pet.rank.name.鲸生共渡': '鲸生共渡',
|
|
18
27
|
'pet.points': '{points} 点',
|
|
19
28
|
'pet.treats': '小鱼干 ×{n}',
|
|
20
29
|
'pet.state.loading': '宠物正在赶来…',
|
|
@@ -88,6 +97,15 @@ export const en = {
|
|
|
88
97
|
'pet.namePlaceholder': 'Enter a new name',
|
|
89
98
|
'pet.summon': 'Summon {name}',
|
|
90
99
|
'pet.rank': 'Affinity {rank}',
|
|
100
|
+
'pet.rank.name.幼鲸': 'Baby Whale',
|
|
101
|
+
'pet.rank.name.伙伴': 'Companion',
|
|
102
|
+
'pet.rank.name.挚友': 'Close Friend',
|
|
103
|
+
'pet.rank.name.深海羁绊': 'Deep Sea Bond',
|
|
104
|
+
'pet.rank.name.心有灵犀': 'Kindred Spirit',
|
|
105
|
+
'pet.rank.name.传说羁绊': 'Legendary Bond',
|
|
106
|
+
'pet.rank.name.神话羁绊': 'Mythic Bond',
|
|
107
|
+
'pet.rank.name.永恒之契': 'Eternal Covenant',
|
|
108
|
+
'pet.rank.name.鲸生共渡': 'Lifelong Companion',
|
|
91
109
|
'pet.points': '{points} pts',
|
|
92
110
|
'pet.treats': 'Treats ×{n}',
|
|
93
111
|
'pet.state.loading': 'The pet is on its way…',
|
|
@@ -135,3 +135,104 @@ describe('frames2dRenderer', () => {
|
|
|
135
135
|
expect(container.querySelector('img')).toBeNull()
|
|
136
136
|
})
|
|
137
137
|
})
|
|
138
|
+
|
|
139
|
+
describe('frames2dRenderer canvas bitmap path', () => {
|
|
140
|
+
// The canvas branch needs createImageBitmap + fetch + a real 2D context;
|
|
141
|
+
// jsdom has none of them, so each test installs fakes and restores after.
|
|
142
|
+
const flush = async (): Promise<void> => {
|
|
143
|
+
await Promise.resolve()
|
|
144
|
+
await Promise.resolve()
|
|
145
|
+
await Promise.resolve()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let draws = 0
|
|
149
|
+
const bitmaps: { width: number; height: number; close: ReturnType<typeof vi.fn> }[] = []
|
|
150
|
+
|
|
151
|
+
beforeEach(() => {
|
|
152
|
+
vi.useFakeTimers()
|
|
153
|
+
document.body.innerHTML = ''
|
|
154
|
+
draws = 0
|
|
155
|
+
bitmaps.length = 0
|
|
156
|
+
vi.stubGlobal('fetch', vi.fn(async () => ({ ok: true, blob: async () => ({}) })))
|
|
157
|
+
vi.stubGlobal('createImageBitmap', vi.fn(async () => {
|
|
158
|
+
const bmp = { width: 32, height: 32, close: vi.fn() }
|
|
159
|
+
bitmaps.push(bmp)
|
|
160
|
+
return bmp
|
|
161
|
+
}))
|
|
162
|
+
;(HTMLCanvasElement.prototype as unknown as { getContext: unknown }).getContext = () => ({
|
|
163
|
+
clearRect: () => {},
|
|
164
|
+
drawImage: () => {
|
|
165
|
+
draws += 1
|
|
166
|
+
},
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
afterEach(() => {
|
|
171
|
+
vi.unstubAllGlobals()
|
|
172
|
+
Reflect.deleteProperty(HTMLCanvasElement.prototype as unknown as Record<string, unknown>, 'getContext')
|
|
173
|
+
vi.useRealTimers()
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
function canvasSetup() {
|
|
177
|
+
const container = document.createElement('div')
|
|
178
|
+
document.body.appendChild(container)
|
|
179
|
+
const ctx: PetRendererContext = {
|
|
180
|
+
petId: 'miku',
|
|
181
|
+
assetBase: '/pet/miku',
|
|
182
|
+
container,
|
|
183
|
+
phase: createPhaseStream('idle'),
|
|
184
|
+
interact: () => {},
|
|
185
|
+
onCleanup: () => {},
|
|
186
|
+
}
|
|
187
|
+
return { ctx, container }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
it('mounts a canvas instead of an img and paints advanced frames via drawImage', async () => {
|
|
191
|
+
const { ctx, container } = canvasSetup()
|
|
192
|
+
const handle = frames2dRenderer.mount(ctx, frames2dRenderer.validateConfig(CONFIG)) as Frames2dRendererHandle
|
|
193
|
+
expect(container.querySelector('canvas')).not.toBeNull()
|
|
194
|
+
expect(container.querySelector('img')).toBeNull()
|
|
195
|
+
await flush()
|
|
196
|
+
// Warm pass decoded every configured frame exactly once; the first frame
|
|
197
|
+
// of the idle track painted during mount.
|
|
198
|
+
expect(bitmaps.length).toBe(6)
|
|
199
|
+
const paintsAtMount = draws
|
|
200
|
+
expect(paintsAtMount).toBeGreaterThanOrEqual(1)
|
|
201
|
+
vi.advanceTimersByTime(100)
|
|
202
|
+
await flush()
|
|
203
|
+
expect(draws).toBeGreaterThan(paintsAtMount)
|
|
204
|
+
handle.dispose()
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
it('sizes the backing store from decoded dimensions and releases bitmaps on dispose', async () => {
|
|
208
|
+
const { ctx, container } = canvasSetup()
|
|
209
|
+
const handle = frames2dRenderer.mount(ctx, frames2dRenderer.validateConfig(CONFIG)) as Frames2dRendererHandle
|
|
210
|
+
await flush()
|
|
211
|
+
const canvas = container.querySelector('canvas')!
|
|
212
|
+
expect(canvas.width).toBe(32)
|
|
213
|
+
expect(canvas.height).toBe(32)
|
|
214
|
+
handle.dispose()
|
|
215
|
+
await flush()
|
|
216
|
+
for (const bmp of bitmaps) expect(bmp.close).toHaveBeenCalled()
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('keeps painting through a phase switch without touching the DOM tree', async () => {
|
|
220
|
+
const { container } = canvasSetup()
|
|
221
|
+
const stream = createPhaseStream('idle')
|
|
222
|
+
const ctx: PetRendererContext = {
|
|
223
|
+
petId: 'miku', assetBase: '/pet/miku', container, phase: stream, interact: () => {}, onCleanup: () => {},
|
|
224
|
+
}
|
|
225
|
+
const handle = frames2dRenderer.mount(ctx, frames2dRenderer.validateConfig(CONFIG)) as Frames2dRendererHandle
|
|
226
|
+
await flush()
|
|
227
|
+
const nodesBefore = container.querySelectorAll('*').length
|
|
228
|
+
stream.push('thinking' as ActivityPhase)
|
|
229
|
+
expect(handle.currentTrack()).toBe('work')
|
|
230
|
+
await flush()
|
|
231
|
+
vi.advanceTimersByTime(100)
|
|
232
|
+
await flush()
|
|
233
|
+
// Steady-state playback is DOM-mutation-free: no element added or removed.
|
|
234
|
+
expect(container.querySelectorAll('*').length).toBe(nodesBefore)
|
|
235
|
+
expect(draws).toBeGreaterThanOrEqual(3)
|
|
236
|
+
handle.dispose()
|
|
237
|
+
})
|
|
238
|
+
})
|