@comet/agent-features 9.0.0-canary-20260527154746

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 (35) hide show
  1. package/LICENSE +24 -0
  2. package/package.json +19 -0
  3. package/rules/coding-guidelines/api-nestjs.instructions.md +107 -0
  4. package/rules/coding-guidelines/cdn.instructions.md +24 -0
  5. package/rules/coding-guidelines/general.instructions.md +30 -0
  6. package/rules/coding-guidelines/git.instructions.md +37 -0
  7. package/rules/coding-guidelines/kubernetes.instructions.md +59 -0
  8. package/rules/coding-guidelines/libraries.instructions.md +34 -0
  9. package/rules/coding-guidelines/naming.instructions.md +39 -0
  10. package/rules/coding-guidelines/postgresql.instructions.md +40 -0
  11. package/rules/coding-guidelines/react.instructions.md +102 -0
  12. package/rules/coding-guidelines/security.instructions.md +44 -0
  13. package/rules/coding-guidelines/styling.instructions.md +50 -0
  14. package/rules/coding-guidelines/typescript.instructions.md +50 -0
  15. package/skills/.gitkeep +0 -0
  16. package/skills/comet-block/SKILL.md +246 -0
  17. package/skills/comet-block/references/admin-patterns.md +192 -0
  18. package/skills/comet-block/references/api-patterns.md +183 -0
  19. package/skills/comet-block/references/block-loader.md +368 -0
  20. package/skills/comet-block/references/block-types.md +210 -0
  21. package/skills/comet-block/references/custom-block-field.md +266 -0
  22. package/skills/comet-block/references/fixtures.md +436 -0
  23. package/skills/comet-block/references/image.md +341 -0
  24. package/skills/comet-block/references/migration.md +597 -0
  25. package/skills/comet-block/references/registration.md +167 -0
  26. package/skills/comet-block/references/response-summary.md +102 -0
  27. package/skills/comet-block/references/rich-text.md +309 -0
  28. package/skills/comet-block/references/select.md +176 -0
  29. package/skills/comet-block/references/site-patterns.md +202 -0
  30. package/skills/comet-mail-react/SKILL.md +539 -0
  31. package/skills/comet-mail-react/references/components-and-theme.md +395 -0
  32. package/skills/comet-mail-react/references/layout-patterns.md +315 -0
  33. package/skills/comet-mail-react/references/styling-and-customization.md +306 -0
  34. package/skills/comet-minor-update/SKILL.md +191 -0
  35. package/skills/dev-pm/SKILL.md +100 -0
@@ -0,0 +1,341 @@
1
+ # Image Block Selection Rules
2
+
3
+ Detailed rules for choosing and using the correct image block in Comet. Load this file when a block contains an image or media property.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ Comet provides three built-in image blocks (`DamImageBlock`, `PixelImageBlock`, `SvgImageBlock`) and a project-specific `MediaBlock` pattern. Each block accepts different file types and has different capabilities. Selecting the wrong block leads to editors being unable to upload the file type they need, or missing features like cropping and optimization.
10
+
11
+ ---
12
+
13
+ ## Decision Flowchart
14
+
15
+ Work through these questions in order. Stop at the first "Yes".
16
+
17
+ | # | Question | Block |
18
+ | --- | -------------------------------------------------------------------------------------- | -------------------------------- |
19
+ | 1 | Does the field need to support both images **and video**? | `MediaBlock` (project-specific) |
20
+ | 2 | Does the field accept **only SVGs** (icons, logos, decorative vector graphics)? | `SvgImageBlock` |
21
+ | 3 | Does the field need to **exclude SVGs** (raster only, with cropping and optimization)? | `PixelImageBlock` |
22
+ | 4 | Does the field accept **any image type** (raster + SVG)? | `DamImageBlock` |
23
+ | 5 | Unsure or no specific requirement? | `DamImageBlock` (safest default) |
24
+
25
+ ---
26
+
27
+ ## Block Comparison
28
+
29
+ | Block | Raster (JPEG, PNG, WebP, ...) | SVG | Video | Cropping / Optimization | Source |
30
+ | ----------------- | ----------------------------- | --- | ----- | ----------------------- | ------------------------------------------------------------ |
31
+ | `DamImageBlock` | Yes | Yes | No | Yes (pixel images only) | `@comet/cms-api` / `@comet/cms-admin` |
32
+ | `PixelImageBlock` | Yes | No | No | Yes | `@comet/cms-api` / `@comet/cms-admin` / `@comet/site-nextjs` |
33
+ | `SvgImageBlock` | No | Yes | No | No (not needed) | `@comet/cms-api` / `@comet/cms-admin` / `@comet/site-nextjs` |
34
+ | `MediaBlock` | Yes | Yes | Yes | Yes (pixel images only) | Project-specific (not in Comet core) |
35
+
36
+ ---
37
+
38
+ ## DamImageBlock
39
+
40
+ A **one-of block** that wraps both `PixelImageBlock` and `SvgImageBlock`. It automatically detects the uploaded file type and delegates to the appropriate sub-block.
41
+
42
+ **Accepted file types:** All image types -- pixel images (JPEG, PNG, WebP, GIF, etc.) and SVG.
43
+
44
+ **When to use:** Default choice for most image fields. Use when editors should be able to upload any image type without restriction. Appropriate for general-purpose fields like "teaser image", "hero image", or "content image".
45
+
46
+ ### Imports
47
+
48
+ | Layer | Import |
49
+ | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
50
+ | API | `import { DamImageBlock } from "@comet/cms-api";` |
51
+ | Admin | `import { DamImageBlock } from "@comet/cms-admin";` |
52
+ | Site | **Project-specific wrapper** -- not exported from `@comet/site-nextjs`. Each project creates its own component, typically at `site/src/common/blocks/DamImageBlock.tsx`. |
53
+
54
+ ### Site Implementation
55
+
56
+ Because `DamImageBlock` is a one-of block, the site component must handle both pixel and SVG sub-types. Check whether the project already has a `DamImageBlock` in `site/src/common/blocks/` before creating one.
57
+
58
+ Typical pattern:
59
+
60
+ ```tsx
61
+ // site/src/common/blocks/DamImageBlock.tsx
62
+ "use client";
63
+ import { PixelImageBlock, PreviewSkeleton, type PropsWithData, SvgImageBlock, withPreview } from "@comet/site-nextjs";
64
+ import { type DamImageBlockData, type PixelImageBlockData, type SvgImageBlockData } from "@src/blocks.generated";
65
+ import { type ImageProps as NextImageProps } from "next/image";
66
+
67
+ type DamImageProps = Omit<NextImageProps, "src" | "width" | "height" | "alt"> & {
68
+ aspectRatio: string | "inherit";
69
+ };
70
+
71
+ export const DamImageBlock = withPreview(
72
+ ({ data: { block }, aspectRatio, ...imageProps }: PropsWithData<DamImageBlockData> & DamImageProps) => {
73
+ if (!block) {
74
+ return <PreviewSkeleton type="media" hasContent={false} />;
75
+ }
76
+
77
+ if (block.type === "pixelImage") {
78
+ return <PixelImageBlock data={block.props as PixelImageBlockData} aspectRatio={aspectRatio} {...imageProps} />;
79
+ } else if (block.type === "svgImage") {
80
+ return <SvgImageBlock data={block.props as SvgImageBlockData} />;
81
+ } else {
82
+ return (
83
+ <>
84
+ Unknown block type: <strong>{block.type}</strong>
85
+ </>
86
+ );
87
+ }
88
+ },
89
+ { label: "Image" },
90
+ );
91
+ ```
92
+
93
+ ### Site Props
94
+
95
+ | Prop | Type | Description |
96
+ | ------------- | --------------------- | -------------------------------------------------------------------------------------------------- |
97
+ | `aspectRatio` | `string \| "inherit"` | Aspect ratio for pixel images (e.g., `"16x9"`, `"4x3"`, `"1x1"`, `"inherit"`). Ignored for SVGs. |
98
+ | `sizes` | `string` | Responsive sizes attribute for pixel images (e.g., `"100vw"`, `"(max-width: 768px) 100vw, 50vw"`). |
99
+ | `fill` | `boolean` | When `true`, the image fills its container (Next.js Image `fill` mode). |
100
+
101
+ ### Allowed aspect ratios
102
+
103
+ Allowed values for `aspectRatio` (for pixel/DAM images) are **not arbitrary**. They are defined in the API config:
104
+
105
+ - **Config location:** `api/src/comet-config.json` (or project equivalent) under `dam.allowedImageAspectRatios`.
106
+
107
+ When creating or editing a block that uses `DamImageBlock` or `PixelImageBlock` with a specific aspect ratio:
108
+
109
+ 1. If the user requests an aspect ratio (e.g. "21/9", "21x9"), check whether it exists in the project's `allowedImageAspectRatios`.
110
+ 2. If it **is** in the list, use it (with the same format as in the config, e.g. `"16x9"`).
111
+ 3. If it **is not** in the list, either:
112
+ - Use the **closest existing value** (e.g. for 21/9 use `"2x1"` if that is allowed), or
113
+ - **Clarify with the user:** use one of the existing ratios or add the new ratio to the API config.
114
+
115
+ Do not use an aspect ratio string that is not in `allowedImageAspectRatios`; the API/cropping pipeline will not support it.
116
+
117
+ ### Usage Pattern
118
+
119
+ ```ts
120
+ // API
121
+ @ChildBlock(DamImageBlock)
122
+ image: BlockDataInterface;
123
+
124
+ // Admin
125
+ image: {
126
+ block: DamImageBlock,
127
+ title: <FormattedMessage id="myBlock.image" defaultMessage="Image" />,
128
+ },
129
+
130
+ // Site
131
+ <DamImageBlock data={image} aspectRatio="16x9" sizes="100vw" />
132
+ ```
133
+
134
+ ---
135
+
136
+ ## PixelImageBlock
137
+
138
+ Handles **raster/pixel-based images only**. Supports image optimization via ImgProxy, focal-point-aware cropping, dominant color placeholders, and responsive image generation.
139
+
140
+ **Accepted file types:** All `image/*` MIME types **except** `image/svg+xml` (JPEG, PNG, WebP, GIF, BMP, TIFF, etc.).
141
+
142
+ **When to use:** When the image field must exclude SVGs and only accept raster images. Common for fields where cropping and optimization are essential, such as hero backgrounds, card thumbnails, or profile photos. In practice, most projects prefer `DamImageBlock` over using `PixelImageBlock` directly, since `DamImageBlock` includes pixel support and also handles SVGs.
143
+
144
+ ### Imports
145
+
146
+ | Layer | Import |
147
+ | ----- | ------------------------------------------------------- |
148
+ | API | `import { PixelImageBlock } from "@comet/cms-api";` |
149
+ | Admin | `import { PixelImageBlock } from "@comet/cms-admin";` |
150
+ | Site | `import { PixelImageBlock } from "@comet/site-nextjs";` |
151
+
152
+ ### Key Features
153
+
154
+ - Automatic image optimization via ImgProxy
155
+ - Crop area with focal point (SMART, CENTER, etc.)
156
+ - Dominant color placeholder during loading
157
+ - Responsive image generation via Next.js Image
158
+ - SEO metadata (alt text, title) from DAM file
159
+
160
+ ### Site Props
161
+
162
+ | Prop | Type | Required | Description |
163
+ | ------------- | --------------------- | -------- | ------------------------------------------------------------------------- |
164
+ | `aspectRatio` | `string \| "inherit"` | Yes | Aspect ratio (e.g., `"16x9"`) or `"inherit"` for the natural image ratio. |
165
+ | `sizes` | `string` | No | Responsive sizes attribute. |
166
+ | `fill` | `boolean` | No | Fill mode for Next.js Image (image fills its container). |
167
+
168
+ ### Usage Pattern
169
+
170
+ ```ts
171
+ // API
172
+ @ChildBlock(PixelImageBlock)
173
+ photo: BlockDataInterface;
174
+
175
+ // Admin
176
+ photo: {
177
+ block: PixelImageBlock,
178
+ title: <FormattedMessage id="myBlock.photo" defaultMessage="Photo" />,
179
+ },
180
+
181
+ // Site
182
+ <PixelImageBlock data={photo} aspectRatio="4x3" />
183
+ ```
184
+
185
+ ---
186
+
187
+ ## SvgImageBlock
188
+
189
+ Handles **SVG images only**. Renders the SVG directly via an `<img>` tag without image optimization (SVGs are already resolution-independent).
190
+
191
+ **Accepted file types:** `image/svg+xml` only.
192
+
193
+ **When to use:** When the field should only accept SVG files. Ideal for icons, logos, decorative graphics, and other vector content where raster images are not appropriate. Common in blocks like key-facts items where each entry has a small icon.
194
+
195
+ ### Imports
196
+
197
+ | Layer | Import |
198
+ | ----- | ----------------------------------------------------- |
199
+ | API | `import { SvgImageBlock } from "@comet/cms-api";` |
200
+ | Admin | `import { SvgImageBlock } from "@comet/cms-admin";` |
201
+ | Site | `import { SvgImageBlock } from "@comet/site-nextjs";` |
202
+
203
+ ### Site Props
204
+
205
+ | Prop | Type | Default | Description |
206
+ | -------- | ---------------------------- | -------- | --------------------------- |
207
+ | `width` | `string \| number \| "auto"` | `"100%"` | Width of the rendered SVG. |
208
+ | `height` | `string \| number \| "auto"` | `"auto"` | Height of the rendered SVG. |
209
+
210
+ ### Empty State Check
211
+
212
+ In the site layer, check `damFile` before rendering to avoid showing a broken image when no SVG is uploaded:
213
+
214
+ ```tsx
215
+ {
216
+ icon.damFile && <SvgImageBlock data={icon} width={48} height={48} />;
217
+ }
218
+ ```
219
+
220
+ ### Usage Pattern
221
+
222
+ ```ts
223
+ // API
224
+ @ChildBlock(SvgImageBlock)
225
+ icon: BlockDataInterface;
226
+
227
+ // Admin
228
+ icon: {
229
+ block: SvgImageBlock,
230
+ title: <FormattedMessage id="myBlock.icon" defaultMessage="Icon" />,
231
+ },
232
+
233
+ // Site
234
+ {icon.damFile && <SvgImageBlock data={icon} width={48} height={48} />}
235
+ ```
236
+
237
+ ---
238
+
239
+ ## MediaBlock (Project-Specific)
240
+
241
+ A **one-of block** that typically combines `DamImageBlock` with one or more video blocks (`DamVideoBlock`, `YouTubeVideoBlock`, `VimeoVideoBlock`). **Not part of Comet core** -- each project defines its own `MediaBlock`.
242
+
243
+ **Accepted file types:** Depends on the wrapped blocks. Typically includes all image types (via `DamImageBlock`) plus video.
244
+
245
+ **When to use:** When the content field should accept **both images and video**. Common for hero/stage areas, teaser media, and any visual content area where editors should choose between an image or a video.
246
+
247
+ ### Discovery
248
+
249
+ Before using `MediaBlock`, check whether the project defines one:
250
+
251
+ 1. Look for `MediaBlock` in `api/src/common/blocks/media.block.ts`
252
+ 2. Look for `MediaBlock` in `admin/src/common/blocks/MediaBlock.tsx`
253
+ 3. Look for `MediaBlock` in `site/src/common/blocks/MediaBlock.tsx`
254
+
255
+ If it does not exist and the block needs image + video support, create one following the one-of block pattern.
256
+
257
+ ### Typical Implementation
258
+
259
+ **API:**
260
+
261
+ ```ts
262
+ // api/src/common/blocks/media.block.ts
263
+ import { createOneOfBlock, DamImageBlock, DamVideoBlock, VimeoVideoBlock, YouTubeVideoBlock } from "@comet/cms-api";
264
+
265
+ export const MediaBlock = createOneOfBlock(
266
+ {
267
+ supportedBlocks: {
268
+ image: DamImageBlock,
269
+ damVideo: DamVideoBlock,
270
+ youTubeVideo: YouTubeVideoBlock,
271
+ vimeoVideo: VimeoVideoBlock,
272
+ },
273
+ },
274
+ "Media",
275
+ );
276
+ ```
277
+
278
+ **Admin:**
279
+
280
+ ```tsx
281
+ // admin/src/common/blocks/MediaBlock.tsx
282
+ import {
283
+ BlockCategory,
284
+ type BlockInterface,
285
+ createOneOfBlock,
286
+ DamImageBlock,
287
+ DamVideoBlock,
288
+ VimeoVideoBlock,
289
+ YouTubeVideoBlock,
290
+ } from "@comet/cms-admin";
291
+ import { FormattedMessage } from "react-intl";
292
+
293
+ export const MediaBlock: BlockInterface = createOneOfBlock({
294
+ supportedBlocks: { image: DamImageBlock, damVideo: DamVideoBlock, youTubeVideo: YouTubeVideoBlock, vimeoVideo: VimeoVideoBlock },
295
+ name: "Media",
296
+ displayName: <FormattedMessage id="mediaBlock.displayName" defaultMessage="Media" />,
297
+ allowEmpty: false,
298
+ variant: "toggle",
299
+ category: BlockCategory.Media,
300
+ });
301
+ ```
302
+
303
+ **Site:** Each project implements its own site component. Typically it renders a `OneOfBlock` with supported blocks for image and video.
304
+
305
+ ### Usage Pattern
306
+
307
+ ```ts
308
+ // API
309
+ @ChildBlock(MediaBlock)
310
+ media: BlockDataInterface;
311
+
312
+ // Admin
313
+ media: {
314
+ block: MediaBlock,
315
+ title: <FormattedMessage id="myBlock.media" defaultMessage="Media" />,
316
+ },
317
+ ```
318
+
319
+ ---
320
+
321
+ ## Common Pitfalls
322
+
323
+ 1. **Using `PixelImageBlock` when `DamImageBlock` would be better** -- Unless there is a specific reason to exclude SVGs, prefer `DamImageBlock`. It gives editors more flexibility.
324
+ 2. **Forgetting the site-side `DamImageBlock` wrapper** -- Unlike `PixelImageBlock` and `SvgImageBlock`, `DamImageBlock` is not exported from `@comet/site-nextjs`. Check whether the project already has a wrapper in `site/src/common/blocks/DamImageBlock.tsx` before creating one.
325
+ 3. **Not checking for an existing `MediaBlock`** -- When the user asks for "image" support but the context suggests video might also be needed (stage blocks, hero blocks, teaser media), check if the project has a `MediaBlock` and suggest using it.
326
+ 4. **Missing `aspectRatio` on `PixelImageBlock` in the site** -- `PixelImageBlock` requires an `aspectRatio` prop in the site layer. Omitting it causes layout issues.
327
+ 5. **Not handling the empty state for `SvgImageBlock`** -- Always check `damFile` before rendering `SvgImageBlock` in the site to avoid broken image placeholders.
328
+ 6. **Using `DamImageBlock` for icon-only fields** -- When the field is specifically for icons or logos (always SVG), use `SvgImageBlock` to prevent editors from uploading raster images that would not scale properly.
329
+
330
+ ---
331
+
332
+ ## Naming Conventions for Image Properties
333
+
334
+ The property name in the block should reflect the content type:
335
+
336
+ | Content | Property Name | Block |
337
+ | --------------------- | ------------------ | ----------------- |
338
+ | General image | `image` | `DamImageBlock` |
339
+ | Icon / logo | `icon` or `logo` | `SvgImageBlock` |
340
+ | Photo (raster only) | `photo` or `image` | `PixelImageBlock` |
341
+ | Media (image + video) | `media` | `MediaBlock` |