@stina/extension-api 1.17.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -156,11 +156,28 @@
156
156
  "description": "Unique view ID within the extension"
157
157
  },
158
158
  "title": {
159
- "type": "string",
159
+ "anyOf": [
160
+ {
161
+ "type": "string"
162
+ },
163
+ {
164
+ "type": "object",
165
+ "additionalProperties": {
166
+ "type": "string"
167
+ }
168
+ }
169
+ ],
160
170
  "description": "Display title"
161
171
  },
162
172
  "description": {
163
- "type": "string",
173
+ "anyOf": [
174
+ {
175
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/0"
176
+ },
177
+ {
178
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/1"
179
+ }
180
+ ],
164
181
  "description": "Help text"
165
182
  },
166
183
  "topic": {
@@ -362,7 +379,7 @@
362
379
  "labels": {
363
380
  "type": "object",
364
381
  "additionalProperties": {
365
- "type": "string"
382
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/description"
366
383
  },
367
384
  "description": "Human-friendly labels per group value (rendered as section headers)"
368
385
  }
@@ -470,7 +487,14 @@
470
487
  "description": "Unique panel ID within the extension"
471
488
  },
472
489
  "title": {
473
- "type": "string",
490
+ "anyOf": [
491
+ {
492
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/0"
493
+ },
494
+ {
495
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/1"
496
+ }
497
+ ],
474
498
  "description": "Display title"
475
499
  },
476
500
  "icon": {
@@ -581,7 +605,14 @@
581
605
  "description": "Unique card ID within the extension"
582
606
  },
583
607
  "title": {
584
- "type": "string",
608
+ "anyOf": [
609
+ {
610
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/0"
611
+ },
612
+ {
613
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/1"
614
+ }
615
+ ],
585
616
  "description": "What it is called where the user picks it"
586
617
  },
587
618
  "icon": {
@@ -704,13 +735,10 @@
704
735
  "name": {
705
736
  "anyOf": [
706
737
  {
707
- "type": "string"
738
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/0"
708
739
  },
709
740
  {
710
- "type": "object",
711
- "additionalProperties": {
712
- "type": "string"
713
- }
741
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/1"
714
742
  }
715
743
  ],
716
744
  "description": "Display name"
@@ -718,10 +746,10 @@
718
746
  "description": {
719
747
  "anyOf": [
720
748
  {
721
- "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/tools/items/properties/name/anyOf/0"
749
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/0"
722
750
  },
723
751
  {
724
- "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/tools/items/properties/name/anyOf/1"
752
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/title/anyOf/1"
725
753
  }
726
754
  ],
727
755
  "description": "Description for Stina"
@@ -736,14 +764,7 @@
736
764
  "description": "Whether this tool requires user confirmation before execution (default: true)"
737
765
  },
738
766
  "confirmationPrompt": {
739
- "anyOf": [
740
- {
741
- "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/tools/items/properties/name/anyOf/0"
742
- },
743
- {
744
- "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/tools/items/properties/name/anyOf/1"
745
- }
746
- ],
767
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/description",
747
768
  "description": "Custom confirmation prompt"
748
769
  }
749
770
  },
@@ -884,7 +905,7 @@
884
905
  "description": "Microsoft Graph delegated permissions"
885
906
  },
886
907
  "reason": {
887
- "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/tools/items/properties/confirmationPrompt",
908
+ "$ref": "#/definitions/ExtensionManifest/properties/contributes/properties/toolSettings/items/properties/description",
888
909
  "description": "Why the extension needs them"
889
910
  }
890
911
  },
@@ -28,6 +28,7 @@
28
28
  */
29
29
 
30
30
  import { z } from 'zod'
31
+ import { LocalizedStringSchema } from './localization.schema.js'
31
32
  import { ExtensionComponentStyleSchema } from './components.schema.js'
32
33
  import {
33
34
  WeatherConditionSchema,
@@ -111,7 +112,7 @@ const FrameCardSchema = z
111
112
  component: z.literal('Frame'),
112
113
  // Only the string form: the components form of a title is for panels that
113
114
  // put controls in their header, which a card has no business doing.
114
- title: z.string().optional(),
115
+ title: LocalizedStringSchema.optional(),
115
116
  collapsible: z.boolean().optional(),
116
117
  defaultExpanded: z.boolean().optional(),
117
118
  variant: FrameVariantSchema.optional(),
@@ -132,8 +133,8 @@ const HeaderCardSchema = z
132
133
  .object({
133
134
  component: z.literal('Header'),
134
135
  level: z.number().min(1).max(6),
135
- title: z.string(),
136
- description: z.union([z.string(), z.array(z.string())]).optional(),
136
+ title: LocalizedStringSchema,
137
+ description: z.union([LocalizedStringSchema, z.array(LocalizedStringSchema)]).optional(),
137
138
  icon: z.string().optional(),
138
139
  style,
139
140
  })
@@ -159,7 +160,7 @@ const IconCardSchema = z
159
160
  .object({
160
161
  component: z.literal('Icon'),
161
162
  name: z.string(),
162
- title: z.string().optional(),
163
+ title: LocalizedStringSchema.optional(),
163
164
  style,
164
165
  })
165
166
  .strict()
@@ -167,7 +168,7 @@ const IconCardSchema = z
167
168
  const PillCardSchema = z
168
169
  .object({
169
170
  component: z.literal('Pill'),
170
- text: z.string(),
171
+ text: LocalizedStringSchema,
171
172
  icon: z.string().optional(),
172
173
  variant: PillVariantSchema.optional(),
173
174
  style,
@@ -197,7 +198,7 @@ const WeatherNowCardSchema = z
197
198
  const WeatherForecastCardSchema = z
198
199
  .object({
199
200
  component: z.literal('WeatherForecast'),
200
- title: z.string().optional(),
201
+ title: LocalizedStringSchema.optional(),
201
202
  icon: z.string().optional(),
202
203
  unit: z.string().optional(),
203
204
  steps: z
@@ -237,7 +238,7 @@ const ChartCardSchema = z
237
238
  .min(1)
238
239
  .max(8),
239
240
  labels: z.array(z.string()).max(200).optional(),
240
- title: z.string().optional(),
241
+ title: LocalizedStringSchema.optional(),
241
242
  icon: z.string().optional(),
242
243
  unit: z.string().optional(),
243
244
  zeroBaseline: z.boolean().optional(),
@@ -249,10 +250,10 @@ const ChartCardSchema = z
249
250
  const StatTileCardSchema = z
250
251
  .object({
251
252
  component: z.literal('StatTile'),
252
- label: z.string(),
253
+ label: LocalizedStringSchema,
253
254
  value: z.union([z.string(), z.number()]),
254
255
  unit: z.string().optional(),
255
- caption: z.string().optional(),
256
+ caption: LocalizedStringSchema.optional(),
256
257
  icon: z.string().optional(),
257
258
  trend: StatTrendSchema.optional(),
258
259
  trendLabel: z.string().optional(),
@@ -264,7 +265,7 @@ const StatTileCardSchema = z
264
265
  const ProgressBarCardSchema = z
265
266
  .object({
266
267
  component: z.literal('ProgressBar'),
267
- label: z.string(),
268
+ label: LocalizedStringSchema,
268
269
  value: z.number(),
269
270
  min: z.number().optional(),
270
271
  max: z.number().optional(),
@@ -272,7 +273,7 @@ const ProgressBarCardSchema = z
272
273
  color: ProgressColorSchema.optional(),
273
274
  unit: z.string().optional(),
274
275
  valueLabel: z.string().optional(),
275
- caption: z.string().optional(),
276
+ caption: LocalizedStringSchema.optional(),
276
277
  icon: z.string().optional(),
277
278
  style,
278
279
  })
@@ -296,7 +297,7 @@ const KeyValueListCardSchema = z
296
297
  const TimelineCardSchema = z
297
298
  .object({
298
299
  component: z.literal('Timeline'),
299
- title: z.string().optional(),
300
+ title: LocalizedStringSchema.optional(),
300
301
  icon: z.string().optional(),
301
302
  entries: z
302
303
  .array(
@@ -323,7 +324,7 @@ const TimelineCardSchema = z
323
324
  const NoteCardSchema = z
324
325
  .object({
325
326
  component: z.literal('Note'),
326
- title: z.string().optional(),
327
+ title: LocalizedStringSchema.optional(),
327
328
  icon: z.string().optional(),
328
329
  badge: z.string().optional(),
329
330
  content: z.string(),
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { z } from 'zod'
8
+ import { LocalizedStringSchema } from './localization.schema.js'
8
9
 
9
10
  // =============================================================================
10
11
  // CSS Properties
@@ -180,8 +181,8 @@ export const HeaderPropsSchema = z
180
181
  .object({
181
182
  component: z.literal('Header'),
182
183
  level: z.number().min(1).max(6).describe('Heading level (1-6)'),
183
- title: z.string().describe('Header title'),
184
- description: z.union([z.string(), z.array(z.string())]).optional().describe('Description text'),
184
+ title: LocalizedStringSchema.describe('Header title'),
185
+ description: z.union([LocalizedStringSchema, z.array(LocalizedStringSchema)]).optional().describe('Description text'),
185
186
  icon: z.string().optional().describe('Icon name'),
186
187
  style: ExtensionComponentStyleSchema.optional(),
187
188
  })
@@ -191,7 +192,7 @@ export const HeaderPropsSchema = z
191
192
  export const LabelPropsSchema = z
192
193
  .object({
193
194
  component: z.literal('Label'),
194
- text: z.string().describe('Label text'),
195
+ text: LocalizedStringSchema.describe('Label text'),
195
196
  style: ExtensionComponentStyleSchema.optional(),
196
197
  })
197
198
  .passthrough()
@@ -208,7 +209,7 @@ export const ClockPropsSchema = z
208
209
  export const ParagraphPropsSchema = z
209
210
  .object({
210
211
  component: z.literal('Paragraph'),
211
- text: z.string().describe('Paragraph text'),
212
+ text: LocalizedStringSchema.describe('Paragraph text'),
212
213
  style: ExtensionComponentStyleSchema.optional(),
213
214
  })
214
215
  .passthrough()
@@ -217,9 +218,9 @@ export const ParagraphPropsSchema = z
217
218
  export const ButtonPropsSchema = z
218
219
  .object({
219
220
  component: z.literal('Button'),
220
- text: z.string().describe('Button text'),
221
+ text: LocalizedStringSchema.describe('Button text'),
221
222
  type: z.enum(['normal', 'primary', 'danger', 'accent']).optional().describe('Visual style'),
222
- title: z.string().optional().describe('Tooltip shown on hover'),
223
+ title: LocalizedStringSchema.optional().describe('Tooltip shown on hover'),
223
224
  disabled: z.boolean().optional().describe('Disable the button'),
224
225
  onClickAction: ExtensionActionRefSchema.describe('Action to call on click'),
225
226
  style: ExtensionComponentStyleSchema.optional(),
@@ -230,8 +231,8 @@ export const ButtonPropsSchema = z
230
231
  export const TextInputPropsSchema = z
231
232
  .object({
232
233
  component: z.literal('TextInput'),
233
- label: z.string().describe('Input label'),
234
- placeholder: z.string().optional().describe('Placeholder text'),
234
+ label: LocalizedStringSchema.describe('Input label'),
235
+ placeholder: LocalizedStringSchema.optional().describe('Placeholder text'),
235
236
  value: z.string().optional().describe('Current value'),
236
237
  onChangeAction: ExtensionActionRefSchema.optional().describe('Action to call on change'),
237
238
  style: ExtensionComponentStyleSchema.optional(),
@@ -242,8 +243,8 @@ export const TextInputPropsSchema = z
242
243
  export const PasswordInputPropsSchema = z
243
244
  .object({
244
245
  component: z.literal('PasswordInput'),
245
- label: z.string().describe('Input label'),
246
- placeholder: z.string().optional().describe('Placeholder text'),
246
+ label: LocalizedStringSchema.describe('Input label'),
247
+ placeholder: LocalizedStringSchema.optional().describe('Placeholder text'),
247
248
  value: z.string().optional().describe('Current value'),
248
249
  onChangeAction: ExtensionActionRefSchema.optional().describe('Action to call on change'),
249
250
  style: ExtensionComponentStyleSchema.optional(),
@@ -254,8 +255,8 @@ export const PasswordInputPropsSchema = z
254
255
  export const NumberInputPropsSchema = z
255
256
  .object({
256
257
  component: z.literal('NumberInput'),
257
- label: z.string().describe('Input label'),
258
- placeholder: z.string().optional().describe('Placeholder text'),
258
+ label: LocalizedStringSchema.describe('Input label'),
259
+ placeholder: LocalizedStringSchema.optional().describe('Placeholder text'),
259
260
  value: z.union([z.string(), z.number()]).optional().describe('Current value'),
260
261
  min: z.number().optional().describe('Minimum value'),
261
262
  max: z.number().optional().describe('Maximum value'),
@@ -269,8 +270,8 @@ export const NumberInputPropsSchema = z
269
270
  export const TextAreaPropsSchema = z
270
271
  .object({
271
272
  component: z.literal('TextArea'),
272
- label: z.string().describe('Input label'),
273
- placeholder: z.string().optional().describe('Placeholder text'),
273
+ label: LocalizedStringSchema.describe('Input label'),
274
+ placeholder: LocalizedStringSchema.optional().describe('Placeholder text'),
274
275
  value: z.string().optional().describe('Current value'),
275
276
  rows: z.number().int().positive().optional().describe('Number of visible text rows'),
276
277
  onChangeAction: ExtensionActionRefSchema.optional().describe('Action to call on change'),
@@ -282,7 +283,7 @@ export const TextAreaPropsSchema = z
282
283
  export const DateTimeInputPropsSchema = z
283
284
  .object({
284
285
  component: z.literal('DateTimeInput'),
285
- label: z.string().describe('Input label'),
286
+ label: LocalizedStringSchema.describe('Input label'),
286
287
  value: z.string().optional().describe('Current value'),
287
288
  onChangeAction: ExtensionActionRefSchema.optional().describe('Action to call on change'),
288
289
  style: ExtensionComponentStyleSchema.optional(),
@@ -293,8 +294,8 @@ export const DateTimeInputPropsSchema = z
293
294
  export const SelectPropsSchema = z
294
295
  .object({
295
296
  component: z.literal('Select'),
296
- label: z.string().describe('Select label'),
297
- options: z.array(z.object({ label: z.string(), value: z.string() })).describe('Available options'),
297
+ label: LocalizedStringSchema.describe('Select label'),
298
+ options: z.array(z.object({ label: LocalizedStringSchema, value: z.string() })).describe('Available options'),
298
299
  selectedValue: z.string().optional().describe('Currently selected value'),
299
300
  onChangeAction: ExtensionActionRefSchema.optional().describe('Action to call on change'),
300
301
  style: ExtensionComponentStyleSchema.optional(),
@@ -305,7 +306,7 @@ export const SelectPropsSchema = z
305
306
  export const IconPickerPropsSchema = z
306
307
  .object({
307
308
  component: z.literal('IconPicker'),
308
- label: z.string().optional().describe('Picker label'),
309
+ label: LocalizedStringSchema.optional().describe('Picker label'),
309
310
  value: z.string().optional().describe('Currently selected icon name'),
310
311
  onChangeAction: ExtensionActionRefSchema.optional().describe('Action to call on change'),
311
312
  style: ExtensionComponentStyleSchema.optional(),
@@ -356,7 +357,7 @@ export const IconPropsSchema = z
356
357
  .object({
357
358
  component: z.literal('Icon'),
358
359
  name: z.string().describe('Icon name'),
359
- title: z.string().optional().describe('Icon title'),
360
+ title: LocalizedStringSchema.optional().describe('Icon title'),
360
361
  style: ExtensionComponentStyleSchema.optional(),
361
362
  })
362
363
  .passthrough()
@@ -370,7 +371,7 @@ export const IconButtonPropsSchema = z
370
371
  .object({
371
372
  component: z.literal('IconButton'),
372
373
  icon: z.string().describe('Icon name'),
373
- tooltip: z.string().describe('Tooltip text'),
374
+ tooltip: LocalizedStringSchema.describe('Tooltip text'),
374
375
  active: z.boolean().optional().describe('Whether the button is active'),
375
376
  disabled: z.boolean().optional().describe('Whether the button is disabled'),
376
377
  type: IconButtonTypeSchema.optional().describe('Button style type'),
@@ -383,7 +384,7 @@ export const IconButtonPropsSchema = z
383
384
  export const PanelActionSchema = z
384
385
  .object({
385
386
  icon: z.string().describe('Icon name'),
386
- tooltip: z.string().describe('Tooltip text'),
387
+ tooltip: LocalizedStringSchema.describe('Tooltip text'),
387
388
  action: ExtensionActionRefSchema.describe('Action to call'),
388
389
  type: IconButtonTypeSchema.optional().describe('Button style type'),
389
390
  })
@@ -392,8 +393,8 @@ export const PanelActionSchema = z
392
393
  export const PanelPropsSchema = z
393
394
  .object({
394
395
  component: z.literal('Panel'),
395
- title: z.string().describe('Panel title'),
396
- description: z.union([z.string(), z.array(z.string())]).optional().describe('Description text'),
396
+ title: LocalizedStringSchema.describe('Panel title'),
397
+ description: z.union([LocalizedStringSchema, z.array(LocalizedStringSchema)]).optional().describe('Description text'),
397
398
  icon: z.string().optional().describe('Icon name'),
398
399
  actions: z.array(PanelActionSchema).optional().describe('Action buttons'),
399
400
  content: ExtensionComponentDataSchema.optional().describe('Panel content'),
@@ -405,8 +406,8 @@ export const PanelPropsSchema = z
405
406
  export const TogglePropsSchema = z
406
407
  .object({
407
408
  component: z.literal('Toggle'),
408
- label: z.string().optional().describe('Toggle label'),
409
- description: z.string().optional().describe('Description text'),
409
+ label: LocalizedStringSchema.optional().describe('Toggle label'),
410
+ description: LocalizedStringSchema.optional().describe('Description text'),
410
411
  checked: z.boolean().optional().describe('Whether the toggle is checked'),
411
412
  disabled: z.boolean().optional().describe('Whether the toggle is disabled'),
412
413
  onChangeAction: ExtensionActionRefSchema.optional().describe('Action to call on change'),
@@ -418,8 +419,8 @@ export const TogglePropsSchema = z
418
419
  export const CollapsiblePropsSchema = z
419
420
  .object({
420
421
  component: z.literal('Collapsible'),
421
- title: z.string().describe('Title displayed in the header'),
422
- description: z.union([z.string(), z.array(z.string())]).optional().describe('Description text'),
422
+ title: LocalizedStringSchema.describe('Title displayed in the header'),
423
+ description: z.union([LocalizedStringSchema, z.array(LocalizedStringSchema)]).optional().describe('Description text'),
423
424
  icon: z.string().optional().describe('Icon name'),
424
425
  defaultExpanded: z.boolean().optional().describe('Whether expanded by default'),
425
426
  content: ExtensionComponentDataSchema.optional().describe('Content when expanded'),
@@ -435,7 +436,7 @@ export const PillVariantSchema = z
435
436
  export const PillPropsSchema = z
436
437
  .object({
437
438
  component: z.literal('Pill'),
438
- text: z.string().describe('Pill text'),
439
+ text: LocalizedStringSchema.describe('Pill text'),
439
440
  icon: z.string().optional().describe('Icon name'),
440
441
  variant: PillVariantSchema.optional().describe('Color variant'),
441
442
  style: ExtensionComponentStyleSchema.optional(),
@@ -446,7 +447,7 @@ export const PillPropsSchema = z
446
447
  export const CheckboxPropsSchema = z
447
448
  .object({
448
449
  component: z.literal('Checkbox'),
449
- label: z.string().describe('Checkbox label'),
450
+ label: LocalizedStringSchema.describe('Checkbox label'),
450
451
  checked: z.boolean().optional().describe('Whether the checkbox is checked'),
451
452
  disabled: z.boolean().optional().describe('Whether the checkbox is disabled'),
452
453
  strikethrough: z.boolean().optional().describe('Strike through label when checked'),
@@ -459,7 +460,7 @@ export const CheckboxPropsSchema = z
459
460
  export const MarkdownPropsSchema = z
460
461
  .object({
461
462
  component: z.literal('Markdown'),
462
- content: z.string().describe('Markdown content'),
463
+ content: LocalizedStringSchema.describe('Markdown content'),
463
464
  style: ExtensionComponentStyleSchema.optional(),
464
465
  })
465
466
  .passthrough()
@@ -478,7 +479,7 @@ export const TextPreviewPropsSchema = z
478
479
  export const ModalPropsSchema = z
479
480
  .object({
480
481
  component: z.literal('Modal'),
481
- title: z.string().describe('Modal title'),
482
+ title: LocalizedStringSchema.describe('Modal title'),
482
483
  open: z.boolean().optional().describe('Whether the modal is open'),
483
484
  maxWidth: z.string().optional().describe('Max width of the modal'),
484
485
  body: ExtensionComponentDataSchema.optional().describe('Modal body content'),
@@ -506,7 +507,7 @@ export const FrameVariantSchema = z
506
507
  export const FramePropsSchema = z
507
508
  .object({
508
509
  component: z.literal('Frame'),
509
- title: z.union([z.string(), ExtensionComponentChildrenSchema]).optional().describe('Optional title (string or components)'),
510
+ title: z.union([LocalizedStringSchema, ExtensionComponentChildrenSchema]).optional().describe('Optional title (string or components)'),
510
511
  icon: z.string().optional().describe('Icon name'),
511
512
  collapsible: z.boolean().optional().describe('Whether content can be toggled'),
512
513
  defaultExpanded: z.boolean().optional().describe('Whether expanded by default'),
@@ -598,7 +599,7 @@ export const WeatherForecastStepSchema = z
598
599
  export const WeatherForecastPropsSchema = z
599
600
  .object({
600
601
  component: z.literal('WeatherForecast'),
601
- title: z.string().optional().describe('Heading above the row'),
602
+ title: LocalizedStringSchema.optional().describe('Heading above the row'),
602
603
  icon: z.string().optional().describe('Icon shown to the left of the title'),
603
604
  unit: z.string().optional().describe('Written after every temperature. Defaults to °'),
604
605
  steps: z.array(WeatherForecastStepSchema).min(1).describe('Steps, hourly or daily'),
@@ -631,7 +632,7 @@ export const ChartPropsSchema = z
631
632
  chart: ChartKindSchema.optional().describe('Defaults to line'),
632
633
  series: z.array(ChartSeriesSchema).min(1).max(8).describe('At most eight series'),
633
634
  labels: z.array(z.string()).optional().describe('One per point, along the horizontal axis'),
634
- title: z.string().optional().describe('Heading above the plot'),
635
+ title: LocalizedStringSchema.optional().describe('Heading above the plot'),
635
636
  icon: z.string().optional().describe('Icon shown to the left of the title'),
636
637
  unit: z.string().optional().describe('Written after every value'),
637
638
  zeroBaseline: z.boolean().optional().describe('Force the value axis to include zero'),
@@ -646,10 +647,10 @@ export const StatTrendSchema = z.enum(['up', 'down', 'flat']).describe('Directio
646
647
  export const StatTilePropsSchema = z
647
648
  .object({
648
649
  component: z.literal('StatTile'),
649
- label: z.string().describe('What the number is'),
650
+ label: LocalizedStringSchema.describe('What the number is'),
650
651
  value: z.union([z.string(), z.number()]).describe('The number itself'),
651
652
  unit: z.string().optional().describe('Written after the value in smaller type'),
652
- caption: z.string().optional().describe('One quiet line under the number'),
653
+ caption: LocalizedStringSchema.optional().describe('One quiet line under the number'),
653
654
  icon: z.string().optional().describe('Icon name'),
654
655
  trend: StatTrendSchema.optional(),
655
656
  trendLabel: z.string().optional().describe('The change in words'),
@@ -670,7 +671,7 @@ export const ProgressColorSchema = z
670
671
  export const ProgressBarPropsSchema = z
671
672
  .object({
672
673
  component: z.literal('ProgressBar'),
673
- label: z.string().describe('What is being measured'),
674
+ label: LocalizedStringSchema.describe('What is being measured'),
674
675
  value: z.number().describe('Where the reading sits. Clamped to the range'),
675
676
  min: z.number().optional().describe('Bottom of the range. Defaults to 0'),
676
677
  max: z.number().optional().describe('Top of the range. Defaults to 100'),
@@ -678,7 +679,7 @@ export const ProgressBarPropsSchema = z
678
679
  color: ProgressColorSchema.optional().describe('Defaults to accent'),
679
680
  unit: z.string().optional().describe('Written after the value'),
680
681
  valueLabel: z.string().optional().describe('The readout in words, replacing value and unit'),
681
- caption: z.string().optional().describe('One quiet line under the reading'),
682
+ caption: LocalizedStringSchema.optional().describe('One quiet line under the reading'),
682
683
  icon: z.string().optional().describe('Icon name'),
683
684
  style: ExtensionComponentStyleSchema.optional(),
684
685
  })
@@ -725,7 +726,7 @@ export const TimelineEntrySchema = z
725
726
  export const TimelinePropsSchema = z
726
727
  .object({
727
728
  component: z.literal('Timeline'),
728
- title: z.string().optional().describe('Heading above the rail'),
729
+ title: LocalizedStringSchema.optional().describe('Heading above the rail'),
729
730
  icon: z.string().optional().describe('Icon shown to the left of the title'),
730
731
  entries: z.array(TimelineEntrySchema).min(1).describe('Entries, in the order they happen'),
731
732
  style: ExtensionComponentStyleSchema.optional(),
@@ -740,7 +741,7 @@ export const NoteVariantSchema = z
740
741
  export const NotePropsSchema = z
741
742
  .object({
742
743
  component: z.literal('Note'),
743
- title: z.string().optional(),
744
+ title: LocalizedStringSchema.optional(),
744
745
  icon: z.string().optional().describe('Icon shown to the left of the title'),
745
746
  badge: z.string().optional().describe('Trailing badge next to the title'),
746
747
  content: z.string().describe('The body, as markdown'),
@@ -798,7 +799,7 @@ export const AgendaDaySchema = z
798
799
  export const AgendaPropsSchema = z
799
800
  .object({
800
801
  component: z.literal('Agenda'),
801
- title: z.string().optional(),
802
+ title: LocalizedStringSchema.optional(),
802
803
  icon: z.string().optional().describe('Icon shown to the left of the title'),
803
804
  days: z.array(AgendaDaySchema),
804
805
  warnOverlaps: z.boolean().optional().describe('Word clashes between events'),
@@ -6,17 +6,10 @@
6
6
 
7
7
  import { z } from 'zod'
8
8
  import { ExtensionComponentDataSchema } from './components.schema.js'
9
+ import { LocalizedStringSchema } from './localization.schema.js'
9
10
 
10
- // =============================================================================
11
- // Localization
12
- // =============================================================================
11
+ export { LocalizedStringSchema }
13
12
 
14
- /**
15
- * Localized string - either a simple string or a map of language codes to strings
16
- */
17
- export const LocalizedStringSchema = z
18
- .union([z.string(), z.record(z.string())])
19
- .describe('String or localized string map')
20
13
 
21
14
  // =============================================================================
22
15
  // Tool Settings Views
@@ -58,7 +51,7 @@ export const ToolSettingsListGroupBySchema = z
58
51
  .optional()
59
52
  .describe('Explicit ordering of group values; unlisted groups appear afterwards alphabetically'),
60
53
  labels: z
61
- .record(z.string())
54
+ .record(LocalizedStringSchema)
62
55
  .optional()
63
56
  .describe('Human-friendly labels per group value (rendered as section headers)'),
64
57
  })
@@ -115,8 +108,8 @@ export const ToolSettingsViewSchema = z
115
108
  export const ToolSettingsViewDefinitionSchema = z
116
109
  .object({
117
110
  id: z.string().describe('Unique view ID within the extension'),
118
- title: z.string().describe('Display title'),
119
- description: z.string().optional().describe('Help text'),
111
+ title: LocalizedStringSchema.describe('Display title'),
112
+ description: LocalizedStringSchema.optional().describe('Help text'),
120
113
  // A string rather than the known topics: one this host does not know yet must not stop
121
114
  // the extension installing, it only lands on the extension's own page.
122
115
  topic: z
@@ -178,7 +171,7 @@ export const PanelViewSchema = z
178
171
  export const PanelDefinitionSchema = z
179
172
  .object({
180
173
  id: z.string().describe('Unique panel ID within the extension'),
181
- title: z.string().describe('Display title'),
174
+ title: LocalizedStringSchema.describe('Display title'),
182
175
  icon: z.string().optional().describe('Icon name (from huge-icons)'),
183
176
  view: PanelViewSchema.describe('Panel view schema'),
184
177
  })
@@ -196,7 +189,7 @@ export const PanelDefinitionSchema = z
196
189
  export const StatusCardDefinitionSchema = z
197
190
  .object({
198
191
  id: z.string().describe('Unique card ID within the extension'),
199
- title: z.string().describe('What it is called where the user picks it'),
192
+ title: LocalizedStringSchema.describe('What it is called where the user picks it'),
200
193
  icon: z.string().optional().describe('Icon name (from huge-icons)'),
201
194
  size: z
202
195
  .enum(['line', 'block'])
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Localization Schema
3
+ *
4
+ * Kept apart so both the component and the contribution schemas can use it without importing
5
+ * each other.
6
+ */
7
+
8
+ import { z } from 'zod'
9
+
10
+ /**
11
+ * Localized string - either a simple string or a map of language codes to strings
12
+ */
13
+ export const LocalizedStringSchema = z
14
+ .union([z.string(), z.record(z.string())])
15
+ .describe('String or localized string map')