@linxin666/dsh-pet 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +129 -3
  3. package/README.zh.md +129 -3
  4. package/assets/decorations/whale/decoration.json +20 -0
  5. package/assets/decorations/whale/whale-frames.png +0 -0
  6. package/assets/whale/pet.json +169 -20
  7. package/assets/whale-refined/pet.json +17 -2
  8. package/contracts/pet-manifest-v2.schema.json +281 -0
  9. package/contracts/status-decoration-v1.schema.json +144 -0
  10. package/contracts/voice-pack-v1.schema.json +234 -0
  11. package/lib/client.js +581 -38
  12. package/lib/client.js.map +1 -1
  13. package/lib/index.js +1684 -59
  14. package/lib/live2d-vendor.js +995 -0
  15. package/lib/live2d-vendor.js.map +1 -0
  16. package/lib/types/chatter.d.ts +61 -3
  17. package/lib/types/chatter.d.ts.map +1 -1
  18. package/lib/types/chatter.js +71 -12
  19. package/lib/types/client/PetDockEntry.d.ts.map +1 -1
  20. package/lib/types/client/PetDockEntry.js +2 -1
  21. package/lib/types/client/PetSettingsCard.d.ts +14 -0
  22. package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
  23. package/lib/types/client/PetSettingsCard.js +24 -1
  24. package/lib/types/client/PetSprite.d.ts +7 -1
  25. package/lib/types/client/PetSprite.d.ts.map +1 -1
  26. package/lib/types/client/PetSprite.js +120 -12
  27. package/lib/types/client/index.d.ts.map +1 -1
  28. package/lib/types/client/index.js +5 -0
  29. package/lib/types/client/locales.d.ts +14 -0
  30. package/lib/types/client/locales.d.ts.map +1 -1
  31. package/lib/types/client/locales.js +14 -0
  32. package/lib/types/client/phase-stream.d.ts +22 -0
  33. package/lib/types/client/phase-stream.d.ts.map +1 -0
  34. package/lib/types/client/phase-stream.js +28 -0
  35. package/lib/types/client/renderers/PetRendererSwitch.d.ts +25 -0
  36. package/lib/types/client/renderers/PetRendererSwitch.d.ts.map +1 -0
  37. package/lib/types/client/renderers/PetRendererSwitch.js +24 -0
  38. package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts +22 -0
  39. package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts.map +1 -0
  40. package/lib/types/client/renderers/live2d/Live2dVisualMount.js +75 -0
  41. package/lib/types/client/renderers/live2d/runtime.d.ts +89 -0
  42. package/lib/types/client/renderers/live2d/runtime.d.ts.map +1 -0
  43. package/lib/types/client/renderers/live2d/runtime.js +63 -0
  44. package/lib/types/client/renderers/live2d/vendor-entry.d.ts +15 -0
  45. package/lib/types/client/renderers/live2d/vendor-entry.d.ts.map +1 -0
  46. package/lib/types/client/renderers/live2d/vendor-entry.js +14 -0
  47. package/lib/types/client/renderers/live2d.d.ts +52 -0
  48. package/lib/types/client/renderers/live2d.d.ts.map +1 -0
  49. package/lib/types/client/renderers/live2d.js +192 -0
  50. package/lib/types/client/renderers/registry.d.ts +32 -0
  51. package/lib/types/client/renderers/registry.d.ts.map +1 -0
  52. package/lib/types/client/renderers/registry.js +49 -0
  53. package/lib/types/client/settings-form.d.ts.map +1 -1
  54. package/lib/types/client/settings-form.js +9 -6
  55. package/lib/types/contracts/renderer.d.ts +50 -0
  56. package/lib/types/contracts/renderer.d.ts.map +1 -0
  57. package/lib/types/contracts/renderer.js +15 -0
  58. package/lib/types/contracts/status-decoration.d.ts +85 -0
  59. package/lib/types/contracts/status-decoration.d.ts.map +1 -0
  60. package/lib/types/contracts/status-decoration.js +21 -0
  61. package/lib/types/decoration.d.ts +39 -0
  62. package/lib/types/decoration.d.ts.map +1 -0
  63. package/lib/types/decoration.js +210 -0
  64. package/lib/types/event-projection.d.ts +8 -3
  65. package/lib/types/event-projection.d.ts.map +1 -1
  66. package/lib/types/event-projection.js +9 -4
  67. package/lib/types/index.d.ts +2 -0
  68. package/lib/types/index.d.ts.map +1 -1
  69. package/lib/types/index.js +2 -0
  70. package/lib/types/manifest-v2.d.ts +129 -0
  71. package/lib/types/manifest-v2.d.ts.map +1 -0
  72. package/lib/types/manifest-v2.js +387 -0
  73. package/lib/types/model3.d.ts +26 -0
  74. package/lib/types/model3.d.ts.map +1 -0
  75. package/lib/types/model3.js +96 -0
  76. package/lib/types/registry.d.ts +112 -5
  77. package/lib/types/registry.d.ts.map +1 -1
  78. package/lib/types/registry.js +395 -38
  79. package/lib/types/routes.d.ts +39 -2
  80. package/lib/types/routes.d.ts.map +1 -1
  81. package/lib/types/routes.js +312 -13
  82. package/lib/types/service.d.ts +38 -1
  83. package/lib/types/service.d.ts.map +1 -1
  84. package/lib/types/service.js +46 -3
  85. package/lib/types/voice-pack.d.ts +98 -0
  86. package/lib/types/voice-pack.d.ts.map +1 -0
  87. package/lib/types/voice-pack.js +384 -0
  88. package/package.json +13 -10
  89. package/src/chatter.test.ts +89 -2
  90. package/src/chatter.ts +120 -14
  91. package/src/client/PetDockEntry.tsx +19 -11
  92. package/src/client/PetSettingsCard.tsx +57 -0
  93. package/src/client/PetSprite.test.tsx +265 -12
  94. package/src/client/PetSprite.tsx +165 -33
  95. package/src/client/index.ts +6 -0
  96. package/src/client/locales.ts +14 -0
  97. package/src/client/phase-stream.test.ts +76 -0
  98. package/src/client/phase-stream.ts +39 -0
  99. package/src/client/renderers/PetRendererSwitch.test.tsx +66 -0
  100. package/src/client/renderers/PetRendererSwitch.tsx +48 -0
  101. package/src/client/renderers/live2d/Live2dVisualMount.tsx +98 -0
  102. package/src/client/renderers/live2d/runtime.test.ts +61 -0
  103. package/src/client/renderers/live2d/runtime.ts +119 -0
  104. package/src/client/renderers/live2d/vendor-entry.ts +14 -0
  105. package/src/client/renderers/live2d.test.ts +263 -0
  106. package/src/client/renderers/live2d.ts +231 -0
  107. package/src/client/renderers/registry.ts +58 -0
  108. package/src/client/settings-form.ts +8 -6
  109. package/src/client/settings-section.module.css +23 -0
  110. package/src/contracts/renderer.ts +54 -0
  111. package/src/contracts/status-decoration.ts +78 -0
  112. package/src/decoration.test.ts +178 -0
  113. package/src/decoration.ts +220 -0
  114. package/src/event-projection.ts +10 -5
  115. package/src/index.ts +2 -0
  116. package/src/manifest-v2.test.ts +251 -0
  117. package/src/manifest-v2.ts +414 -0
  118. package/src/model3.test.ts +79 -0
  119. package/src/model3.ts +91 -0
  120. package/src/registry.test.ts +438 -2
  121. package/src/registry.ts +470 -38
  122. package/src/routes.ts +328 -14
  123. package/src/service.ts +65 -3
  124. package/src/voice-pack.test.ts +216 -0
  125. package/src/voice-pack.ts +413 -0
@@ -0,0 +1,281 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.linxin666.org/dsh-pet/pet-manifest-v2.schema.json",
4
+ "title": "DSH Pet Manifest v2",
5
+ "description": "Pet-center manifest v2 (issue #623). Pure-asset pet directory contract: renderer type declaration, license metadata, and renderer-specific blocks. Top level and renderer blocks are fail-closed; v1 manifests (no petManifestVersion) are compat-read as sprite2d by the registry.",
6
+ "type": "object",
7
+ "required": [
8
+ "petManifestVersion",
9
+ "id",
10
+ "displayName",
11
+ "license"
12
+ ],
13
+ "additionalProperties": false,
14
+ "properties": {
15
+ "$schema": {
16
+ "type": "string"
17
+ },
18
+ "petManifestVersion": {
19
+ "const": 2
20
+ },
21
+ "id": {
22
+ "type": "string",
23
+ "pattern": "^[a-z0-9][a-z0-9-]*$",
24
+ "maxLength": 64,
25
+ "description": "Globally unique lowercase kebab-case pet id."
26
+ },
27
+ "displayName": {
28
+ "type": "string",
29
+ "minLength": 1,
30
+ "maxLength": 64
31
+ },
32
+ "description": {
33
+ "type": "string",
34
+ "maxLength": 500
35
+ },
36
+ "version": {
37
+ "type": "string",
38
+ "pattern": "^\\d+\\.\\d+\\.\\d+$"
39
+ },
40
+ "author": {
41
+ "type": "string",
42
+ "maxLength": 128
43
+ },
44
+ "license": {
45
+ "type": "string",
46
+ "minLength": 1,
47
+ "maxLength": 128,
48
+ "description": "Asset license identifier (SPDX id or free text). Required so community pets always carry provenance."
49
+ },
50
+ "homepage": {
51
+ "type": "string",
52
+ "maxLength": 500,
53
+ "description": "Optional provenance URL for the pet assets."
54
+ },
55
+ "renderer": {
56
+ "enum": [
57
+ "sprite2d",
58
+ "live2d"
59
+ ],
60
+ "default": "sprite2d",
61
+ "description": "Renderer kind; omitted means sprite2d (v1 compatibility). Unknown values are rejected."
62
+ },
63
+ "sprite2d": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "required": [
67
+ "spritesheetPath"
68
+ ],
69
+ "description": "Spritesheet renderer block; required when renderer=sprite2d.",
70
+ "properties": {
71
+ "spritesheetPath": {
72
+ "type": "string",
73
+ "minLength": 1,
74
+ "description": "Atlas path relative to the manifest directory (safe segments only)."
75
+ },
76
+ "cell": {
77
+ "type": "object",
78
+ "additionalProperties": false,
79
+ "description": "Atlas cell size in px; defaults to the Codex contract 192x208.",
80
+ "properties": {
81
+ "width": {
82
+ "type": "integer",
83
+ "minimum": 1,
84
+ "maximum": 2048
85
+ },
86
+ "height": {
87
+ "type": "integer",
88
+ "minimum": 1,
89
+ "maximum": 2048
90
+ }
91
+ }
92
+ },
93
+ "columns": {
94
+ "type": "integer",
95
+ "minimum": 1,
96
+ "maximum": 32,
97
+ "default": 8
98
+ },
99
+ "atlasRows": {
100
+ "type": "integer",
101
+ "minimum": 1,
102
+ "maximum": 32,
103
+ "description": "Total atlas rows; 9 for the classic contract, 11 for v2 look-row atlases."
104
+ },
105
+ "frames": {
106
+ "type": "array",
107
+ "maxItems": 32,
108
+ "items": {
109
+ "type": "integer",
110
+ "minimum": 0,
111
+ "maximum": 32
112
+ },
113
+ "description": "Per-row used frame counts; omitted rows fall back to the hatch-pet contract table."
114
+ },
115
+ "tracks": {
116
+ "type": "object",
117
+ "description": "Per-track rhythm overrides (durations/loop/fallback), v1 structure unchanged."
118
+ }
119
+ }
120
+ },
121
+ "live2d": {
122
+ "type": "object",
123
+ "additionalProperties": false,
124
+ "required": [
125
+ "model",
126
+ "motions"
127
+ ],
128
+ "description": "Live2D renderer block; required when renderer=live2d. The Cubism Core runtime is always user-supplied; the plugin never bundles or downloads it.",
129
+ "properties": {
130
+ "model": {
131
+ "type": "string",
132
+ "minLength": 1,
133
+ "pattern": "\\.model3\\.json$",
134
+ "description": "Path of the .model3.json relative to the manifest directory."
135
+ },
136
+ "scale": {
137
+ "type": "number",
138
+ "exclusiveMinimum": 0,
139
+ "maximum": 10,
140
+ "default": 1
141
+ },
142
+ "translate": {
143
+ "type": "object",
144
+ "additionalProperties": false,
145
+ "properties": {
146
+ "x": {
147
+ "type": "number"
148
+ },
149
+ "y": {
150
+ "type": "number"
151
+ }
152
+ }
153
+ },
154
+ "motions": {
155
+ "type": "object",
156
+ "additionalProperties": false,
157
+ "required": [
158
+ "idle"
159
+ ],
160
+ "description": "ActivityPhase -> model motion group name. Unmapped phases fall back to the idle group; missing groups degrade to the first frame with a diagnostic.",
161
+ "properties": {
162
+ "idle": {
163
+ "type": "string",
164
+ "minLength": 1
165
+ },
166
+ "waiting": {
167
+ "type": "string",
168
+ "minLength": 1
169
+ },
170
+ "thinking": {
171
+ "type": "string",
172
+ "minLength": 1
173
+ },
174
+ "tool": {
175
+ "type": "string",
176
+ "minLength": 1
177
+ },
178
+ "review": {
179
+ "type": "string",
180
+ "minLength": 1
181
+ },
182
+ "done": {
183
+ "type": "string",
184
+ "minLength": 1
185
+ },
186
+ "failed": {
187
+ "type": "string",
188
+ "minLength": 1
189
+ }
190
+ }
191
+ },
192
+ "expressions": {
193
+ "type": "object",
194
+ "additionalProperties": false,
195
+ "description": "Optional ActivityPhase -> expression name (layered over the motion).",
196
+ "properties": {
197
+ "idle": {
198
+ "type": "string",
199
+ "minLength": 1
200
+ },
201
+ "waiting": {
202
+ "type": "string",
203
+ "minLength": 1
204
+ },
205
+ "thinking": {
206
+ "type": "string",
207
+ "minLength": 1
208
+ },
209
+ "tool": {
210
+ "type": "string",
211
+ "minLength": 1
212
+ },
213
+ "review": {
214
+ "type": "string",
215
+ "minLength": 1
216
+ },
217
+ "done": {
218
+ "type": "string",
219
+ "minLength": 1
220
+ },
221
+ "failed": {
222
+ "type": "string",
223
+ "minLength": 1
224
+ }
225
+ }
226
+ },
227
+ "hitAreas": {
228
+ "type": "array",
229
+ "items": {
230
+ "type": "string",
231
+ "minLength": 1
232
+ },
233
+ "description": "Hit area names that trigger pet.interact; defaults to every HitArea the model declares."
234
+ },
235
+ "lipSync": {
236
+ "type": "boolean",
237
+ "default": false,
238
+ "description": "Optional whisper-paced lip sync (post-M3)."
239
+ }
240
+ }
241
+ },
242
+ "sequences": {
243
+ "type": "object",
244
+ "description": "Renderer-agnostic ActivityPhase sequence table (v1 structure; every declared sequence has at least 5 items)."
245
+ },
246
+ "remarks": {
247
+ "type": "object",
248
+ "description": "Per-slot witty-remark pools (v1 structure; a slot replaces the built-in pool for that slot only)."
249
+ }
250
+ },
251
+ "allOf": [
252
+ {
253
+ "if": {
254
+ "properties": {
255
+ "renderer": {
256
+ "const": "sprite2d"
257
+ }
258
+ }
259
+ },
260
+ "then": {
261
+ "required": [
262
+ "sprite2d"
263
+ ]
264
+ }
265
+ },
266
+ {
267
+ "if": {
268
+ "properties": {
269
+ "renderer": {
270
+ "const": "live2d"
271
+ }
272
+ }
273
+ },
274
+ "then": {
275
+ "required": [
276
+ "live2d"
277
+ ]
278
+ }
279
+ }
280
+ ]
281
+ }
@@ -0,0 +1,144 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.linxin666.org/dsh-pet/status-decoration-v1.schema.json",
4
+ "title": "DSH Pet Status Decoration v1",
5
+ "description": "Status-decoration descriptor (issue #623 M5, protocol #567). A pure-content entry ornamenting the pet center's status bubble chrome with a PNG/WebP sprite strip driven by the ActivityPhase stream. Structure is fail-closed; phase-binding content issues drop that binding only. Entry assets are PNG/WebP strips only (no SVG/CSS) per the adopted disciplines.",
6
+ "type": "object",
7
+ "required": [
8
+ "decorationManifestVersion",
9
+ "id",
10
+ "license",
11
+ "entry",
12
+ "cell",
13
+ "columns"
14
+ ],
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "$schema": {
18
+ "type": "string"
19
+ },
20
+ "decorationManifestVersion": {
21
+ "const": 1
22
+ },
23
+ "id": {
24
+ "type": "string",
25
+ "pattern": "^[a-z0-9][a-z0-9-]*$",
26
+ "maxLength": 64
27
+ },
28
+ "displayName": {
29
+ "type": "string",
30
+ "maxLength": 64
31
+ },
32
+ "license": {
33
+ "type": "string",
34
+ "minLength": 1,
35
+ "maxLength": 128,
36
+ "description": "Asset license identifier (SPDX id or free text). Required so community decorations always carry provenance."
37
+ },
38
+ "entry": {
39
+ "type": "string",
40
+ "maxLength": 256,
41
+ "description": "PNG/WebP single-row sprite strip, relative to the descriptor directory."
42
+ },
43
+ "cell": {
44
+ "type": "object",
45
+ "required": [
46
+ "width",
47
+ "height"
48
+ ],
49
+ "additionalProperties": false,
50
+ "properties": {
51
+ "width": {
52
+ "type": "integer",
53
+ "minimum": 1,
54
+ "maximum": 256
55
+ },
56
+ "height": {
57
+ "type": "integer",
58
+ "minimum": 1,
59
+ "maximum": 256
60
+ }
61
+ }
62
+ },
63
+ "columns": {
64
+ "type": "integer",
65
+ "minimum": 1,
66
+ "maximum": 16
67
+ },
68
+ "frameMs": {
69
+ "type": "integer",
70
+ "minimum": 1,
71
+ "maximum": 2000,
72
+ "description": "Constant per-frame duration; 'durations' overrides per frame."
73
+ },
74
+ "durations": {
75
+ "type": "array",
76
+ "items": {
77
+ "type": "integer",
78
+ "minimum": 1,
79
+ "maximum": 2000
80
+ },
81
+ "description": "Per-frame durations; length must equal 'columns'."
82
+ },
83
+ "loop": {
84
+ "type": "boolean",
85
+ "default": true
86
+ },
87
+ "phases": {
88
+ "type": "object",
89
+ "additionalProperties": false,
90
+ "description": "ActivityPhase -> frame segment; 'hide' (default) shows no ornament.",
91
+ "properties": {
92
+ "idle": {
93
+ "$ref": "#/definitions/phaseBinding"
94
+ },
95
+ "waiting": {
96
+ "$ref": "#/definitions/phaseBinding"
97
+ },
98
+ "thinking": {
99
+ "$ref": "#/definitions/phaseBinding"
100
+ },
101
+ "tool": {
102
+ "$ref": "#/definitions/phaseBinding"
103
+ },
104
+ "review": {
105
+ "$ref": "#/definitions/phaseBinding"
106
+ },
107
+ "done": {
108
+ "$ref": "#/definitions/phaseBinding"
109
+ },
110
+ "failed": {
111
+ "$ref": "#/definitions/phaseBinding"
112
+ }
113
+ }
114
+ }
115
+ },
116
+ "definitions": {
117
+ "phaseBinding": {
118
+ "oneOf": [
119
+ {
120
+ "const": "hide"
121
+ },
122
+ {
123
+ "type": "object",
124
+ "required": [
125
+ "from",
126
+ "to"
127
+ ],
128
+ "additionalProperties": false,
129
+ "properties": {
130
+ "from": {
131
+ "type": "integer",
132
+ "minimum": 0
133
+ },
134
+ "to": {
135
+ "type": "integer",
136
+ "minimum": 0
137
+ }
138
+ },
139
+ "description": "Inclusive frame segment into the strip; must satisfy from <= to < columns."
140
+ }
141
+ ]
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,234 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.linxin666.org/dsh-pet/voice-pack-v1.schema.json",
4
+ "title": "DSH Pet Voice Pack v1",
5
+ "description": "Pet-center voice pack (issue #677). Optional voice.json inside a pet directory, or the global $DSH_HOME/pets/.voice.json override — pure JSON content layering status / tool / whisper copy over the built-in pools, plus hover-panel chrome. Structure is fail-closed per file (a non-object root drops the pack); content is warn-and-drop per slot.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "$schema": {
10
+ "type": "string"
11
+ },
12
+ "voicePackVersion": {
13
+ "const": 1,
14
+ "description": "Optional; absent reads as v1."
15
+ },
16
+ "status": {
17
+ "type": "object",
18
+ "additionalProperties": false,
19
+ "description": "Status copy pools keyed by the eleven StatusScene ids; each key replaces that scene's built-in pool.",
20
+ "properties": {
21
+ "prepare": {
22
+ "$ref": "#/definitions/pool"
23
+ },
24
+ "waiting": {
25
+ "$ref": "#/definitions/pool"
26
+ },
27
+ "thinking": {
28
+ "$ref": "#/definitions/pool"
29
+ },
30
+ "review": {
31
+ "$ref": "#/definitions/pool"
32
+ },
33
+ "toolResult": {
34
+ "$ref": "#/definitions/pool"
35
+ },
36
+ "done": {
37
+ "$ref": "#/definitions/pool"
38
+ },
39
+ "failed": {
40
+ "$ref": "#/definitions/pool"
41
+ },
42
+ "toolFailed": {
43
+ "$ref": "#/definitions/pool"
44
+ },
45
+ "maxTokens": {
46
+ "$ref": "#/definitions/pool"
47
+ },
48
+ "interrupted": {
49
+ "$ref": "#/definitions/pool"
50
+ },
51
+ "blocked": {
52
+ "$ref": "#/definitions/pool"
53
+ }
54
+ }
55
+ },
56
+ "tools": {
57
+ "type": "object",
58
+ "additionalProperties": false,
59
+ "description": "Tool copy pools keyed by the seventeen ToolCategory ids; {tool} and {hint} interpolate.",
60
+ "properties": {
61
+ "read": {
62
+ "$ref": "#/definitions/pool"
63
+ },
64
+ "write": {
65
+ "$ref": "#/definitions/pool"
66
+ },
67
+ "edit": {
68
+ "$ref": "#/definitions/pool"
69
+ },
70
+ "shell": {
71
+ "$ref": "#/definitions/pool"
72
+ },
73
+ "grep": {
74
+ "$ref": "#/definitions/pool"
75
+ },
76
+ "find": {
77
+ "$ref": "#/definitions/pool"
78
+ },
79
+ "ls": {
80
+ "$ref": "#/definitions/pool"
81
+ },
82
+ "webSearch": {
83
+ "$ref": "#/definitions/pool"
84
+ },
85
+ "webFetch": {
86
+ "$ref": "#/definitions/pool"
87
+ },
88
+ "mcp": {
89
+ "$ref": "#/definitions/pool"
90
+ },
91
+ "memory": {
92
+ "$ref": "#/definitions/pool"
93
+ },
94
+ "subagent": {
95
+ "$ref": "#/definitions/pool"
96
+ },
97
+ "todo": {
98
+ "$ref": "#/definitions/pool"
99
+ },
100
+ "browser": {
101
+ "$ref": "#/definitions/pool"
102
+ },
103
+ "git": {
104
+ "$ref": "#/definitions/pool"
105
+ },
106
+ "ask": {
107
+ "$ref": "#/definitions/pool"
108
+ },
109
+ "generic": {
110
+ "$ref": "#/definitions/pool"
111
+ }
112
+ }
113
+ },
114
+ "toolRemaining": {
115
+ "$ref": "#/definitions/pool",
116
+ "description": "The parallel-tools count line pool; {n} interpolates the count."
117
+ },
118
+ "whispers": {
119
+ "type": "object",
120
+ "additionalProperties": false,
121
+ "description": "Murmur pools; each section replaces the built-in one as a whole. An explicit empty array mutes that channel.",
122
+ "properties": {
123
+ "generic": {
124
+ "$ref": "#/definitions/pool"
125
+ },
126
+ "rules": {
127
+ "type": "array",
128
+ "maxItems": 32,
129
+ "items": {
130
+ "type": "object",
131
+ "additionalProperties": false,
132
+ "required": [
133
+ "keywords",
134
+ "pool"
135
+ ],
136
+ "properties": {
137
+ "keywords": {
138
+ "type": "array",
139
+ "maxItems": 16,
140
+ "items": {
141
+ "type": "string",
142
+ "maxLength": 40,
143
+ "minLength": 1
144
+ },
145
+ "description": "Lowercase substrings matched against the model's output."
146
+ },
147
+ "pool": {
148
+ "$ref": "#/definitions/pool"
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ },
155
+ "panel": {
156
+ "type": "object",
157
+ "additionalProperties": false,
158
+ "description": "Hover-panel chrome; unset slots keep the client's i18n dictionary copy.",
159
+ "properties": {
160
+ "labels": {
161
+ "type": "object",
162
+ "additionalProperties": false,
163
+ "properties": {
164
+ "feed": {
165
+ "type": "string",
166
+ "maxLength": 40
167
+ },
168
+ "rename": {
169
+ "type": "string",
170
+ "maxLength": 40
171
+ },
172
+ "hide": {
173
+ "type": "string",
174
+ "maxLength": 40
175
+ },
176
+ "confirm": {
177
+ "type": "string",
178
+ "maxLength": 40
179
+ }
180
+ }
181
+ },
182
+ "stats": {
183
+ "type": "object",
184
+ "additionalProperties": false,
185
+ "description": "{rank} / {n} / {points} interpolate the live values.",
186
+ "properties": {
187
+ "rank": {
188
+ "type": "string",
189
+ "maxLength": 80
190
+ },
191
+ "treats": {
192
+ "type": "string",
193
+ "maxLength": 80
194
+ },
195
+ "points": {
196
+ "type": "string",
197
+ "maxLength": 80
198
+ }
199
+ }
200
+ },
201
+ "actions": {
202
+ "type": "array",
203
+ "uniqueItems": true,
204
+ "items": {
205
+ "enum": [
206
+ "feed",
207
+ "rename",
208
+ "hide"
209
+ ]
210
+ },
211
+ "description": "Subset of actions to render in canonical order; absent = all three, [] = none."
212
+ }
213
+ }
214
+ }
215
+ },
216
+ "definitions": {
217
+ "pool": {
218
+ "oneOf": [
219
+ {
220
+ "type": "string",
221
+ "maxLength": 160
222
+ },
223
+ {
224
+ "type": "array",
225
+ "maxItems": 64,
226
+ "items": {
227
+ "type": "string",
228
+ "maxLength": 160
229
+ }
230
+ }
231
+ ]
232
+ }
233
+ }
234
+ }