@eventmodelers/cli 1.0.14 → 1.0.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.14",
3
+ "version": "1.0.18",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,7 @@ export async function createSupabaseRealtimeAdapter(cfg, initialToken) {
10
10
  await supabase.realtime.setAuth(initialToken);
11
11
 
12
12
  return {
13
- subscribe(topic, handlers, onStatus) {
13
+ async subscribe(topic, handlers, onStatus) {
14
14
  let channel = supabase.channel(topic, { config: { private: true } });
15
15
  for (const [event, handler] of Object.entries(handlers)) {
16
16
  channel = channel.on('broadcast', { event }, (msg) => handler(msg.payload));
@@ -38,6 +38,10 @@ Read the target project's `.build-kit/CLAUDE.md` and explore existing slices. Lo
38
38
  - Feature flag patterns (Step 4 — optional)
39
39
  - Spring Boot test annotation: check if the project defines a meta-annotation over `@SpringBootTest`
40
40
 
41
+ **Determine `{basePackage}`** — every path below is rooted at
42
+ `{basePackage}.slices.{context}.automation.{slicename}`. Resolve `{basePackage}` as documented in
43
+ `.build-kit/CLAUDE.md`'s Structure section.
44
+
41
45
  ## Step 1: Understand the Input
42
46
 
43
47
  Extract these elements regardless of input format:
@@ -131,7 +135,7 @@ If a command fails, the event handler fails and the event processor retries.
131
135
  ### Stateless Automation
132
136
 
133
137
  New automation slices live under
134
- `src/main/java/de/eventmodelers/slices/{context}/automation/{slicename}/`.
138
+ `src/main/java/.../slices/{context}/automation/{slicename}/`.
135
139
 
136
140
  #### Strategy interface (if needed)
137
141
 
@@ -280,7 +284,7 @@ Add to ALL config files when using `@ConditionalOnProperty`:
280
284
  **For stateless automations** — pure unit tests with a mocked `CommandDispatcher`:
281
285
 
282
286
  ```java
283
- // File: src/test/java/de/eventmodelers/slices/{context}/automation/{slicename}/{AutomationName}Test.java
287
+ // File: src/test/java/.../slices/{context}/automation/{slicename}/{AutomationName}Test.java
284
288
  class {AutomationName}ProcessorTest {
285
289
 
286
290
  private {AutomationName}Processor processor;
@@ -19,7 +19,8 @@ description: >
19
19
  > **Preview feature** — AF5 Workflow APIs may change without notice and are not yet for production.
20
20
 
21
21
  New workflow slices live under
22
- `src/main/java/de/eventmodelers/slices/{context}/automation/{slicename}/`.
22
+ `src/main/java/.../slices/{context}/automation/{slicename}/` — see Step 0 below for how to resolve the
23
+ `{basePackage}` this path is rooted at.
23
24
 
24
25
  ---
25
26
 
@@ -32,6 +33,11 @@ Read `.build-kit/CLAUDE.md` and check whether the project already uses AF5 Workf
32
33
  - A `WorkflowModule` bean in any `@Configuration` class
33
34
  - Classes annotated with `@Workflow`
34
35
  - Existing `*Workflow.java` files under any slice package
36
+
37
+ **Determine `{basePackage}`** — every path in this skill is rooted at
38
+ `{basePackage}.slices.{context}.automation.{slicename}`. Resolve `{basePackage}` as documented in
39
+ `.build-kit/CLAUDE.md`'s Structure section.
40
+
35
41
  - The `WorkflowModule` dependency in `pom.xml`:
36
42
 
37
43
  ```xml
@@ -92,7 +98,7 @@ The simplest way to define a workflow using `@Workflow`:
92
98
 
93
99
  ```java
94
100
  // File: {slicename}/{SliceName}Workflow.java
95
- package de.eventmodelers.slices.{context}.automation.{slicename};
101
+ package {basePackage}.slices.{context}.automation.{slicename};
96
102
 
97
103
  import org.axonframework.workflow.annotation.Workflow;
98
104
  import org.axonframework.workflow.SimpleWorkflowContext;
@@ -100,7 +106,7 @@ import org.axonframework.workflow.SimpleWorkflowContext;
100
106
  @Workflow(
101
107
  idProperty = "{triggerEventIdField}", // field name on the trigger event that becomes the workflow ID
102
108
  startOnEventClass = {TriggerEvent}.class, // event that starts a new workflow instance
103
- workflowNamespace = "de.eventmodelers.slices.{context}"
109
+ workflowNamespace = "{basePackage}.slices.{context}"
104
110
  )
105
111
  public class {SliceName}Workflow {
106
112
 
@@ -333,7 +339,7 @@ public void execute(SimpleWorkflowContext ctx) {
333
339
 
334
340
  ```java
335
341
  @Workflow(idProperty = "id", startOnEventClass = OrderPlaced.class,
336
- workflowNamespace = "de.eventmodelers.slices.{context}")
342
+ workflowNamespace = "{basePackage}.slices.{context}")
337
343
  public class {SliceName}Workflow {
338
344
 
339
345
  public void execute(SimpleWorkflowContext ctx) { /* ... */ }
@@ -476,14 +482,14 @@ class {SliceName}WorkflowIntegrationTest extends AbstractDeclarativeTestBase {
476
482
  ## Files to Create / Modify
477
483
 
478
484
  ```
479
- src/main/java/de/eventmodelers/slices/{context}/automation/{slicename}/
485
+ src/main/java/.../slices/{context}/automation/{slicename}/
480
486
  ├── {SliceName}Workflow.java ← @Workflow class (execute method + lifecycle listeners)
481
487
  └── {SliceName}WorkflowServices.java ← @Component step handlers (Spring beans)
482
488
 
483
- src/main/java/de/eventmodelers/slices/{context}/
489
+ src/main/java/.../slices/{context}/
484
490
  └── WorkflowConfiguration.java ← WorkflowModule bean (one per context, create if missing)
485
491
 
486
- src/test/java/de/eventmodelers/slices/{context}/automation/{slicename}/
492
+ src/test/java/.../slices/{context}/automation/{slicename}/
487
493
  └── {SliceName}WorkflowTest.java ← unit tests with mocked context + services
488
494
  ```
489
495
 
@@ -35,12 +35,18 @@ Read `.build-kit/.slices/{context}/{slicename}/slice.json`. Extract, and use **o
35
35
 
36
36
  Never invent a field, business rule, or event that isn't in slice.json.
37
37
 
38
+ ## Step 0a: Determine `{basePackage}`
39
+
40
+ Every code example below is rooted at `{basePackage}.slices.{context}.{slicename}`. Resolve
41
+ `{basePackage}` as documented in `.build-kit/CLAUDE.md`'s Structure section — never hardcode
42
+ `io.axoniq.quickstart` (the shipped quickstart scaffold's package) or any other specific package.
43
+
38
44
  ## Step 1: Command
39
45
 
40
46
  **Exactly one field has `idAttribute: true` in slice.json** — annotate it directly:
41
47
 
42
48
  ```java
43
- package io.axoniq.quickstart.slices.{context}.{slicename};
49
+ package {basePackage}.slices.{context}.{slicename};
44
50
 
45
51
  import org.axonframework.messaging.commandhandling.annotation.Command;
46
52
  import org.axonframework.modelling.annotation.TargetEntityId;
@@ -61,13 +67,13 @@ one field directly.** Instead build a compound id record and put `@TargetEntityI
61
67
  verified against the `SubscribeToCourse` slice (`email` + `courseId` both `idAttribute: true`):
62
68
 
63
69
  ```java
64
- package io.axoniq.quickstart.slices.{context}.{slicename};
70
+ package {basePackage}.slices.{context}.{slicename};
65
71
 
66
72
  public record {SliceName}Id(String field1, String field2) {}
67
73
  ```
68
74
 
69
75
  ```java
70
- package io.axoniq.quickstart.slices.{context}.{slicename};
76
+ package {basePackage}.slices.{context}.{slicename};
71
77
 
72
78
  import org.axonframework.messaging.commandhandling.annotation.Command;
73
79
  import org.axonframework.modelling.annotation.TargetEntityId;
@@ -93,7 +99,7 @@ Check `src/main/java/.../{context}/events/` first; add to the existing sealed/ma
93
99
  than creating a duplicate.
94
100
 
95
101
  ```java
96
- package io.axoniq.quickstart.slices.{context}.events;
102
+ package {basePackage}.slices.{context}.events;
97
103
 
98
104
  import org.axonframework.eventsourcing.annotation.EventTag;
99
105
  import org.axonframework.messaging.eventhandling.annotation.Event;
@@ -119,10 +125,10 @@ Package-private, mutable field(s) — **not** an immutable `State` record with f
119
125
  check needs, nothing else.
120
126
 
121
127
  ```java
122
- package io.axoniq.quickstart.slices.{context}.{slicename};
128
+ package {basePackage}.slices.{context}.{slicename};
123
129
 
124
- import io.axoniq.quickstart.slices.{context}.events.{EventName};
125
- import io.axoniq.quickstart.slices.{context}.events.EventTags;
130
+ import {basePackage}.slices.{context}.events.{EventName};
131
+ import {basePackage}.slices.{context}.events.EventTags;
126
132
  import org.axonframework.eventsourcing.annotation.EventCriteriaBuilder;
127
133
  import org.axonframework.eventsourcing.annotation.EventSourcingHandler;
128
134
  import org.axonframework.eventsourcing.annotation.reflection.EntityCreator;
@@ -164,7 +170,7 @@ resolved automatically from `Configuration` — pass it plus the event class str
164
170
  tempting to think `andBeingOneOfTypes(new QualifiedName({EventName}.class))` should work without it,
165
171
  since `QualifiedName` has a `Class<?>` constructor. Verified experimentally that it does NOT:
166
172
  `QualifiedName(Class<?>)`'s only job is `clazz.getName()` — the raw Java class name
167
- (`io.axoniq.quickstart.slices.foo.events.CustomerRegistered`) — not the `@Event(namespace, name)` value
173
+ (`{basePackage}.slices.foo.events.CustomerRegistered`) — not the `@Event(namespace, name)` value
168
174
  the event was actually appended under (`Foo.CustomerRegistered`). Swapping to it in
169
175
  `SubscribeToCourseDecisionModel` as a test made 2 of 3 passing tests fail immediately, silently, with
170
176
  no exception pointing at the real cause — the criteria just stopped matching anything, identical in
@@ -220,9 +226,9 @@ itself.
220
226
  ## Step 4: Command handler
221
227
 
222
228
  ```java
223
- package io.axoniq.quickstart.slices.{context}.{slicename};
229
+ package {basePackage}.slices.{context}.{slicename};
224
230
 
225
- import io.axoniq.quickstart.slices.{context}.events.{EventName};
231
+ import {basePackage}.slices.{context}.events.{EventName};
226
232
  import org.axonframework.messaging.commandhandling.annotation.CommandHandler;
227
233
  import org.axonframework.messaging.core.Metadata;
228
234
  import org.axonframework.messaging.eventhandling.gateway.EventAppender;
@@ -255,7 +261,7 @@ exist as a type in this version.
255
261
  ## Step 5: REST endpoint — only if slice.json shows an inbound `SCREEN` dependency on the command
256
262
 
257
263
  ```java
258
- package io.axoniq.quickstart.slices.{context}.{slicename};
264
+ package {basePackage}.slices.{context}.{slicename};
259
265
 
260
266
  import org.axonframework.messaging.commandhandling.gateway.CommandGateway;
261
267
  import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -323,9 +329,9 @@ One-time `pom.xml` addition (no version needed — resolved via the project's ex
323
329
  ```
324
330
 
325
331
  ```java
326
- package io.axoniq.quickstart.slices.{context}.{slicename};
332
+ package {basePackage}.slices.{context}.{slicename};
327
333
 
328
- import io.axoniq.quickstart.slices.{context}.events.{EventName};
334
+ import {basePackage}.slices.{context}.events.{EventName};
329
335
  import org.axonframework.eventsourcing.configuration.EventSourcedEntityModule;
330
336
  import org.axonframework.eventsourcing.configuration.EventSourcingConfigurer;
331
337
  import org.axonframework.messaging.commandhandling.configuration.CommandHandlingModule;
@@ -9,7 +9,7 @@ directly, and tests use `WebTestClient`, not `MockMvc`.
9
9
  ## Controller
10
10
 
11
11
  ```java
12
- package io.axoniq.quickstart.slices.{context}.{slicename};
12
+ package {basePackage}.slices.{context}.{slicename};
13
13
 
14
14
  import org.axonframework.messaging.commandhandling.gateway.CommandGateway;
15
15
  import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -59,7 +59,7 @@ shape for the first one, matching the project's WebFlux stack and the `@Conditio
59
59
  feature-flag convention (tests disable all slices by default; opt in per test class):
60
60
 
61
61
  ```java
62
- package io.axoniq.quickstart.slices.{context}.{slicename};
62
+ package {basePackage}.slices.{context}.{slicename};
63
63
 
64
64
  import org.axonframework.messaging.commandhandling.gateway.CommandGateway;
65
65
  import org.junit.jupiter.api.Test;
@@ -21,6 +21,10 @@ description: >
21
21
 
22
22
  Before writing any code, read the target project's `.build-kit/CLAUDE.md`
23
23
 
24
+ **Determine `{basePackage}`** — every code example below is rooted at
25
+ `{basePackage}.slices.{context}.{slicename}`. Resolve `{basePackage}` as documented in
26
+ `.build-kit/CLAUDE.md`'s Structure section.
27
+
24
28
  ## Step 1: Ensure Events Exist
25
29
 
26
30
  Before implementing the read slice, verify that all events the projector handles exist in the
@@ -70,7 +74,7 @@ comments** — those are only for write slices.
70
74
  ### Slice package structure
71
75
 
72
76
  ```
73
- de/<package>/{context}/slices/{slicename}/
77
+ .../slices/{context}/{slicename}/ (i.e. {basePackage}.slices.{context}.{slicename} — see Step 0)
74
78
  ├── Get{SliceName}.java ← query record + nested Result
75
79
  ├── {SliceName}Summary.java ← read model (projection output shape)
76
80
  ├── {SliceName}Projector.java ← @Component with @EventHandler + @QueryHandler
@@ -252,7 +256,7 @@ Pure unit tests — instantiate the projector directly, no Spring context needed
252
256
  Fast, no container startup.
253
257
 
254
258
  ```java
255
- // File: src/test/java/de/<package>/{context}/slices/{slicename}/{SliceName}ProjectorTest.java
259
+ // File: src/test/java/.../slices/{context}/{slicename}/{SliceName}ProjectorTest.java
256
260
  class {SliceName}ProjectorTest {
257
261
 
258
262
  private {SliceName}Projector projector;
@@ -2,6 +2,13 @@
2
2
 
3
3
  Read Events in src/events to understand the global structure.
4
4
 
5
+ `<basePackage>` in this project's Java code (`src/main/java/<basePackage>/slices/...`) is this
6
+ project's own Java package prefix, not a fixed value — resolve it, in order: (1) the package of the
7
+ project's `@SpringBootApplication` class, (2) the package of any existing slice already under
8
+ `.../slices/{context}/{slicename}/`, (3) only if no code exists yet, Maven's `<groupId>` in `pom.xml`
9
+ or Gradle's `group` property in `build.gradle`/`build.gradle.kts`. Never hardcode
10
+ `io.axoniq.quickstart` (the shipped quickstart scaffold's package) or any other specific package.
11
+
5
12
  ## File Structure Constraints
6
13
 
7
14
  - **Strict Path Limitation**: if not instructed otherwise, only check `src/slices/{slicename}/*.ts`
@@ -1,6 +1,5 @@
1
1
  package io.axoniq.quickstart;
2
2
 
3
- import io.axoniq.quickstart.giftcard.domain.GiftCard;
4
3
  import org.axonframework.messaging.eventhandling.processing.streaming.token.store.TokenStore;
5
4
  import org.axonframework.messaging.eventhandling.processing.streaming.token.store.inmemory.InMemoryTokenStore;
6
5
  import org.springframework.boot.SpringApplication;
@@ -8,115 +7,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
8
7
  import org.springframework.context.annotation.Bean;
9
8
  import org.springframework.scheduling.annotation.EnableScheduling;
10
9
 
11
- /**
12
- * Main entry point for the Axoniq Platform Quickstart application.
13
- *
14
- * <p>This Spring Boot application demonstrates a complete CQRS/Event Sourcing implementation
15
- * using Axon Framework and Axon Server, showcasing best practices for building reactive,
16
- * scalable applications with event-driven architecture.</p>
17
- *
18
- * <p><strong>Architecture Overview:</strong></p>
19
- * <ul>
20
- * <li><strong>CQRS Implementation</strong>: Separates command and query responsibilities</li>
21
- * <li><strong>Event Sourcing</strong>: Stores state changes as immutable events</li>
22
- * <li><strong>Reactive Web Stack</strong>: Uses Spring WebFlux for non-blocking I/O</li>
23
- * <li><strong>Real-time Updates</strong>: Implements Server-Sent Events for live UI updates</li>
24
- * <li><strong>In-Memory Projections</strong>: Fast query performance with eventual consistency</li>
25
- * </ul>
26
- *
27
- * <p><strong>Key Components Enabled:</strong></p>
28
- * <ul>
29
- * <li><strong>{@code @SpringBootApplication}</strong>: Enables auto-configuration, component scanning, and configuration properties</li>
30
- * <li><strong>{@code @EnableScheduling}</strong>: Activates scheduled task execution for the {@link io.axoniq.quickstart.giftcard.scheduler.GiftCardScheduler}</li>
31
- * </ul>
32
- *
33
- * <p><strong>Domain Model:</strong></p>
34
- * <p>The application centers around a Gift Card domain implementing:</p>
35
- * <ul>
36
- * <li><strong>EventSourced DCB Model</strong>: {@link GiftCard} - Core business logic and state</li>
37
- * <li><strong>Commands</strong>: Issue and redeem operations with business validation</li>
38
- * <li><strong>Events</strong>: Immutable facts about gift card lifecycle changes</li>
39
- * <li><strong>Queries</strong>: Read operations with subscription query support</li>
40
- * <li><strong>Projections</strong>: Denormalized read models for efficient querying</li>
41
- * </ul>
42
- *
43
- * <p><strong>Technical Stack:</strong></p>
44
- * <ul>
45
- * <li><strong>Axon Framework</strong>: CQRS/Event Sourcing framework</li>
46
- * <li><strong>Axon Server</strong>: Event store and message routing infrastructure</li>
47
- * <li><strong>Spring WebFlux</strong>: Reactive web framework with non-blocking I/O</li>
48
- * <li><strong>Vue.js 3</strong>: Frontend framework with Vuetify UI components</li>
49
- * <li><strong>Server-Sent Events</strong>: Real-time updates without WebSocket complexity</li>
50
- * </ul>
51
- *
52
- * <p><strong>Educational Value:</strong></p>
53
- * <p>This quickstart serves as a practical learning resource demonstrating:</p>
54
- * <ul>
55
- * <li>Event Sourcing patterns and practices</li>
56
- * <li>CQRS implementation with separate read/write models</li>
57
- * <li>Real-time web applications with reactive streams</li>
58
- * <li>Integration between Axon Framework and Spring Boot</li>
59
- * <li>Modern UI development with real-time data updates</li>
60
- * </ul>
61
- *
62
- * <p><strong>Production Readiness Notes:</strong></p>
63
- * <p>While this quickstart demonstrates core patterns, production deployments should consider:</p>
64
- * <ul>
65
- * <li>Persistent event store configuration (vs. in-memory)</li>
66
- * <li>Distributed deployment strategies</li>
67
- * <li>Monitoring and observability integration</li>
68
- * <li>Security implementation (authentication, authorization)</li>
69
- * <li>Error handling and retry mechanisms</li>
70
- * <li>Performance tuning and resource optimization</li>
71
- * </ul>
72
- *
73
- * <p><strong>Getting Started:</strong></p>
74
- * <ol>
75
- * <li>Ensure Axon Server is running on localhost:8124</li>
76
- * <li>Run this application using Spring Boot</li>
77
- * <li>Access the web interface at http://localhost:8080</li>
78
- * <li>Observe real-time gift card operations via the scheduler</li>
79
- * <li>Interact with the API endpoints at /api/giftcards</li>
80
- * </ol>
81
- *
82
- * @see GiftCard
83
- * @see io.axoniq.quickstart.giftcard.web.GiftCardController
84
- * @see io.axoniq.quickstart.giftcard.query.GiftCardProjection
85
- * @see io.axoniq.quickstart.giftcard.scheduler.GiftCardScheduler
86
- * @see <a href="https://docs.axoniq.io/reference-guide/">Axon Framework Reference Guide</a>
87
- *
88
- * @author AxonIQ Quickstart
89
- * @version 1.0
90
- * @since 1.0
91
- */
92
10
  @SpringBootApplication
93
11
  @EnableScheduling
94
12
  public class QuickstartApplication {
95
13
 
96
- /**
97
- * Application entry point that starts the Spring Boot application.
98
- *
99
- * <p>This method bootstraps the entire application context, including:</p>
100
- * <ul>
101
- * <li>Axon Framework auto-configuration</li>
102
- * <li>Spring WebFlux reactive web server</li>
103
- * <li>Component scanning and dependency injection</li>
104
- * <li>Scheduled task initialization</li>
105
- * <li>Static resource serving configuration</li>
106
- * </ul>
107
- *
108
- * <p><strong>Startup sequence:</strong></p>
109
- * <ol>
110
- * <li>Spring Boot application context initialization</li>
111
- * <li>Axon Server connection establishment</li>
112
- * <li>Event store and command/query bus configuration</li>
113
- * <li>EventSourced DCB model and projection registration</li>
114
- * <li>Web server startup on port 8080</li>
115
- * <li>Scheduler activation for demo operations</li>
116
- * </ol>
117
- *
118
- * @param args command line arguments passed to the application
119
- */
120
14
  public static void main(String[] args) {
121
15
  SpringApplication.run(QuickstartApplication.class, args);
122
16
  }
@@ -1,2 +1 @@
1
- spring.application.name=Platform QuickStart
2
- axoniq.platform.credentials=${AXONIQ_PLATFORM_CREDENTIALS}
1
+ spring.application.name=Platform QuickStart
@@ -68,12 +68,14 @@ Guidelines:
68
68
 
69
69
  ### Marks — only when the user explicitly asks for one
70
70
 
71
- The canvas has a native "Marks" feature (outline highlight, optional blur-outside spotlight) for calling out part of a screen. **Do not add marks by default.** Only apply one of the two effects below when the request explicitly asks to highlight/mark/call out/circle/spotlight or blur/obscure part of the screen (e.g. "highlight the submit button", "blur everything except the email field"). An ordinary "design a screen" request gets no marks.
71
+ The canvas has a native "Marks" feature (outline highlight, plus an optional "blur outside" or "white outside" spotlight) for calling out part of a screen — see `HtmlEditorModal.tsx`'s Highlight tool and `markBlur.ts`/`markStyles.ts` in the main app. **Do not add marks by default.** Only apply the effects below when the request explicitly asks to highlight/mark/call out/circle/spotlight, or blur/obscure/white-out part of the screen (e.g. "highlight the submit button", "blur everything except the email field", "white out everything but the header"). An ordinary "design a screen" request gets no marks.
72
72
 
73
- Since this skill only has a `pages`/`backgroundColor` field to send (no separate marks API), reproduce the same visual language directly as inline CSS on the target element(s) self-contained in the page HTML, same as any other styling in Step 3:
73
+ This skill only has a `pages`/`backgroundColor` field to send (no separate marks API — the native feature persists marks as board metadata, not through this render call), so reproduce the same visual language directly as inline CSS on the target element(s), self-contained in the page HTML same as any other styling in Step 3. No `<script>`/`<style>` tags are needed (and `<script>` is stripped anyway) — inline `style="..."` reproduces the same CSS the native feature injects:
74
74
 
75
- - **Mark / highlight an area** — add to the target element's `style`: `outline:4px solid <color> !important;outline-offset:1px;`. Default color `#e74c3c` (red) unless the user names one; other options mirror the app's mark picker: `#1e293b` (dark slate), `#2ecc71` (green), `#3b82f6` (blue), `#f1c40f` (yellow), `#ffffff` (white).
76
- - **Blur outside / spotlight an area** — add `style="filter:blur(6px) !important;"` to every other top-level sibling/section on the page so only the called-out element stays sharp. Combine with the outline above if the user asked to both mark and blur.
75
+ - **Mark / highlight an area** — add to the target element's `style`: `outline:4px solid <color> !important;outline-offset:1px;`. Default color `#e74c3c` (red) unless the user names one; other options mirror the app's mark picker (`ColorPicker.tsx`): `#1e293b` (dark slate), `#2ecc71` (green), `#3b82f6` (blue), `#f1c40f` (yellow), `#ffffff` (white).
76
+ - **Blur outside / spotlight an area** — add `style="filter:blur(6px) !important;"` to every other top-level sibling/section on the page so only the called-out element stays sharp.
77
+ - **White outside / spotlight an area** — same idea, but instead add `style="filter:brightness(0) invert(1) !important;"` to every other top-level sibling/section (collapses them to solid white — works uniformly across text, shapes, and images, unlike a plain background-color override). Use this only when the user says "white out" / "whiteout" rather than "blur" — the two are mutually exclusive per mark in the native tool, so never apply both blur and white filters to the same sibling.
78
+ - Combine the outline rule with either spotlight rule if the user asked to both mark *and* blur/white-out.
77
79
 
78
80
  Apply these only to the specific element(s) the request describes — don't guess at additional areas to call out.
79
81