@linxin666/dsh-pet 0.2.1 → 0.2.3

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 (95) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +78 -5
  3. package/README.zh.md +78 -5
  4. package/assets/whale/pet.json +170 -21
  5. package/assets/whale-refined/pet.json +22 -0
  6. package/assets/whale-refined/spritesheet.webp +0 -0
  7. package/lib/client.js +442 -25
  8. package/lib/client.js.map +1 -1
  9. package/lib/index.js +752 -36
  10. package/lib/live2d-vendor.js +995 -0
  11. package/lib/live2d-vendor.js.map +1 -0
  12. package/lib/types/client/PetDockEntry.d.ts.map +1 -1
  13. package/lib/types/client/PetDockEntry.js +2 -1
  14. package/lib/types/client/PetSettingsCard.d.ts +10 -0
  15. package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
  16. package/lib/types/client/PetSettingsCard.js +22 -1
  17. package/lib/types/client/PetSprite.d.ts +7 -1
  18. package/lib/types/client/PetSprite.d.ts.map +1 -1
  19. package/lib/types/client/PetSprite.js +20 -11
  20. package/lib/types/client/index.d.ts.map +1 -1
  21. package/lib/types/client/index.js +5 -0
  22. package/lib/types/client/locales.d.ts +10 -0
  23. package/lib/types/client/locales.d.ts.map +1 -1
  24. package/lib/types/client/locales.js +10 -0
  25. package/lib/types/client/phase-stream.d.ts +22 -0
  26. package/lib/types/client/phase-stream.d.ts.map +1 -0
  27. package/lib/types/client/phase-stream.js +28 -0
  28. package/lib/types/client/renderers/PetRendererSwitch.d.ts +25 -0
  29. package/lib/types/client/renderers/PetRendererSwitch.d.ts.map +1 -0
  30. package/lib/types/client/renderers/PetRendererSwitch.js +24 -0
  31. package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts +22 -0
  32. package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts.map +1 -0
  33. package/lib/types/client/renderers/live2d/Live2dVisualMount.js +75 -0
  34. package/lib/types/client/renderers/live2d/runtime.d.ts +89 -0
  35. package/lib/types/client/renderers/live2d/runtime.d.ts.map +1 -0
  36. package/lib/types/client/renderers/live2d/runtime.js +63 -0
  37. package/lib/types/client/renderers/live2d/vendor-entry.d.ts +15 -0
  38. package/lib/types/client/renderers/live2d/vendor-entry.d.ts.map +1 -0
  39. package/lib/types/client/renderers/live2d/vendor-entry.js +14 -0
  40. package/lib/types/client/renderers/live2d.d.ts +52 -0
  41. package/lib/types/client/renderers/live2d.d.ts.map +1 -0
  42. package/lib/types/client/renderers/live2d.js +180 -0
  43. package/lib/types/client/renderers/registry.d.ts +32 -0
  44. package/lib/types/client/renderers/registry.d.ts.map +1 -0
  45. package/lib/types/client/renderers/registry.js +49 -0
  46. package/lib/types/client/spritesheet.d.ts +1 -3
  47. package/lib/types/client/spritesheet.d.ts.map +1 -1
  48. package/lib/types/client/spritesheet.js +1 -5
  49. package/lib/types/contracts/renderer.d.ts +50 -0
  50. package/lib/types/contracts/renderer.d.ts.map +1 -0
  51. package/lib/types/contracts/renderer.js +15 -0
  52. package/lib/types/manifest-v2.d.ts +129 -0
  53. package/lib/types/manifest-v2.d.ts.map +1 -0
  54. package/lib/types/manifest-v2.js +387 -0
  55. package/lib/types/model3.d.ts +26 -0
  56. package/lib/types/model3.d.ts.map +1 -0
  57. package/lib/types/model3.js +96 -0
  58. package/lib/types/registry.d.ts +57 -5
  59. package/lib/types/registry.d.ts.map +1 -1
  60. package/lib/types/registry.js +208 -37
  61. package/lib/types/routes.d.ts +39 -2
  62. package/lib/types/routes.d.ts.map +1 -1
  63. package/lib/types/routes.js +183 -12
  64. package/lib/types/service.d.ts +5 -1
  65. package/lib/types/service.d.ts.map +1 -1
  66. package/lib/types/service.js +4 -0
  67. package/package.json +3 -2
  68. package/src/client/PetDockEntry.tsx +19 -11
  69. package/src/client/PetSettingsCard.tsx +39 -0
  70. package/src/client/PetSprite.test.tsx +11 -0
  71. package/src/client/PetSprite.tsx +27 -12
  72. package/src/client/index.ts +6 -0
  73. package/src/client/locales.ts +10 -0
  74. package/src/client/phase-stream.test.ts +76 -0
  75. package/src/client/phase-stream.ts +39 -0
  76. package/src/client/renderers/PetRendererSwitch.test.tsx +66 -0
  77. package/src/client/renderers/PetRendererSwitch.tsx +48 -0
  78. package/src/client/renderers/live2d/Live2dVisualMount.tsx +98 -0
  79. package/src/client/renderers/live2d/runtime.test.ts +61 -0
  80. package/src/client/renderers/live2d/runtime.ts +119 -0
  81. package/src/client/renderers/live2d/vendor-entry.ts +14 -0
  82. package/src/client/renderers/live2d.test.ts +242 -0
  83. package/src/client/renderers/live2d.ts +218 -0
  84. package/src/client/renderers/registry.ts +58 -0
  85. package/src/client/settings-section.module.css +23 -0
  86. package/src/client/spritesheet.ts +1 -6
  87. package/src/contracts/renderer.ts +54 -0
  88. package/src/manifest-v2.test.ts +251 -0
  89. package/src/manifest-v2.ts +414 -0
  90. package/src/model3.test.ts +79 -0
  91. package/src/model3.ts +91 -0
  92. package/src/registry.test.ts +236 -3
  93. package/src/registry.ts +246 -38
  94. package/src/routes.ts +202 -13
  95. package/src/service.ts +6 -1
@@ -1,14 +1,24 @@
1
1
  /**
2
2
  * Pet registry — the multi-pet contract. One pet is a directory holding a
3
3
  * 'pet.json' manifest plus an atlas image; nothing else is required, and no
4
- * host or client code changes when a pet is added. The registry scans three
4
+ * host or client code changes when a pet is added. The registry scans four
5
5
  * sources, later sources overriding earlier ones on an id collision:
6
6
  *
7
7
  * 1. the package's own 'assets' subdirectories (built-in pets);
8
- * 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets);
9
- * 3. 'PetConfig.pets' manifests composed by the embedding application
8
+ * 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets,
9
+ * legacy source kept readable);
10
+ * 3. '$DSH_HOME/pets' subdirectories (the pet-center user directory);
11
+ * 4. 'PetConfig.pets' manifests composed by the embedding application
10
12
  * (highest precedence).
11
13
  *
14
+ * Manifests are parsed through manifest-v2 (pet-center M2, issue #623): v1
15
+ * manifests are compat-read as sprite2d, v2 manifests validate fail-closed,
16
+ * and structured diagnostics ride alongside the legacy warnings. Live2d
17
+ * entries (pet-center M3) list like any other pet: the entry carries the
18
+ * validated live2d block plus the model's reference closure (the servable
19
+ * set the asset route allows), and a model3.json that is unreadable or
20
+ * declares unsafe references rejects the entry with an error diagnostic.
21
+ *
12
22
  * The manifest follows the Codex/hatch-pet contract (8 columns x 9 rows of
13
23
  * 192x208 cells, the 9-state row order below). Legacy whale-girl manifests
14
24
  * that only carry 'frames' keep working: geometry, per-row frame counts and
@@ -18,6 +28,7 @@
18
28
  */
19
29
  import type { ActivityPhase, PetAnimation } from './state.ts';
20
30
  import { type PetRemarks, type PetRemarksManifest } from './remarks.ts';
31
+ import { type PetRendererKind } from './manifest-v2.ts';
21
32
  /** Fixed row order of the 9-state animation contract. */
22
33
  export declare const PET_ROW_ORDER: readonly PetAnimation[];
23
34
  /** Atlas cell size in px. */
@@ -100,11 +111,37 @@ export interface PetTrackOverride {
100
111
  /** Track to switch to after a non-looping track finishes. */
101
112
  fallback?: PetAnimation;
102
113
  }
114
+ /** The live2d renderer block as served to the browser half (pet-center M3). */
115
+ export interface PetLive2dDefinition {
116
+ /** Browser URL of the .model3.json (served by the host asset route). */
117
+ modelUrl: string;
118
+ /** Manifest-relative model path (host route allow-list key). */
119
+ modelPath: string;
120
+ /** Scale multiplier over the canvas auto-fit, (0, 10]. */
121
+ scale?: number;
122
+ /** Model offset in canvas px from the center-bottom anchor. */
123
+ translate?: {
124
+ x?: number;
125
+ y?: number;
126
+ };
127
+ /** ActivityPhase -> motion group; unmapped phases fall back to idle. */
128
+ motions: Partial<Record<ActivityPhase, string>> & {
129
+ idle: string;
130
+ };
131
+ /** Optional ActivityPhase -> expression name layered over the motion. */
132
+ expressions?: Partial<Record<ActivityPhase, string>>;
133
+ /** Hit area names triggering the tap motion; defaults to every model HitArea. */
134
+ hitAreas?: string[];
135
+ }
103
136
  /** A normalized pet as served to the browser half. */
104
137
  export interface PetDefinition {
105
138
  id: string;
106
139
  displayName: string;
107
140
  description: string;
141
+ /** The renderer this entry mounts with (pet-center M2). */
142
+ renderer: PetRendererKind;
143
+ /** Live2d render block; present exactly when renderer is 'live2d' (M3). */
144
+ live2d?: PetLive2dDefinition;
108
145
  /** Atlas cell size in px. */
109
146
  cell: PetCell;
110
147
  /** Columns per row. */
@@ -128,6 +165,12 @@ export interface PetEntry extends PetDefinition {
128
165
  dir: string;
129
166
  /** Atlas path relative to 'dir' (declared by the manifest). */
130
167
  spritesheetPath: string;
168
+ /**
169
+ * Manifest-relative files the asset route may serve beyond pet.json and
170
+ * 'previews/*' (pet-center M3): the sprite2d atlas, or the live2d model
171
+ * plus its model3.json reference closure.
172
+ */
173
+ servable: readonly string[];
131
174
  /** Normalized per-pet remark pools (manifest 'remarks'), when declared. */
132
175
  remarks?: PetRemarks;
133
176
  }
@@ -135,10 +178,19 @@ export interface PetEntry extends PetDefinition {
135
178
  export interface PetRegistry {
136
179
  entries: PetEntry[];
137
180
  warnings: string[];
181
+ /** Structured diagnostics from the manifest-v2 parse (superset detail of warnings). */
182
+ diagnostics: PetRegistryDiagnostic[];
138
183
  byId(id: string): PetEntry | undefined;
139
184
  /** The pet an installation falls back to when the selection is unknown. */
140
185
  defaultEntry(): PetEntry;
141
186
  }
187
+ /** One structured registry diagnostic (manifest-v2 era). */
188
+ export interface PetRegistryDiagnostic {
189
+ level: 'error' | 'warning';
190
+ /** Where the diagnostic originates (directory or file). */
191
+ source: string;
192
+ message: string;
193
+ }
142
194
  /** Registry sources. */
143
195
  export interface PetRegistryOptions {
144
196
  /** Absolute package root whose 'assets/*' hold built-in pets. */
@@ -147,6 +199,8 @@ export interface PetRegistryOptions {
147
199
  assetPrefix?: string;
148
200
  /** Custom pet directory (defaults to '${CODEX_HOME:-~/.codex}/pets'). */
149
201
  petsDir?: string;
202
+ /** Pet-center user directory (defaults to '$DSH_HOME/pets'; '' disables). */
203
+ dshPetsDir?: string;
150
204
  /** Extra manifest entries composed by the embedding application. */
151
205
  extra?: readonly PetManifest[];
152
206
  }
@@ -169,6 +223,4 @@ export declare function loadPetRegistry(options: PetRegistryOptions): PetRegistr
169
223
  export declare function petEntryView(entry: PetEntry): PetDefinition;
170
224
  /** The absolute file a pet's atlas resolves to (host asset route). */
171
225
  export declare function petAtlasFile(entry: PetEntry): string;
172
- /** The directory basename of one entry (legacy asset URL alias, e.g. whale). */
173
- export declare function petDirAlias(entry: PetEntry): string;
174
226
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,24 @@
1
1
  /**
2
2
  * Pet registry — the multi-pet contract. One pet is a directory holding a
3
3
  * 'pet.json' manifest plus an atlas image; nothing else is required, and no
4
- * host or client code changes when a pet is added. The registry scans three
4
+ * host or client code changes when a pet is added. The registry scans four
5
5
  * sources, later sources overriding earlier ones on an id collision:
6
6
  *
7
7
  * 1. the package's own 'assets' subdirectories (built-in pets);
8
- * 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets);
9
- * 3. 'PetConfig.pets' manifests composed by the embedding application
8
+ * 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets,
9
+ * legacy source kept readable);
10
+ * 3. '$DSH_HOME/pets' subdirectories (the pet-center user directory);
11
+ * 4. 'PetConfig.pets' manifests composed by the embedding application
10
12
  * (highest precedence).
11
13
  *
14
+ * Manifests are parsed through manifest-v2 (pet-center M2, issue #623): v1
15
+ * manifests are compat-read as sprite2d, v2 manifests validate fail-closed,
16
+ * and structured diagnostics ride alongside the legacy warnings. Live2d
17
+ * entries (pet-center M3) list like any other pet: the entry carries the
18
+ * validated live2d block plus the model's reference closure (the servable
19
+ * set the asset route allows), and a model3.json that is unreadable or
20
+ * declares unsafe references rejects the entry with an error diagnostic.
21
+ *
12
22
  * The manifest follows the Codex/hatch-pet contract (8 columns x 9 rows of
13
23
  * 192x208 cells, the 9-state row order below). Legacy whale-girl manifests
14
24
  * that only carry 'frames' keep working: geometry, per-row frame counts and
@@ -21,6 +31,9 @@ import { homedir } from 'node:os';
21
31
  import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
22
32
  import { fileURLToPath } from 'node:url';
23
33
  import { normalizePetRemarks } from './remarks.js';
34
+ import { dshHome } from './dsh-home.js';
35
+ import { parsePetManifest } from './manifest-v2.js';
36
+ import { collectModel3References } from './model3.js';
24
37
  /** Fixed row order of the 9-state animation contract. */
25
38
  export const PET_ROW_ORDER = [
26
39
  'idle',
@@ -115,6 +128,41 @@ function normalizeSequences(raw, id, warn) {
115
128
  }
116
129
  return Object.keys(sequences).length === 0 ? undefined : sequences;
117
130
  }
131
+ /**
132
+ * Build the fully resolved animation tracks from the contract defaults plus
133
+ * optional per-track overrides. Shared by the sprite2d resolver and the
134
+ * live2d entry builder (which fills the sprite fields with contract
135
+ * defaults so the flat PetDefinition shape holds for every renderer).
136
+ */
137
+ function buildTracks(rows, columns, trackOverrides, warn) {
138
+ const tracks = {};
139
+ for (const [row, animation] of PET_ROW_ORDER.entries()) {
140
+ const pattern = DEFAULT_TRACK_PATTERNS[animation];
141
+ const override = trackOverrides[animation];
142
+ const durations = Array.isArray(override?.durations) && override.durations.length > 0
143
+ ? override.durations.filter((value) => typeof value === 'number' && Number.isFinite(value) && value > 0)
144
+ : pattern.durations;
145
+ if (durations.length === 0) {
146
+ warn('track ' + animation + ' carries no usable durations');
147
+ return undefined;
148
+ }
149
+ const frameCount = Math.max(1, Math.min(rows[row], columns));
150
+ const sized = durations.length >= frameCount
151
+ ? durations.slice(0, frameCount)
152
+ : Array.from({ length: frameCount }, (_, index) => durations[index % durations.length]);
153
+ tracks[animation] = {
154
+ frames: Array.from({ length: frameCount }, (_, index) => index),
155
+ durations: sized,
156
+ loop: typeof override?.loop === 'boolean' ? override.loop : pattern.loop,
157
+ ...(override?.fallback === undefined
158
+ ? pattern.fallback === undefined ? {} : { fallback: pattern.fallback }
159
+ : PET_ROW_ORDER.includes(override.fallback)
160
+ ? { fallback: override.fallback }
161
+ : pattern.fallback === undefined ? {} : { fallback: pattern.fallback }),
162
+ };
163
+ }
164
+ return tracks;
165
+ }
118
166
  /**
119
167
  * Normalize one parsed manifest into a renderable pet entry, or undefined
120
168
  * (with a warning recorded) when the manifest violates the contract.
@@ -164,36 +212,15 @@ export function resolvePetManifest(raw, dir, options = {}) {
164
212
  const remarks = normalizePetRemarks(source.remarks, message => warn('manifest ' + id + ': ' + message));
165
213
  const sequences = normalizeSequences(source.sequences, id, warn);
166
214
  const trackOverrides = (typeof source.tracks === 'object' && source.tracks !== null ? source.tracks : {});
167
- const tracks = {};
168
- for (const [row, animation] of PET_ROW_ORDER.entries()) {
169
- const pattern = DEFAULT_TRACK_PATTERNS[animation];
170
- const override = trackOverrides[animation];
171
- const durations = Array.isArray(override?.durations) && override.durations.length > 0
172
- ? override.durations.filter((value) => typeof value === 'number' && Number.isFinite(value) && value > 0)
173
- : pattern.durations;
174
- if (durations.length === 0) {
175
- warn('manifest ' + id + ': track ' + animation + ' carries no usable durations');
176
- return undefined;
177
- }
178
- const frameCount = Math.max(1, Math.min(rows[row], columns));
179
- const sized = durations.length >= frameCount
180
- ? durations.slice(0, frameCount)
181
- : Array.from({ length: frameCount }, (_, index) => durations[index % durations.length]);
182
- tracks[animation] = {
183
- frames: Array.from({ length: frameCount }, (_, index) => index),
184
- durations: sized,
185
- loop: typeof override?.loop === 'boolean' ? override.loop : pattern.loop,
186
- ...(override?.fallback === undefined
187
- ? pattern.fallback === undefined ? {} : { fallback: pattern.fallback }
188
- : PET_ROW_ORDER.includes(override.fallback)
189
- ? { fallback: override.fallback }
190
- : pattern.fallback === undefined ? {} : { fallback: pattern.fallback }),
191
- };
192
- }
215
+ const tracks = buildTracks(rows, columns, trackOverrides, message => warn('manifest ' + id + ': ' + message));
216
+ if (tracks === undefined)
217
+ return undefined;
218
+ const sheet = spritesheetPath.join('/');
193
219
  return {
194
220
  id,
195
221
  displayName,
196
222
  description,
223
+ renderer: 'sprite2d',
197
224
  cell,
198
225
  columns,
199
226
  rows,
@@ -203,7 +230,121 @@ export function resolvePetManifest(raw, dir, options = {}) {
203
230
  atlasUrl: assetUrl(assetPrefix, id, spritesheet),
204
231
  manifestUrl: assetUrl(assetPrefix, id, 'pet.json'),
205
232
  dir,
206
- spritesheetPath: spritesheetPath.join('/'),
233
+ spritesheetPath: sheet,
234
+ servable: [sheet],
235
+ ...(remarks === undefined ? {} : { remarks }),
236
+ };
237
+ }
238
+ /**
239
+ * Adapt a validated v2 manifest's sprite2d block onto the legacy flat shape
240
+ * the established resolver consumes (pet-center M2 P2). The legacy resolver
241
+ * only expresses 9-row (default) and 11-row (spriteVersionNumber 2) atlases,
242
+ * so other atlasRows values are rejected here with a diagnostic.
243
+ */
244
+ function flattenV2Sprite2d(manifest) {
245
+ const block = manifest.sprite2d;
246
+ if (block === undefined)
247
+ return undefined;
248
+ const legacy = {
249
+ id: manifest.id,
250
+ displayName: manifest.displayName,
251
+ spritesheetPath: block.spritesheetPath,
252
+ };
253
+ if (manifest.description !== undefined)
254
+ legacy.description = manifest.description;
255
+ if (block.cell !== undefined)
256
+ legacy.cell = block.cell;
257
+ if (block.columns !== undefined)
258
+ legacy.columns = block.columns;
259
+ if (block.frames !== undefined)
260
+ legacy.frames = block.frames;
261
+ if (block.tracks !== undefined)
262
+ legacy.tracks = block.tracks;
263
+ if (block.atlasRows !== undefined) {
264
+ if (block.atlasRows === 11)
265
+ legacy.spriteVersionNumber = 2;
266
+ else if (block.atlasRows !== DEFAULT_PET_ROW_COUNT)
267
+ return undefined;
268
+ }
269
+ if (manifest.sequences !== undefined)
270
+ legacy.sequences = manifest.sequences;
271
+ if (manifest.remarks !== undefined)
272
+ legacy.remarks = manifest.remarks;
273
+ return legacy;
274
+ }
275
+ /**
276
+ * Resolve a validated live2d manifest into a renderable entry (pet-center
277
+ * M3). The model3.json is read at scan time: its reference closure becomes
278
+ * the entry's servable set (the asset route's allow-list), and a model that
279
+ * is unreadable or declares unsafe references rejects the entry fail-closed
280
+ * with an error diagnostic. Closure files missing on disk warn but keep the
281
+ * entry listed — the client renderer's diagnostic card reports the broken
282
+ * render, matching the registry's never-throw philosophy (install-time
283
+ * strictness belongs to the CLI validator). The sprite fields carry contract
284
+ * defaults: the chrome sizes live2d pets off 'display.size', not the atlas.
285
+ */
286
+ function resolveLive2dEntry(manifest, dir, options) {
287
+ const assetPrefix = options.assetPrefix ?? '/pet';
288
+ const record = (level, message) => {
289
+ options.diagnostics?.push({ level, source: dir, message });
290
+ options.warnings?.push(message);
291
+ };
292
+ const block = manifest.live2d;
293
+ if (block === undefined) {
294
+ record('error', 'pet ' + manifest.id + ': renderer live2d requires a live2d block');
295
+ return undefined;
296
+ }
297
+ let model3;
298
+ try {
299
+ model3 = JSON.parse(readFileSync(join(dir, block.model), 'utf8'));
300
+ }
301
+ catch (error) {
302
+ record('error', 'pet ' + manifest.id + ': live2d model ' + block.model + ' is not readable: '
303
+ + (error instanceof Error ? error.message : String(error)));
304
+ return undefined;
305
+ }
306
+ const { references, errors } = collectModel3References(model3);
307
+ if (errors.length > 0) {
308
+ for (const message of errors) {
309
+ record('error', 'pet ' + manifest.id + ': live2d model ' + block.model + ': ' + message);
310
+ }
311
+ return undefined;
312
+ }
313
+ for (const reference of references) {
314
+ if (!existsSync(join(dir, reference))) {
315
+ record('warning', 'pet ' + manifest.id + ': live2d closure file missing: ' + reference);
316
+ }
317
+ }
318
+ const tracks = buildTracks(DEFAULT_FRAME_COUNTS, DEFAULT_PET_COLUMNS, {}, message => record('warning', 'pet ' + manifest.id + ': ' + message));
319
+ if (tracks === undefined)
320
+ return undefined;
321
+ const remarks = normalizePetRemarks(manifest.remarks, message => record('warning', 'pet ' + manifest.id + ': ' + message));
322
+ const modelUrl = assetUrl(assetPrefix, manifest.id, block.model);
323
+ const live2d = {
324
+ modelUrl,
325
+ modelPath: block.model,
326
+ ...(block.scale === undefined ? {} : { scale: block.scale }),
327
+ ...(block.translate === undefined ? {} : { translate: block.translate }),
328
+ motions: block.motions,
329
+ ...(block.expressions === undefined ? {} : { expressions: block.expressions }),
330
+ ...(block.hitAreas === undefined ? {} : { hitAreas: block.hitAreas }),
331
+ };
332
+ return {
333
+ id: manifest.id,
334
+ displayName: manifest.displayName,
335
+ description: manifest.description ?? '',
336
+ renderer: 'live2d',
337
+ live2d,
338
+ cell: { ...DEFAULT_PET_CELL },
339
+ columns: DEFAULT_PET_COLUMNS,
340
+ rows: [...DEFAULT_FRAME_COUNTS],
341
+ atlasRows: DEFAULT_PET_ROW_COUNT,
342
+ tracks,
343
+ atlasUrl: modelUrl,
344
+ manifestUrl: assetUrl(assetPrefix, manifest.id, 'pet.json'),
345
+ dir,
346
+ spritesheetPath: block.model,
347
+ servable: [block.model, ...references],
207
348
  ...(remarks === undefined ? {} : { remarks }),
208
349
  };
209
350
  }
@@ -227,7 +368,28 @@ function scanPetDir(dir, options) {
227
368
  const parsed = readPetJson(manifestFile, options.warnings);
228
369
  if (parsed === undefined)
229
370
  continue;
230
- const entry = resolvePetManifest(parsed, join(dir, name), options);
371
+ const entryDir = join(dir, name);
372
+ const verdict = parsePetManifest(parsed, entryDir);
373
+ for (const diagnostic of verdict.diagnostics) {
374
+ options.diagnostics?.push({ level: diagnostic.level, source: entryDir, message: diagnostic.message });
375
+ options.warnings?.push(diagnostic.message);
376
+ }
377
+ if (!verdict.ok)
378
+ continue;
379
+ if (verdict.manifest.renderer === 'live2d') {
380
+ const entry = resolveLive2dEntry(verdict.manifest, entryDir, options);
381
+ if (entry !== undefined)
382
+ entries.push(entry);
383
+ continue;
384
+ }
385
+ const legacy = flattenV2Sprite2d(verdict.manifest);
386
+ if (legacy === undefined) {
387
+ const note = 'pet ' + verdict.manifest.id + ': sprite2d.atlasRows only supports 9 or 11 under the v1 compat resolver';
388
+ options.diagnostics?.push({ level: 'error', source: entryDir, message: note });
389
+ options.warnings?.push(note);
390
+ continue;
391
+ }
392
+ const entry = resolvePetManifest(legacy, entryDir, options);
231
393
  if (entry !== undefined)
232
394
  entries.push(entry);
233
395
  }
@@ -252,9 +414,10 @@ function readPetJson(file, warnings) {
252
414
  export function loadPetRegistry(options) {
253
415
  const { packageRoot, assetPrefix = '/pet' } = options;
254
416
  const warnings = [];
417
+ const diagnostics = [];
255
418
  const byId = new Map();
256
419
  const builtinIds = new Set();
257
- for (const entry of scanPetDir(join(packageRoot, 'assets'), { assetPrefix, warnings })) {
420
+ for (const entry of scanPetDir(join(packageRoot, 'assets'), { assetPrefix, warnings, diagnostics })) {
258
421
  if (byId.has(entry.id)) {
259
422
  warnings.push('duplicate built-in pet id ' + entry.id + '; the first one wins');
260
423
  continue;
@@ -264,12 +427,21 @@ export function loadPetRegistry(options) {
264
427
  }
265
428
  const petsDir = options.petsDir ?? codexPetsDir();
266
429
  if (petsDir !== '') {
267
- for (const entry of scanPetDir(petsDir, { assetPrefix, warnings })) {
430
+ for (const entry of scanPetDir(petsDir, { assetPrefix, warnings, diagnostics })) {
268
431
  if (byId.has(entry.id))
269
432
  warnings.push('custom pet ' + entry.id + ' overrides the built-in one');
270
433
  byId.set(entry.id, entry);
271
434
  }
272
435
  }
436
+ // The pet-center user directory ranks above the legacy hatch-pet source.
437
+ const dshPetsDir = options.dshPetsDir ?? join(dshHome(), 'pets');
438
+ if (dshPetsDir !== '') {
439
+ for (const entry of scanPetDir(dshPetsDir, { assetPrefix, warnings, diagnostics })) {
440
+ if (byId.has(entry.id))
441
+ warnings.push('user pet ' + entry.id + ' overrides an earlier registration');
442
+ byId.set(entry.id, entry);
443
+ }
444
+ }
273
445
  for (const manifest of options.extra ?? []) {
274
446
  const raw = manifest.spritesheetPath;
275
447
  const dir = raw === undefined || isAbsolute(raw)
@@ -293,6 +465,7 @@ export function loadPetRegistry(options) {
293
465
  return {
294
466
  entries,
295
467
  warnings,
468
+ diagnostics,
296
469
  byId: (id) => byId.get(id),
297
470
  defaultEntry: () => entries.find(entry => builtinIds.has(entry.id)) ?? entries[0],
298
471
  };
@@ -303,6 +476,8 @@ export function petEntryView(entry) {
303
476
  id: entry.id,
304
477
  displayName: entry.displayName,
305
478
  description: entry.description,
479
+ renderer: entry.renderer,
480
+ ...(entry.live2d === undefined ? {} : { live2d: entry.live2d }),
306
481
  cell: entry.cell,
307
482
  columns: entry.columns,
308
483
  rows: entry.rows,
@@ -317,7 +492,3 @@ export function petEntryView(entry) {
317
492
  export function petAtlasFile(entry) {
318
493
  return join(entry.dir, entry.spritesheetPath);
319
494
  }
320
- /** The directory basename of one entry (legacy asset URL alias, e.g. whale). */
321
- export function petDirAlias(entry) {
322
- return basename(entry.dir);
323
- }
@@ -14,9 +14,46 @@ import type { PetService } from './service.ts';
14
14
  export declare const PET_API_PREFIX = "/api/pet";
15
15
  /** Browser-facing base path of the pet asset routes ('/pet/<id>/...'). */
16
16
  export declare const PET_ASSET_PREFIX = "/pet";
17
- /** Build the full route family (API + assets) for one service. */
17
+ /**
18
+ * Per-class size ceilings for served pet assets, in bytes (pet-center M2 P3,
19
+ * issue #623). Constants are tested directly; makePetRoutes accepts an
20
+ * override so tests can exercise the 413 path with tiny caps.
21
+ */
22
+ export declare const PET_ASSET_CAPS: {
23
+ /** pet.json manifest. */
24
+ readonly manifest: number;
25
+ /** Atlas, preview and Live2D texture imagery. */
26
+ readonly image: number;
27
+ /** Live2D model closure files (.moc3, motion/physics/expression JSON; M3). */
28
+ readonly model: number;
29
+ };
30
+ /** Size-cap profile the asset route enforces (test seam). */
31
+ export interface PetAssetCaps {
32
+ manifest: number;
33
+ image: number;
34
+ model: number;
35
+ }
36
+ /**
37
+ * realpath containment: resolve both sides and require the candidate to stay
38
+ * inside the base directory. A pet directory (or an atlas/preview inside it)
39
+ * that is a symlink escaping its root is rejected, never followed.
40
+ */
41
+ export declare function containedRealpath(base: string, candidate: string): string | undefined;
42
+ /** Browser-facing base path of the plugin runtime files (pet-center M3). */
43
+ export declare const PET_RUNTIME_PREFIX: string;
44
+ /** Size ceiling for one runtime file (the Cubism Core is ~200 KB today). */
45
+ export declare const PET_RUNTIME_CAP: number;
46
+ /** Runtime file roots (test seam; defaults resolve from the environment). */
47
+ export interface PetRuntimeRoots {
48
+ /** User-supplied runtime directory (defaults to '$DSH_HOME/pets/.runtime'). */
49
+ runtimeDir?: string;
50
+ /** Plugin vendor bundle directory (defaults to the package 'lib'). */
51
+ vendorDir?: string;
52
+ }
53
+ /** Build the full route family (API + assets + runtime) for one service. */
18
54
  export declare function makePetRoutes(deps: {
19
55
  service: PetService;
20
- }): WebRoute[];
56
+ assetCaps?: PetAssetCaps;
57
+ } & PetRuntimeRoots): WebRoute[];
21
58
  export { petPackageRoot } from './registry.ts';
22
59
  //# sourceMappingURL=routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAK9C,+CAA+C;AAC/C,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAiOtC,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,UAAU,CAAA;CAAE,GAAG,QAAQ,EAAE,CAwCvE;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAM9C,+CAA+C;AAC/C,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAMtC;;;;GAIG;AACH,eAAO,MAAM,cAAc;IACzB,yBAAyB;aACzB,QAAQ;IACR,iDAAiD;aACjD,KAAK;IACL,8EAA8E;aAC9E,KAAK;CACG,CAAA;AAEV,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAWD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUrF;AAsPD,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAA8B,CAAA;AAe7D,4EAA4E;AAC5E,eAAO,MAAM,eAAe,QAAmB,CAAA;AAE/C,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAiFD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,SAAS,CAAC,EAAE,YAAY,CAAA;CAAE,GAAG,eAAe,GAAG,QAAQ,EAAE,CAkDnH;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}