@eventmodelers/cli 0.0.1
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/README.md +175 -0
- package/cli.js +676 -0
- package/package.json +35 -0
- package/shared/build-kit/code-export.mjs +560 -0
- package/shared/build-kit/lib/ollama-agent.js +147 -0
- package/shared/build-kit/package.json +11 -0
- package/shared/build-kit/ralph-ollama.js +39 -0
- package/shared/build-kit/realtime-agent.js +18 -0
- package/stacks/axon/templates/.claude/skills/build-automation/SKILL.md +407 -0
- package/stacks/axon/templates/.claude/skills/build-automation/references/feature-flag-patterns.md +114 -0
- package/stacks/axon/templates/.claude/skills/build-automation-workflow/SKILL.md +496 -0
- package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/axon-workflow-api.md +279 -0
- package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/feature-flag-patterns.md +114 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/SKILL.md +396 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/references/axon-test-fixture-patterns.md +162 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/references/feature-flag-patterns.md +56 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/references/rest-api-patterns.md +115 -0
- package/stacks/axon/templates/.claude/skills/build-state-view/SKILL.md +282 -0
- package/stacks/axon/templates/.claude/skills/connect/SKILL.md +178 -0
- package/stacks/axon/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +611 -0
- package/stacks/axon/templates/.claude/skills/load-slice/SKILL.md +141 -0
- package/stacks/axon/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
- package/stacks/axon/templates/build-kit/lib/AGENT.md +47 -0
- package/stacks/axon/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/axon/templates/build-kit/lib/backend-prompt.md +158 -0
- package/stacks/axon/templates/build-kit/lib/prompt.md +126 -0
- package/stacks/axon/templates/build-kit/lib/ralph.js +369 -0
- package/stacks/axon/templates/build-kit/ralph-claude.js +44 -0
- package/stacks/axon/templates/build-kit/ralph.sh +98 -0
- package/stacks/axon/templates/root/.env.example +5 -0
- package/stacks/axon/templates/root/CLAUDE.md +60 -0
- package/stacks/axon/templates/root/README.md +44 -0
- package/stacks/axon/templates/root/docker-compose.yml +64 -0
- package/stacks/axon/templates/root/mvnw +259 -0
- package/stacks/axon/templates/root/mvnw.cmd +149 -0
- package/stacks/axon/templates/root/pom.xml +125 -0
- package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/QuickstartApplication.java +128 -0
- package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/config/WebConfig.java +155 -0
- package/stacks/axon/templates/root/src/main/resources/application.properties +2 -0
- package/stacks/axon/templates/root/src/main/resources/static/bg-body.png +0 -0
- package/stacks/axon/templates/root/src/main/resources/static/bg-header.png +0 -0
- package/stacks/axon/templates/root/src/main/resources/static/index.html +596 -0
- package/stacks/cratis-csharp/templates/.claude/skills/_shared/cratis-conventions.md +251 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-automation/SKILL.md +99 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-automation/references/patterns.md +115 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/SKILL.md +163 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/references/patterns.md +234 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/SKILL.md +120 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/references/patterns.md +166 -0
- package/stacks/cratis-csharp/templates/.claude/skills/connect/SKILL.md +169 -0
- package/stacks/cratis-csharp/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +609 -0
- package/stacks/cratis-csharp/templates/.claude/skills/load-slice/SKILL.md +141 -0
- package/stacks/cratis-csharp/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/AGENT.md +58 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/backend-prompt.md +129 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/prompt.md +124 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/ralph.js +302 -0
- package/stacks/cratis-csharp/templates/build-kit/ralph-claude.js +37 -0
- package/stacks/cratis-csharp/templates/build-kit/ralph.sh +98 -0
- package/stacks/cratis-csharp/templates/root/.frontend/index.css +29 -0
- package/stacks/cratis-csharp/templates/root/.frontend/index.html +17 -0
- package/stacks/cratis-csharp/templates/root/.frontend/main.tsx +18 -0
- package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.json +42 -0
- package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.node.json +11 -0
- package/stacks/cratis-csharp/templates/root/.frontend/vite.config.ts +56 -0
- package/stacks/cratis-csharp/templates/root/App.tsx +23 -0
- package/stacks/cratis-csharp/templates/root/CLAUDE.md +62 -0
- package/stacks/cratis-csharp/templates/root/CratisApp.csproj +25 -0
- package/stacks/cratis-csharp/templates/root/CratisApp.sln +18 -0
- package/stacks/cratis-csharp/templates/root/GlobalUsings.cs +3 -0
- package/stacks/cratis-csharp/templates/root/Home.tsx +102 -0
- package/stacks/cratis-csharp/templates/root/Program.cs +26 -0
- package/stacks/cratis-csharp/templates/root/README.md +192 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/AllListings.ts +47 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.cs +11 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.ts +12 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/ListingDataTable.tsx +17 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/index.ts +1 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Register.ts +51 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/RegisterDialog.tsx +18 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Registration.cs +27 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/index.ts +1 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeFeature.tsx +22 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeName.cs +3 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/index.ts +1 -0
- package/stacks/cratis-csharp/templates/root/appsettings.Development.json +9 -0
- package/stacks/cratis-csharp/templates/root/appsettings.json +26 -0
- package/stacks/cratis-csharp/templates/root/docker-compose.yml +23 -0
- package/stacks/cratis-csharp/templates/root/package.json +33 -0
- package/stacks/cratis-csharp/templates/root/tsconfig.json +3 -0
- package/stacks/modeling-kit/templates/.claude/settings.local.json +13 -0
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +215 -0
- package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +176 -0
- package/stacks/modeling-kit/templates/.claude/skills/connect/SKILL.md +182 -0
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +383 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +465 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +587 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/facilitating-event-modeling-workshops.md +626 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +542 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +497 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +783 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +604 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +699 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +674 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +231 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +150 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +329 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +204 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +352 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/project-planning-with-event-modeling.md +341 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +153 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +136 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +78 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +85 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +655 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +479 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +234 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +353 -0
- package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +200 -0
- package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +94 -0
- package/stacks/modeling-kit/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +441 -0
- package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +290 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +212 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +123 -0
- package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +353 -0
- package/stacks/modeling-kit/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
- package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +134 -0
- package/stacks/modeling-kit/templates/kit/lib/agent.sh +20 -0
- package/stacks/modeling-kit/templates/kit/lib/ollama-agent.js +147 -0
- package/stacks/modeling-kit/templates/kit/lib/ralph.js +286 -0
- package/stacks/modeling-kit/templates/kit/package.json +12 -0
- package/stacks/modeling-kit/templates/kit/ralph-claude.js +50 -0
- package/stacks/modeling-kit/templates/kit/ralph-ollama.js +38 -0
- package/stacks/modeling-kit/templates/kit/ralph.sh +61 -0
- package/stacks/modeling-kit/templates/kit/realtime-agent.js +18 -0
- package/stacks/modeling-kit/templates/root/CLAUDE.md +56 -0
- package/stacks/node/templates/.claude/skills/build-automation/SKILL.md +266 -0
- package/stacks/node/templates/.claude/skills/build-state-change/SKILL.md +344 -0
- package/stacks/node/templates/.claude/skills/build-state-view/SKILL.md +412 -0
- package/stacks/node/templates/.claude/skills/connect/SKILL.md +178 -0
- package/stacks/node/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
- package/stacks/node/templates/.claude/skills/load-slice/SKILL.md +143 -0
- package/stacks/node/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
- package/stacks/node/templates/build-kit/README.md +86 -0
- package/stacks/node/templates/build-kit/lib/AGENT.md +47 -0
- package/stacks/node/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/node/templates/build-kit/lib/backend-prompt.md +152 -0
- package/stacks/node/templates/build-kit/lib/prompt.md +122 -0
- package/stacks/node/templates/build-kit/lib/ralph.js +369 -0
- package/stacks/node/templates/build-kit/ralph-claude.js +44 -0
- package/stacks/node/templates/build-kit/ralph.sh +98 -0
- package/stacks/node/templates/root/.env.example +15 -0
- package/stacks/node/templates/root/CLAUDE.md +60 -0
- package/stacks/node/templates/root/docker-compose.yml +15 -0
- package/stacks/node/templates/root/flyway.conf +17 -0
- package/stacks/node/templates/root/migrations/V1__schema.sql.example +12 -0
- package/stacks/node/templates/root/package.json +50 -0
- package/stacks/node/templates/root/server.ts +130 -0
- package/stacks/node/templates/root/setup-env.sh +53 -0
- package/stacks/node/templates/root/src/common/assertions.ts +6 -0
- package/stacks/node/templates/root/src/common/db.ts +32 -0
- package/stacks/node/templates/root/src/common/loadPostgresEventstore.ts +23 -0
- package/stacks/node/templates/root/src/common/parseEndpoint.ts +51 -0
- package/stacks/node/templates/root/src/common/processorDlq.ts +28 -0
- package/stacks/node/templates/root/src/common/realtimeBroadcast.ts +12 -0
- package/stacks/node/templates/root/src/common/replay.ts +16 -0
- package/stacks/node/templates/root/src/common/routes.ts +19 -0
- package/stacks/node/templates/root/src/common/testHelpers.ts +44 -0
- package/stacks/node/templates/root/src/swagger.ts +34 -0
- package/stacks/node/templates/root/src/util/assertions.ts +6 -0
- package/stacks/node/templates/root/src/util/hash.ts +9 -0
- package/stacks/node/templates/root/src/util/sanitize.ts +23 -0
- package/stacks/node/templates/root/tsconfig.json +32 -0
- package/stacks/node/templates/root/vercel.json +8 -0
- package/stacks/supabase/templates/.claude/skills/build-automation/SKILL.md +266 -0
- package/stacks/supabase/templates/.claude/skills/build-state-change/SKILL.md +344 -0
- package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +390 -0
- package/stacks/supabase/templates/.claude/skills/build-webhook/SKILL.md +303 -0
- package/stacks/supabase/templates/.claude/skills/connect/SKILL.md +178 -0
- package/stacks/supabase/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
- package/stacks/supabase/templates/.claude/skills/load-slice/SKILL.md +143 -0
- package/stacks/supabase/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
- package/stacks/supabase/templates/build-kit/README.md +86 -0
- package/stacks/supabase/templates/build-kit/lib/AGENT.md +47 -0
- package/stacks/supabase/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/supabase/templates/build-kit/lib/backend-prompt.md +152 -0
- package/stacks/supabase/templates/build-kit/lib/prompt.md +123 -0
- package/stacks/supabase/templates/build-kit/lib/ralph.js +369 -0
- package/stacks/supabase/templates/build-kit/ralph-claude.js +44 -0
- package/stacks/supabase/templates/build-kit/ralph.sh +98 -0
- package/stacks/supabase/templates/root/.env.example +22 -0
- package/stacks/supabase/templates/root/CLAUDE.md +61 -0
- package/stacks/supabase/templates/root/flyway.conf +17 -0
- package/stacks/supabase/templates/root/package.json +52 -0
- package/stacks/supabase/templates/root/server.ts +177 -0
- package/stacks/supabase/templates/root/setup-env.sh +53 -0
- package/stacks/supabase/templates/root/src/common/assertions.ts +6 -0
- package/stacks/supabase/templates/root/src/common/db.ts +32 -0
- package/stacks/supabase/templates/root/src/common/loadPostgresEventstore.ts +23 -0
- package/stacks/supabase/templates/root/src/common/parseEndpoint.ts +51 -0
- package/stacks/supabase/templates/root/src/common/processorDlq.ts +28 -0
- package/stacks/supabase/templates/root/src/common/realtimeBroadcast.ts +19 -0
- package/stacks/supabase/templates/root/src/common/replay.ts +16 -0
- package/stacks/supabase/templates/root/src/common/routes.ts +23 -0
- package/stacks/supabase/templates/root/src/common/testHelpers.ts +54 -0
- package/stacks/supabase/templates/root/src/supabase/README.md +141 -0
- package/stacks/supabase/templates/root/src/supabase/api.ts +56 -0
- package/stacks/supabase/templates/root/src/supabase/requireOrgaAdmin.ts +32 -0
- package/stacks/supabase/templates/root/src/supabase/requireSysUser.ts +40 -0
- package/stacks/supabase/templates/root/src/supabase/requireUser.ts +72 -0
- package/stacks/supabase/templates/root/src/swagger.ts +34 -0
- package/stacks/supabase/templates/root/src/util/assertions.ts +6 -0
- package/stacks/supabase/templates/root/src/util/hash.ts +9 -0
- package/stacks/supabase/templates/root/src/util/sanitize.ts +23 -0
- package/stacks/supabase/templates/root/supabase/config.toml +295 -0
- package/stacks/supabase/templates/root/supabase/migrations/V1__schema.sql.example +12 -0
- package/stacks/supabase/templates/root/supabase/seed.sql +1 -0
- package/stacks/supabase/templates/root/tsconfig.json +32 -0
- package/stacks/supabase/templates/root/vercel.json +8 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: place-element
|
|
3
|
+
description: Place a COMMAND, READMODEL, EVENT, SCREEN, AUTOMATION, or SCENARIO spec node onto an existing eventmodelers board timeline at a specific position
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Place Element
|
|
7
|
+
|
|
8
|
+
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, and `BASE_URL`. Then invoke the `learn-eventmodelers-api` skill to load the full API reference. Do not proceed until both skills have been loaded.
|
|
9
|
+
|
|
10
|
+
Place a single element — COMMAND, READMODEL, EVENT, SCREEN, AUTOMATION, or SCENARIO spec node — onto an existing timeline on an eventmodelers board. Uses an existing column when a position is given; only creates a new column when appending.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Step 1 — Parse arguments
|
|
14
|
+
|
|
15
|
+
From `$ARGUMENTS`, extract:
|
|
16
|
+
|
|
17
|
+
| Field | How to find it | Default |
|
|
18
|
+
|-------|---------------|---------|
|
|
19
|
+
| `elementType` | `event`, `command`, `readmodel`, `screen`, or `automation` (case-insensitive) | **required** |
|
|
20
|
+
| `title` | the element name, e.g. "Order Placed" | **required** |
|
|
21
|
+
| `boardId` | a board UUID | from `connect` skill (`BOARD_ID`) |
|
|
22
|
+
| `timelineId` | the chapter/timeline UUID | auto-detect (see Step 2) |
|
|
23
|
+
| `position` | column index (0-based number), `"after <title>"`, or omitted | append at end |
|
|
24
|
+
| `baseUrl` | explicit URL override | from `connect` skill (`BASE_URL`) |
|
|
25
|
+
|
|
26
|
+
Normalise `elementType` to uppercase: `event` → `EVENT`, `command` → `COMMAND`, `readmodel` → `READMODEL`, `screen` → `SCREEN`, `automation` → `AUTOMATION`.
|
|
27
|
+
|
|
28
|
+
Use `BOARD_ID` and `BASE_URL` from the `connect` skill. If a `boardId` argument is explicitly passed, it overrides `BOARD_ID`.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Step 2 — Resolve the timeline
|
|
33
|
+
|
|
34
|
+
If `timelineId` is not provided, discover chapters on the board:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=CHAPTER"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- **Exactly one chapter** → use it automatically, tell the user which one was selected.
|
|
41
|
+
- **Multiple chapters** → list them by name/ID and ask the user which to target.
|
|
42
|
+
- **No chapters** → stop and tell the user to create a chapter first (e.g. via the `/timeline` skill).
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Step 3 — Fetch existing columns and resolve position
|
|
47
|
+
|
|
48
|
+
Always fetch the chapter node first to get the current timeline state:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$TIMELINE_ID"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
From `meta.timelineData`, read `columns` (ordered array of column objects with `id` and `index`) and `cells`.
|
|
55
|
+
|
|
56
|
+
Then resolve `position`:
|
|
57
|
+
|
|
58
|
+
| Input | Behaviour |
|
|
59
|
+
|-------|-----------|
|
|
60
|
+
| A number (e.g. `2`) | Find the existing column whose `index === 2`. Save its `id` as `columnId`. **Do NOT create a new column.** |
|
|
61
|
+
| `"after <title>"` | Cross-reference node titles to find the named column, then target the column at position + 1. If that next column already exists use it; if not, create one at that index. |
|
|
62
|
+
| Omitted | No existing column is targeted → create a new column at the end (Step 5). |
|
|
63
|
+
|
|
64
|
+
If `position` is a number and no column exists at that index, stop and tell the user: "No column at index `<n>` — did you mean to append instead?"
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Step 4 — Determine the target lane
|
|
69
|
+
|
|
70
|
+
| `elementType` | Target lane `type` |
|
|
71
|
+
|---------------|--------------------|
|
|
72
|
+
| `EVENT` | `swimlane` |
|
|
73
|
+
| `COMMAND` | `interaction` |
|
|
74
|
+
| `READMODEL` | `interaction` |
|
|
75
|
+
| `SCREEN` | `actor` |
|
|
76
|
+
| `AUTOMATION` | `actor` |
|
|
77
|
+
| `SCENARIO` | `spec` |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Step 4a — SCENARIO only: append scenarios via the spec endpoint
|
|
82
|
+
|
|
83
|
+
**Only applies when `elementType === "SCENARIO"`.**
|
|
84
|
+
|
|
85
|
+
The `/scenarios` endpoint creates the SCENARIO spec node automatically if the spec cell is empty, then appends all provided scenarios in one call. Do **not** use `/nodes/events` to create the spec node or write scenarios manually.
|
|
86
|
+
|
|
87
|
+
After resolving `columnId` (from step 3, or from step 5 if a new column was just created), call:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TL/columns/$COL/scenarios" \
|
|
91
|
+
-H "x-token: $TOKEN" -H "Content-Type: application/json" \
|
|
92
|
+
-d '[
|
|
93
|
+
{
|
|
94
|
+
"id": "<scenario-uuid>",
|
|
95
|
+
"title": "Happy path",
|
|
96
|
+
"given": [{"id":"<eventNodeId>","title":"OrderPlaced","type":"EVENT"}],
|
|
97
|
+
"when": [{"id":"<commandNodeId>","title":"PlaceOrder","type":"COMMAND"}],
|
|
98
|
+
"then": [{"id":"<eventNodeId2>","title":"OrderConfirmed","type":"EVENT"}]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "<scenario-uuid>",
|
|
102
|
+
"title": "Insufficient stock",
|
|
103
|
+
"given": [{"id":"<eventNodeId>","title":"OrderPlaced","type":"EVENT"}],
|
|
104
|
+
"when": [{"id":"<commandNodeId>","title":"PlaceOrder","type":"COMMAND"}],
|
|
105
|
+
"then": [],
|
|
106
|
+
"expectError": true,
|
|
107
|
+
"errorDescription": "Stock below requested quantity"
|
|
108
|
+
}
|
|
109
|
+
]'
|
|
110
|
+
# → 201 { specNodeId, scenarios (all), added (count), isNewNode }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Scenario object shapes:**
|
|
114
|
+
|
|
115
|
+
| Scenario type | Shape |
|
|
116
|
+
|---|---|
|
|
117
|
+
| Happy path | `{ id, title, given[], when[], then[] }` |
|
|
118
|
+
| Error case | `{ id, title, given[], when[], then: [], expectError: true, errorDescription: "..." }` |
|
|
119
|
+
|
|
120
|
+
**Step item format** — each item in `given`, `when`, `then`:
|
|
121
|
+
```json
|
|
122
|
+
{ "id": "<board-node-uuid>", "title": "OrderPlaced", "type": "EVENT", "fields": [], "specRow": 0 }
|
|
123
|
+
```
|
|
124
|
+
`id` is required (board node UUID). `title` and `type` are informational.
|
|
125
|
+
|
|
126
|
+
| Step | Allowed types |
|
|
127
|
+
|------|--------------|
|
|
128
|
+
| `given` | `EVENT` only |
|
|
129
|
+
| `when` | at most one `COMMAND`; empty when `then` has a READMODEL |
|
|
130
|
+
| `then` (happy path) | `EVENT` or `READMODEL` — not mixed |
|
|
131
|
+
| `then` (error case) | leave empty, use `expectError: true` |
|
|
132
|
+
|
|
133
|
+
**Mapping config IDs to board node IDs** — if working from a slice config file, build a lookup first:
|
|
134
|
+
```
|
|
135
|
+
config_command_id → board COMMAND node ID (from chapter cells for that column)
|
|
136
|
+
config_event_id → board EVENT node ID (from chapter cells for that column)
|
|
137
|
+
config_rm_id → board READMODEL node ID
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Once `/scenarios` returns `201`, proceed directly to **Step 8** — report back to the user.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Step 5 — Create a column only when appending
|
|
145
|
+
|
|
146
|
+
**Skip this step entirely** when `columnId` was already resolved in Step 3 (i.e. the user targeted an existing column).
|
|
147
|
+
|
|
148
|
+
Only run this when position was omitted (append mode):
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TIMELINE_ID/columns" \
|
|
152
|
+
-H "x-token: $TOKEN" \
|
|
153
|
+
-H "x-board-id: $BOARD_ID" \
|
|
154
|
+
-H "x-user-id: agent" \
|
|
155
|
+
-H "Content-Type: application/json" \
|
|
156
|
+
-d '{}'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Response: `{ "columnId": "<uuid>", "index": <n>, "totalColumns": <n> }`
|
|
160
|
+
|
|
161
|
+
Save `columnId` from the response.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Step 6 — Compute the target cell ID and check availability
|
|
166
|
+
|
|
167
|
+
Using the `timelineData` already fetched in Step 3 (re-fetch if a column was just created):
|
|
168
|
+
|
|
169
|
+
- Find the row in `rows` whose `type` matches the target lane (`swimlane`, `interaction`, or `actor`).
|
|
170
|
+
- Compute the cell ID directly: **`CELL_ID = targetRow.id + "-" + columnId`**
|
|
171
|
+
|
|
172
|
+
Cell IDs are always `<rowId>-<columnId>` — no cell array search needed.
|
|
173
|
+
|
|
174
|
+
**Check if the cell is already occupied**: query nodes in that cell:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=$CELL_ID"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**If the cell is occupied**, the behaviour depends on the element type being placed:
|
|
181
|
+
|
|
182
|
+
| Element type | Occupant type in same cell | Action |
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| `READMODEL` | `COMMAND` (state-change slice already owns this column) | Insert a **new column immediately after** the current column (not at the end) and use that new column as the target. |
|
|
185
|
+
| `SCREEN` (view/output screen) | any | Same as READMODEL — insert immediately after. |
|
|
186
|
+
| Any | Same element type | Stop and tell the user — true conflict, no safe default. |
|
|
187
|
+
| Any | Different type but not a known pairing | Stop and tell the user. |
|
|
188
|
+
|
|
189
|
+
**Insert immediately after** means: create the new column with `index = currentColumnIndex + 1`, not by appending to the end. This keeps the read model visually adjacent to the event that drives it.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TIMELINE_ID/columns" \
|
|
193
|
+
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: agent" \
|
|
194
|
+
-H "Content-Type: application/json" \
|
|
195
|
+
-d '{"index": <currentColumnIndex + 1>}'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
If no matching row is found, stop and report the error — the timeline may be missing the required lane type.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Step 7 — Create the node
|
|
203
|
+
|
|
204
|
+
> **SCREEN nodes always require a sketch.** The server auto-generates a title-only placeholder when a SCREEN is created without one, but it will look empty. Always follow up a SCREEN node creation with a call to `POST /images/:nodeId/sketch` (or use `POST /image-nodes/:nodeId/sketch` to create and render in one call — see `learn-eventmodelers-api` for the sketch format).
|
|
205
|
+
|
|
206
|
+
Include `x-token`, `x-board-id`, and `x-user-id: agent` on every call to `/nodes/events`:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
210
|
+
-H "x-token: $TOKEN" \
|
|
211
|
+
-H "x-board-id: $BOARD_ID" \
|
|
212
|
+
-H "x-user-id: agent" \
|
|
213
|
+
-H "Content-Type: application/json" \
|
|
214
|
+
-d '[{
|
|
215
|
+
"eventType": "node:created",
|
|
216
|
+
"nodeId": "<node-uuid>",
|
|
217
|
+
"boardId": "<BOARD_ID>",
|
|
218
|
+
"timestamp": <Date.now()>,
|
|
219
|
+
"chapterId": "<TIMELINE_ID>",
|
|
220
|
+
"cellId": "<CELL_ID>",
|
|
221
|
+
"meta": {
|
|
222
|
+
"type": "<ELEMENT_TYPE>",
|
|
223
|
+
"title": "<title>"
|
|
224
|
+
},
|
|
225
|
+
"node": { "data": { "title": "<title>" } }
|
|
226
|
+
}]'
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Response: `{ "hashes": { "<event-uuid>": "<hash>" } }`
|
|
230
|
+
|
|
231
|
+
> **`node:created` with `cellId` IS the placement** — do NOT also call the `drop` endpoint afterwards. The `drop` endpoint adds a second cell reference without removing the first, causing the node to appear in two columns simultaneously. Use `node:created + cellId` for all initial placements.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Step 8 — Report back
|
|
236
|
+
|
|
237
|
+
Tell the user:
|
|
238
|
+
|
|
239
|
+
- **What was placed**: element type and title
|
|
240
|
+
- **Where**: column index on the timeline
|
|
241
|
+
- **Node ID**: the UUID of the placed element
|
|
242
|
+
- **Cell ID**: the cell it was placed into
|
|
243
|
+
- **Any errors**: raw API message if something failed
|
|
244
|
+
|
|
245
|
+
Example success output:
|
|
246
|
+
```
|
|
247
|
+
Placed: EVENT "Order Placed" at column 3
|
|
248
|
+
Node ID: a1b2c3d4-…
|
|
249
|
+
Cell ID: e5f6g7h8-…
|
|
250
|
+
Timeline: <timelineId>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Example — place an EVENT via curl
|
|
256
|
+
|
|
257
|
+
Full working example placing an EVENT called "Order Placed" at the end of a timeline:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# 1. Add a column (append at end)
|
|
261
|
+
curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/timelines/<TIMELINE_ID>/columns" \
|
|
262
|
+
-H "Content-Type: application/json" \
|
|
263
|
+
-d '{}'
|
|
264
|
+
|
|
265
|
+
# 2. Fetch chapter to find the target lane cell for the new column
|
|
266
|
+
curl -s -H "x-user-id: place-element-skill" \
|
|
267
|
+
"http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<TIMELINE_ID>"
|
|
268
|
+
|
|
269
|
+
# 3. Create the EVENT node
|
|
270
|
+
|
|
271
|
+
Do not skip the User-ID.
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events" \
|
|
275
|
+
-H "Content-Type: application/json" \
|
|
276
|
+
-H "x-user-id: place-element-skill" \
|
|
277
|
+
-d '[{
|
|
278
|
+
"id": "<event-uuid>",
|
|
279
|
+
"eventType": "node:created",
|
|
280
|
+
"nodeId": "<node-uuid>",
|
|
281
|
+
"boardId": "<BOARD_ID>",
|
|
282
|
+
"timestamp": 1714900000000,
|
|
283
|
+
"chapterId": "<TIMELINE_ID>",
|
|
284
|
+
"cellId": "<CELL_ID>",
|
|
285
|
+
"meta": { "type": "EVENT", "title": "Order Placed" },
|
|
286
|
+
"node": { "id": "<node-uuid>", "data": { "title": "Order Placed" } }
|
|
287
|
+
}]'
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Replace `<TIMELINE_ID>`, `<BOARD_ID>`, `<CELL_ID>`, `<event-uuid>`, and `<node-uuid>` with real UUIDs. Use `Date.now()` or a current unix-ms timestamp for `timestamp`.
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: storyboard
|
|
3
|
+
description: Build a complete visual storyboard with AI-generated screens from a natural language description — creates a chapter, N columns, and N custom sketch screens
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Storyboard Builder
|
|
7
|
+
|
|
8
|
+
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, and `BASE_URL`. Do not proceed until the connect skill has completed.
|
|
9
|
+
|
|
10
|
+
You are building a complete visual storyboard by calling the board HTTP API. You generate the screen designs yourself using the grid description language below, then create the storyboard structure via `curl`. Only SCREEN nodes are created — no COMMAND or EVENT nodes.
|
|
11
|
+
|
|
12
|
+
## Step 1 — Parse arguments
|
|
13
|
+
|
|
14
|
+
From `$ARGUMENTS`, extract:
|
|
15
|
+
|
|
16
|
+
| Field | How to find it | Default |
|
|
17
|
+
|-------|---------------|---------|
|
|
18
|
+
| `description` | the flow name, e.g. "login flow", "checkout", "user onboarding" | required |
|
|
19
|
+
| `screenCount` | any number mentioned, e.g. "6 screens", "with 4 steps" | 3 |
|
|
20
|
+
| `boardId` | a board ID string, e.g. "board-abc" | from `connect` skill (`BOARD_ID`) |
|
|
21
|
+
| `chapterId` | an existing chapter ID to reuse, e.g. "chapter-xyz" | empty — create a new chapter |
|
|
22
|
+
| `baseUrl` | explicit URL override | from `connect` skill (`BASE_URL`) |
|
|
23
|
+
|
|
24
|
+
`BOARD_ID` and `BASE_URL` come from the `connect` skill. Only ask the user for `boardId` if explicitly overriding.
|
|
25
|
+
If `chapterId` is provided, skip chapter creation and go straight to Step 4.
|
|
26
|
+
|
|
27
|
+
## Step 2 — Plan all screens and create tasks
|
|
28
|
+
|
|
29
|
+
Before making any API calls, plan all N screens. For each screen, decide:
|
|
30
|
+
|
|
31
|
+
- `screenTitle` — human-readable name (e.g. "Enter Credentials")
|
|
32
|
+
- `elements` — a minimal list of grid elements (see language below, aim for 5–8 elements)
|
|
33
|
+
- `visualDescription` — a prose description of the screen's visual layout and content (2–4 sentences) that lets someone who cannot see the image understand what is shown: what UI sections appear, what text/labels are visible, where buttons and inputs are placed, and the overall purpose of the screen
|
|
34
|
+
|
|
35
|
+
Then **create one task per screen** using TaskCreate, naming each task after the screen title. This gives you a visible queue of work. Create the screens directly after each task has been planned.
|
|
36
|
+
|
|
37
|
+
## Grid description language
|
|
38
|
+
|
|
39
|
+
Canvas: **50 × 40 grid units** (1000 × 800 px, 1 unit = 20 px).
|
|
40
|
+
|
|
41
|
+
**Keep screens simple.** 5–8 elements is ideal. Speed matters more than detail — use rectangles as section placeholders, skip decorative elements. Skip circles.
|
|
42
|
+
|
|
43
|
+
Every screen's `elements` array **must start** with a full white background:
|
|
44
|
+
```json
|
|
45
|
+
{"type":"rectangle","gridX":0,"gridY":0,"gridWidth":50,"gridHeight":40,"fill":"white"}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Element types
|
|
49
|
+
|
|
50
|
+
| type | required fields | optional fields |
|
|
51
|
+
|------|----------------|-----------------|
|
|
52
|
+
| `rectangle` | gridX, gridY, gridWidth, gridHeight | fill, stroke |
|
|
53
|
+
| `text` | gridX, gridY, text | fontSize (default 12), fill, gridWidth |
|
|
54
|
+
| `headline` | gridX, gridY, text | fontSize (default 20), fill, gridWidth |
|
|
55
|
+
| `button` | gridX, gridY, gridWidth, gridHeight, text | fill, stroke |
|
|
56
|
+
| `input` | gridX, gridY, gridWidth, gridHeight, text (placeholder) | fill, stroke |
|
|
57
|
+
| `image` | gridX, gridY, gridWidth, gridHeight | fill (placeholder color) |
|
|
58
|
+
| `line` | gridX, gridY, gridX2, gridY2 | stroke |
|
|
59
|
+
| `circle` | gridX, gridY, gridRadius | fill, stroke |
|
|
60
|
+
|
|
61
|
+
### Colors
|
|
62
|
+
Limited to: `black` `grey` `light-violet` `violet` `blue` `light-blue` `yellow` `orange` `green` `light-green` `light-red` `red` `white`. No hex codes.
|
|
63
|
+
|
|
64
|
+
Keep all coordinates within bounds: gridX 0–50, gridY 0–40.
|
|
65
|
+
|
|
66
|
+
### Example — a simple screen (8 elements)
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"elements": [
|
|
70
|
+
{"type":"rectangle","gridX":0,"gridY":0,"gridWidth":50,"gridHeight":40,"fill":"white"},
|
|
71
|
+
{"type":"rectangle","gridX":0,"gridY":0,"gridWidth":50,"gridHeight":3,"fill":"light-violet"},
|
|
72
|
+
{"type":"headline","gridX":2,"gridY":1,"text":"Sign In","fontSize":18,"fill":"white"},
|
|
73
|
+
{"type":"input","gridX":15,"gridY":12,"gridWidth":20,"gridHeight":2,"text":"Email","fill":"white","stroke":"grey"},
|
|
74
|
+
{"type":"input","gridX":15,"gridY":16,"gridWidth":20,"gridHeight":2,"text":"Password","fill":"white","stroke":"grey"},
|
|
75
|
+
{"type":"button","gridX":15,"gridY":21,"gridWidth":20,"gridHeight":3,"text":"Sign In","fill":"blue"},
|
|
76
|
+
{"type":"text","gridX":18,"gridY":26,"text":"Forgot password?","fontSize":12,"fill":"blue"}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## ONE-TIME SETUP — run Steps 3 and 4 exactly once before the screen loop
|
|
84
|
+
|
|
85
|
+
### Step 3 — Resolve or create the chapter
|
|
86
|
+
|
|
87
|
+
**If `chapterId` was provided in Step 1** — set `CHAPTER_ID = chapterId` and skip to Step 4. Do not make any API call here.
|
|
88
|
+
|
|
89
|
+
**If `chapterId` was NOT provided** — create a new chapter (exactly once):
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/chapters" \
|
|
93
|
+
-H "Content-Type: application/json" \
|
|
94
|
+
-d '{"position":{"x":0,"y":0}}'
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Extract `id` from the response → `CHAPTER_ID`.
|
|
98
|
+
|
|
99
|
+
**You now have exactly one `CHAPTER_ID`. Do not create another chapter.**
|
|
100
|
+
|
|
101
|
+
### Step 4 — Fetch chapter state and build empty-column queue
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Parse `meta.timelineData` from the response:
|
|
108
|
+
- `rows` — list of row objects, each with `id` and `type`
|
|
109
|
+
- `columns` — list of column objects, each with `id`
|
|
110
|
+
- `cells` — list of cell objects, each with `rowId`, `colId`, and optionally `nodeId` (used only to check occupancy)
|
|
111
|
+
|
|
112
|
+
Find the row IDs for the `actor`, `interaction`, and `swimlane` row types. Save as `actorRowId`, `interactionRowId`, `swimlaneRowId`.
|
|
113
|
+
|
|
114
|
+
> **Cell ID convention**: Cell IDs are always `<rowId>-<columnId>`. Compute them directly — never search the `cells` array for an ID.
|
|
115
|
+
|
|
116
|
+
Build an **empty-column queue**: for each column (in order), compute `actorCellId = actorRowId + "-" + col.id`, `interactionCellId = interactionRowId + "-" + col.id`, `swimlaneCellId = swimlaneRowId + "-" + col.id`. Check these IDs in the `cells` array for a `nodeId` (absent or null). If ALL three have no `nodeId`, push `{actorCellId, interactionCellId, swimlaneCellId}` onto the queue.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## SCREEN LOOP — repeat Steps 5a–5d once per screen (N iterations total)
|
|
121
|
+
|
|
122
|
+
Process screens **one at a time**. Do not start the next screen until the current one is fully complete (node created + sketch rendered + verified).
|
|
123
|
+
|
|
124
|
+
**You have ONE chapter (`CHAPTER_ID`). All screens go into this same chapter. Do NOT call the chapter creation endpoint again inside this loop.**
|
|
125
|
+
|
|
126
|
+
Only SCREEN nodes are created. COMMAND and EVENT nodes are not created.
|
|
127
|
+
|
|
128
|
+
### Step 5a — Acquire a column slot for this screen
|
|
129
|
+
|
|
130
|
+
**If the empty-column queue is non-empty** — pop the first entry. Use its `actorCellId` directly, proceed to Step 5b.
|
|
131
|
+
|
|
132
|
+
**If the empty-column queue is empty** — add a new column (this does NOT create a new chapter):
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$CHAPTER_ID/columns" \
|
|
136
|
+
-H "Content-Type: application/json" \
|
|
137
|
+
-d '{}'
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Extract `columnId` from the response. Compute the actor cell ID directly:
|
|
141
|
+
|
|
142
|
+
**`actorCellId = actorRowId + "-" + columnId`**
|
|
143
|
+
|
|
144
|
+
(Cell IDs are always `<rowId>-<columnId>` — no re-fetch or cell array search needed.)
|
|
145
|
+
|
|
146
|
+
**In both cases**, generate a node UUID: `SCREEN_NODE_ID`. Generate an event UUID: `ACTOR_EVT_ID`.
|
|
147
|
+
|
|
148
|
+
Place the SCREEN node into the actor cell using the `/nodes/events` endpoint (agent-compatible — requires `x-user-id: agent`):
|
|
149
|
+
|
|
150
|
+
> **Do NOT use** `/boards/$BOARD_ID/events` — that endpoint requires a user JWT and will fail for agent (x-token) auth with "Authenticated user id is required".
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
154
|
+
-H "x-token: $TOKEN" \
|
|
155
|
+
-H "x-board-id: $BOARD_ID" \
|
|
156
|
+
-H "x-user-id: agent" \
|
|
157
|
+
-H "Content-Type: application/json" \
|
|
158
|
+
-d '[
|
|
159
|
+
{
|
|
160
|
+
"id": "<ACTOR_EVT_ID>",
|
|
161
|
+
"eventType": "node:created",
|
|
162
|
+
"nodeId": "<SCREEN_NODE_ID>",
|
|
163
|
+
"boardId": "<BOARD_ID>",
|
|
164
|
+
"timestamp": <NOW_MS>,
|
|
165
|
+
"chapterId": "<CHAPTER_ID>",
|
|
166
|
+
"cellId": "<actorCellId>",
|
|
167
|
+
"meta": {"type": "SCREEN", "title": "<screenTitle>", "description": "<visualDescription>"},
|
|
168
|
+
"node": {"id": "<SCREEN_NODE_ID>", "data": {}}
|
|
169
|
+
}
|
|
170
|
+
]'
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Verify the response contains `"hashes"`. If it fails, stop and report the error — do not proceed to the sketch step.
|
|
174
|
+
|
|
175
|
+
> **Do NOT call the `drop` endpoint after this step.** `node:created` with `cellId` already places the node in the correct cell. Calling drop afterwards creates a duplicate cell reference without removing the original, causing the node to appear in two columns simultaneously.
|
|
176
|
+
|
|
177
|
+
### Step 5b — Render the sketch onto the SCREEN node
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/images/$SCREEN_NODE_ID/sketch" \
|
|
181
|
+
-H "x-token: $TOKEN" \
|
|
182
|
+
-H "x-board-id: $BOARD_ID" \
|
|
183
|
+
-H "x-user-id: agent" \
|
|
184
|
+
-H "Content-Type: application/json" \
|
|
185
|
+
-d '{"description": "<screenTitle — what this screen shows>", "elements": [...]}'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Step 5c — Verify the screen
|
|
189
|
+
|
|
190
|
+
Confirm the node and its rendered image both actually exist before moving on:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/screens/$SCREEN_NODE_ID/verify" \
|
|
194
|
+
-H "x-token: $TOKEN"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Check the `valid` field in the response:
|
|
198
|
+
- **`valid: true`** — proceed to Step 5d.
|
|
199
|
+
- **`valid: false`** — read the `error` field. If `nodeExists` is `false`, the node creation in Step 5a failed; retry it. If `imageExists` is `false`, the sketch render in Step 5b failed silently; retry Step 5b once. If it fails verification again, log the error for this screen in the final report and move on to the next screen — do not get stuck retrying indefinitely.
|
|
200
|
+
|
|
201
|
+
### Step 5d — Mark the task complete
|
|
202
|
+
|
|
203
|
+
After the node, sketch, and verification all succeed, mark the task for this screen as completed using TaskUpdate.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Step 6 — Report back
|
|
208
|
+
|
|
209
|
+
After all screens are done, summarise:
|
|
210
|
+
- Chapter ID
|
|
211
|
+
- Numbered list: screen title
|
|
212
|
+
- Any errors (with status codes), including screens that failed the Step 5c verification
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: storyboard-screen
|
|
3
|
+
description: Design and render a single AI-generated wireframe screen onto an existing SCREEN node using the sketch API
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Storyboard Screen Designer
|
|
7
|
+
|
|
8
|
+
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, and `BASE_URL`. Do not proceed until the connect skill has completed.
|
|
9
|
+
|
|
10
|
+
> **MANDATORY RENDER + VERIFY**: The sketch API call in Step 4 and the verification in Step 5 are **not optional**. This skill exists solely to produce a rendered wireframe. A SCREEN node without a rendered sketch is an empty placeholder that adds no value to the model. If the sketch API call is skipped or fails, or verification reports `valid: false`, the task is incomplete — retry or report the error.
|
|
11
|
+
|
|
12
|
+
Design a single wireframe screen and render it onto an existing SCREEN node. Use this to redesign a screen, add detail to a placeholder, or update a screen after a flow changes.
|
|
13
|
+
|
|
14
|
+
## Step 1 — Parse arguments
|
|
15
|
+
|
|
16
|
+
From `$ARGUMENTS`, extract:
|
|
17
|
+
|
|
18
|
+
| Field | How to find it | Default |
|
|
19
|
+
|-------|---------------|---------|
|
|
20
|
+
| `description` | what the screen should contain, e.g. "login with email and password" | required |
|
|
21
|
+
| `boardId` | a board ID string | from `connect` skill (`BOARD_ID`) |
|
|
22
|
+
| `nodeId` | the SCREEN node UUID to update | **ask the user if missing** |
|
|
23
|
+
| `baseUrl` | explicit URL override | from `connect` skill (`BASE_URL`) |
|
|
24
|
+
|
|
25
|
+
If `nodeId` is missing, ask for it before doing anything. `BOARD_ID` and `BASE_URL` come from the `connect` skill.
|
|
26
|
+
|
|
27
|
+
## Step 2 — If updating an existing screen, load its current description first
|
|
28
|
+
|
|
29
|
+
If `nodeId` refers to a screen that has already been rendered (i.e. this is an adjustment/tweak, not a brand-new screen), **do not design from scratch**. First load the existing sketch description so the edit preserves the rest of the layout:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/images/$NODE_ID/description" \
|
|
33
|
+
-H "x-token: $TOKEN" \
|
|
34
|
+
-H "x-board-id: $BOARD_ID" \
|
|
35
|
+
-H "x-user-id: agent"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `200` — returns the previously stored `{ elements: [...] }`. Use this as the base and apply only the requested change (e.g. edit one element's `text`/`fill`, add/remove a specific element) — leave everything else untouched.
|
|
39
|
+
- `404` — no description stored yet (e.g. an older screen rendered before this endpoint existed, or a placeholder node). Fall back to designing from scratch in Step 3.
|
|
40
|
+
|
|
41
|
+
Skip this step entirely when the node is brand-new (no prior render) — go straight to Step 3.
|
|
42
|
+
|
|
43
|
+
## Step 3 — Design the screen
|
|
44
|
+
|
|
45
|
+
Design the screen using the grid description language — either from scratch (new screen, or Step 2 returned `404`) or by editing the elements loaded in Step 2. Think carefully about the layout — what elements does this screen need? Where should they go on the 50×40 grid?
|
|
46
|
+
|
|
47
|
+
Also compose a `visualDescription` — a prose description (2–4 sentences) of the screen's visual layout and content, written so that someone who cannot see the image can understand what is shown: what UI sections appear, what text/labels are visible, where buttons and inputs are placed, and the overall purpose of the screen.
|
|
48
|
+
|
|
49
|
+
## Grid description language
|
|
50
|
+
|
|
51
|
+
Canvas: **50 × 40 grid units** (1000 × 800 px, 1 unit = 20 px).
|
|
52
|
+
|
|
53
|
+
Always start with a full white background:
|
|
54
|
+
```json
|
|
55
|
+
{"type":"rectangle","gridX":0,"gridY":0,"gridWidth":50,"gridHeight":40,"fill":"white"}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Element types
|
|
59
|
+
|
|
60
|
+
| type | required fields | optional fields |
|
|
61
|
+
|------|----------------|-----------------|
|
|
62
|
+
| `rectangle` | gridX, gridY, gridWidth, gridHeight | fill, stroke |
|
|
63
|
+
| `text` | gridX, gridY, text | fontSize (default 12), fill, gridWidth |
|
|
64
|
+
| `headline` | gridX, gridY, text | fontSize (default 20), fill, gridWidth |
|
|
65
|
+
| `button` | gridX, gridY, gridWidth, gridHeight, text | fill, stroke |
|
|
66
|
+
| `input` | gridX, gridY, gridWidth, gridHeight, text (placeholder) | fill, stroke |
|
|
67
|
+
| `image` | gridX, gridY, gridWidth, gridHeight | fill (placeholder color) |
|
|
68
|
+
| `line` | gridX, gridY, gridX2, gridY2 | stroke |
|
|
69
|
+
| `circle` | gridX, gridY, gridRadius | fill, stroke |
|
|
70
|
+
|
|
71
|
+
### Colors
|
|
72
|
+
Limited to: `black` `grey` `light-violet` `violet` `blue` `light-blue` `yellow` `orange` `green` `light-green` `light-red` `red` `white`. No hex codes.
|
|
73
|
+
|
|
74
|
+
**Default palette — gray shades**: Unless instructed otherwise, use a grayscale palette. Prefer `white` for surfaces, `grey` for backgrounds, containers, borders, and secondary/placeholder text, and `black` for headings and primary text. Only introduce color when the user explicitly requests it.
|
|
75
|
+
|
|
76
|
+
Keep all coordinates within bounds: gridX 0–50, gridY 0–40.
|
|
77
|
+
|
|
78
|
+
### Example
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"elements": [
|
|
82
|
+
{"type":"rectangle","gridX":0,"gridY":0,"gridWidth":50,"gridHeight":40,"fill":"white"},
|
|
83
|
+
{"type":"rectangle","gridX":0,"gridY":0,"gridWidth":50,"gridHeight":3,"fill":"#424242"},
|
|
84
|
+
{"type":"headline","gridX":2,"gridY":1,"text":"Dashboard","fontSize":18,"fill":"white"},
|
|
85
|
+
{"type":"text","gridX":2,"gridY":6,"text":"Welcome back","fontSize":14,"fill":"grey"},
|
|
86
|
+
{"type":"rectangle","gridX":2,"gridY":9,"gridWidth":21,"gridHeight":8,"fill":"#e0e0e0","stroke":"#bdbdbd"},
|
|
87
|
+
{"type":"headline","gridX":4,"gridY":11,"text":"142","fontSize":24,"fill":"#424242"},
|
|
88
|
+
{"type":"text","gridX":4,"gridY":14,"text":"Orders this month","fontSize":11,"fill":"grey"},
|
|
89
|
+
{"type":"button","gridX":35,"gridY":36,"gridWidth":12,"gridHeight":2,"text":"Logout","fill":"#bdbdbd","stroke":"grey"}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Step 4 — Render the sketch
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/images/$NODE_ID/sketch" \
|
|
98
|
+
-H "x-token: $TOKEN" \
|
|
99
|
+
-H "x-board-id: $BOARD_ID" \
|
|
100
|
+
-H "x-user-id: agent" \
|
|
101
|
+
-H "Content-Type: application/json" \
|
|
102
|
+
-d '{"description": "<what this screen shows>", "elements": [...]}'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Expect `204 No Content` on success.
|
|
106
|
+
|
|
107
|
+
## Step 5 — Verify the screen
|
|
108
|
+
|
|
109
|
+
Confirm the node and its rendered image both actually exist:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/screens/$NODE_ID/verify" \
|
|
113
|
+
-H "x-token: $TOKEN"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If `valid` is `false`, read the `error` field and retry the failing step (Step 4 if `imageExists` is `false`) once before reporting failure.
|
|
117
|
+
|
|
118
|
+
## Step 6 — Report back
|
|
119
|
+
|
|
120
|
+
Tell the user:
|
|
121
|
+
- The node ID that was updated
|
|
122
|
+
- Whether the render succeeded (HTTP 204) and verification passed (`valid: true`)
|
|
123
|
+
- Any errors
|