@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.
Files changed (50) hide show
  1. package/contracts/voice-pack-v1.schema.json +30 -0
  2. package/cordis.patch.yml +1 -1
  3. package/lib/client.js +144 -16
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +56 -17
  6. package/lib/invariant.js +1 -1
  7. package/lib/{state-DrMX22GL.js → state-NvDEoCln.js} +5 -2
  8. package/lib/types/access.d.ts +5 -4
  9. package/lib/types/access.d.ts.map +1 -1
  10. package/lib/types/access.js +2 -12
  11. package/lib/types/affinity.d.ts +2 -0
  12. package/lib/types/affinity.d.ts.map +1 -1
  13. package/lib/types/affinity.js +12 -0
  14. package/lib/types/client/PetSprite.d.ts.map +1 -1
  15. package/lib/types/client/PetSprite.js +7 -1
  16. package/lib/types/client/locales.d.ts +18 -0
  17. package/lib/types/client/locales.d.ts.map +1 -1
  18. package/lib/types/client/locales.js +18 -0
  19. package/lib/types/client/renderers/frames2d.d.ts +12 -0
  20. package/lib/types/client/renderers/frames2d.d.ts.map +1 -1
  21. package/lib/types/client/renderers/frames2d.js +143 -18
  22. package/lib/types/ledger.d.ts +4 -2
  23. package/lib/types/ledger.d.ts.map +1 -1
  24. package/lib/types/ledger.js +4 -4
  25. package/lib/types/pair-access.d.ts +35 -0
  26. package/lib/types/pair-access.d.ts.map +1 -0
  27. package/lib/types/pair-access.js +19 -0
  28. package/lib/types/remarks.d.ts +1 -1
  29. package/lib/types/remarks.d.ts.map +1 -1
  30. package/lib/types/remarks.js +11 -2
  31. package/lib/types/service.d.ts.map +1 -1
  32. package/lib/types/service.js +4 -1
  33. package/lib/types/voice-pack.d.ts +5 -0
  34. package/lib/types/voice-pack.d.ts.map +1 -1
  35. package/lib/types/voice-pack.js +36 -2
  36. package/package.json +1 -1
  37. package/src/access.ts +7 -27
  38. package/src/affinity.ts +13 -0
  39. package/src/client/PetSprite.test.tsx +18 -0
  40. package/src/client/PetSprite.tsx +9 -1
  41. package/src/client/locales.ts +18 -0
  42. package/src/client/renderers/frames2d.test.ts +101 -0
  43. package/src/client/renderers/frames2d.ts +138 -18
  44. package/src/ledger.ts +6 -4
  45. package/src/pair-access.ts +49 -0
  46. package/src/remarks.test.ts +10 -0
  47. package/src/remarks.ts +9 -2
  48. package/src/service.ts +4 -1
  49. package/src/voice-pack.test.ts +39 -0
  50. package/src/voice-pack.ts +37 -2
@@ -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
+ }
@@ -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;IAQlC,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"}
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"}
@@ -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
- this.pools[kind] = custom !== undefined && custom.length > 0 ? custom : BUILTIN_REMARKS[kind];
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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"}
@@ -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.ledger.setRemarks(entry.remarks);
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":"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"}
1
+ {"version":3,"file":"voice-pack.d.ts","sourceRoot":"","sources":["../../src/voice-pack.ts"],"names":[],"mappings":"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"}
@@ -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.5",
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 paired-device
3
- * cookie is an additional allow path when remote-web-ui is loaded. The pet
4
- * never depends on that plugin — without the service the fence stays
5
- * loopback-only (same pattern as skill-explorer / aionui-panel).
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 { isLoopbackRequest } from './loopback.ts'
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
- if (isLoopbackRequest(request)) return true
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()
@@ -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}>{panelStat('rank', 'pet.rank', { rank: snapshot?.affinity.rank ?? '?' })}</span>
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>
@@ -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
+ })