eventmodeler 0.4.7 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/dist/api/client-config.js +10 -0
  2. package/dist/api/generated/client/client.gen.js +235 -0
  3. package/dist/api/generated/client/index.js +6 -0
  4. package/dist/api/generated/client/types.gen.js +2 -0
  5. package/dist/api/generated/client/utils.gen.js +228 -0
  6. package/dist/api/generated/client.gen.js +4 -0
  7. package/dist/api/generated/core/auth.gen.js +14 -0
  8. package/dist/api/generated/core/bodySerializer.gen.js +57 -0
  9. package/dist/api/generated/core/params.gen.js +100 -0
  10. package/dist/api/generated/core/pathSerializer.gen.js +106 -0
  11. package/dist/api/generated/core/queryKeySerializer.gen.js +92 -0
  12. package/dist/api/generated/core/serverSentEvents.gen.js +133 -0
  13. package/dist/api/generated/core/types.gen.js +2 -0
  14. package/dist/api/generated/core/utils.gen.js +87 -0
  15. package/dist/api/generated/index.js +2 -0
  16. package/dist/api/generated/sdk.gen.js +4222 -0
  17. package/dist/api/generated/types.gen.js +2 -0
  18. package/dist/api/generated/zod.gen.js +7217 -0
  19. package/dist/commands/add.js +315 -0
  20. package/dist/commands/auth.js +14 -0
  21. package/dist/commands/create.js +192 -0
  22. package/dist/commands/design.js +108 -0
  23. package/dist/commands/guide.js +15 -0
  24. package/dist/commands/init.js +21 -0
  25. package/dist/commands/list-schemas.js +177 -0
  26. package/dist/commands/list.js +39 -0
  27. package/dist/commands/loop.js +101 -0
  28. package/dist/commands/map.js +40 -0
  29. package/dist/commands/mark.js +27 -0
  30. package/dist/commands/move.js +35 -0
  31. package/dist/commands/remove.js +170 -0
  32. package/dist/commands/rename.js +53 -0
  33. package/dist/commands/resize.js +30 -0
  34. package/dist/commands/search.js +14 -0
  35. package/dist/commands/set.js +199 -0
  36. package/dist/commands/show-schemas.js +259 -0
  37. package/dist/commands/show.js +56 -0
  38. package/dist/commands/summary.js +13 -0
  39. package/dist/commands/update.js +240 -0
  40. package/dist/index.js +46 -2379
  41. package/dist/lib/auth.js +1 -1
  42. package/dist/lib/config.js +0 -15
  43. package/dist/lib/excalidraw-schema.js +66 -0
  44. package/dist/lib/globals.js +8 -0
  45. package/dist/lib/model.js +11 -0
  46. package/dist/lib/project-config.js +20 -0
  47. package/dist/lib/resolve.js +59 -0
  48. package/dist/lib/scenario.js +15 -0
  49. package/dist/slices/add-scenario/index.js +2 -206
  50. package/dist/slices/guide/guides/codegen.js +1 -1
  51. package/dist/slices/guide/guides/connect-slices.js +12 -37
  52. package/dist/slices/guide/guides/create-slices.js +110 -140
  53. package/dist/slices/guide/guides/explore.js +37 -26
  54. package/dist/slices/guide/guides/information-flow.js +70 -82
  55. package/dist/slices/guide/guides/scenarios.js +82 -137
  56. package/dist/slices/guide/index.js +6 -6
  57. package/dist/slices/help/index.js +96 -0
  58. package/dist/slices/help/topics/build-codegen.js +109 -0
  59. package/dist/slices/help/topics/build-slice.js +147 -0
  60. package/dist/slices/help/topics/check-completeness.js +57 -0
  61. package/dist/slices/help/topics/connect-slices.js +99 -0
  62. package/dist/slices/help/topics/explore-model.js +112 -0
  63. package/dist/slices/help/topics/json-reference.js +188 -0
  64. package/dist/slices/help/topics/linked-copies.js +89 -0
  65. package/dist/slices/help/topics/manipulate-canvas.js +150 -0
  66. package/dist/slices/help/topics/write-scenarios.js +162 -0
  67. package/dist/slices/init/index.js +10 -4
  68. package/dist/slices/init/loop.js +60 -0
  69. package/dist/slices/login/index.js +2 -2
  70. package/dist/slices/logout/index.js +2 -2
  71. package/dist/slices/whoami/index.js +11 -36
  72. package/package.json +8 -3
  73. package/dist/api/index.d.ts +0 -285
  74. package/dist/api/index.js +0 -323
  75. package/dist/cloud/slices/index.d.ts +0 -276
  76. package/dist/cloud/slices/index.js +0 -406
  77. package/dist/eventmodeler.js +0 -5646
  78. package/dist/formatters.d.ts +0 -17
  79. package/dist/formatters.js +0 -482
  80. package/dist/index.d.ts +0 -2
  81. package/dist/lib/auth.d.ts +0 -24
  82. package/dist/lib/backend.d.ts +0 -43
  83. package/dist/lib/backend.js +0 -73
  84. package/dist/lib/chapter-utils.d.ts +0 -13
  85. package/dist/lib/chapter-utils.js +0 -71
  86. package/dist/lib/cloud-client.d.ts +0 -69
  87. package/dist/lib/cloud-client.js +0 -364
  88. package/dist/lib/config.d.ts +0 -30
  89. package/dist/lib/diff/merge-rules.d.ts +0 -45
  90. package/dist/lib/diff/merge-rules.js +0 -210
  91. package/dist/lib/diff/model-differ.d.ts +0 -8
  92. package/dist/lib/diff/model-differ.js +0 -568
  93. package/dist/lib/diff/three-way-merge.d.ts +0 -7
  94. package/dist/lib/diff/three-way-merge.js +0 -390
  95. package/dist/lib/diff/types.d.ts +0 -75
  96. package/dist/lib/diff/types.js +0 -1
  97. package/dist/lib/element-lookup.d.ts +0 -58
  98. package/dist/lib/element-lookup.js +0 -126
  99. package/dist/lib/file-loader.d.ts +0 -8
  100. package/dist/lib/file-loader.js +0 -108
  101. package/dist/lib/flow-utils.d.ts +0 -53
  102. package/dist/lib/flow-utils.js +0 -348
  103. package/dist/lib/format.d.ts +0 -10
  104. package/dist/lib/format.js +0 -23
  105. package/dist/lib/project-config.d.ts +0 -27
  106. package/dist/lib/slice-utils.d.ts +0 -59
  107. package/dist/lib/slice-utils.js +0 -140
  108. package/dist/local/slices/index.d.ts +0 -11
  109. package/dist/local/slices/index.js +0 -13
  110. package/dist/projection.d.ts +0 -3
  111. package/dist/projection.js +0 -828
  112. package/dist/slices/add-field/index.d.ts +0 -8
  113. package/dist/slices/add-field/index.js +0 -211
  114. package/dist/slices/add-scenario/index.d.ts +0 -27
  115. package/dist/slices/codegen-chapter-events/index.d.ts +0 -2
  116. package/dist/slices/codegen-chapter-events/index.js +0 -145
  117. package/dist/slices/codegen-slice/index.d.ts +0 -2
  118. package/dist/slices/codegen-slice/index.js +0 -448
  119. package/dist/slices/create-automation-slice/index.d.ts +0 -2
  120. package/dist/slices/create-automation-slice/index.js +0 -304
  121. package/dist/slices/create-flow/index.d.ts +0 -2
  122. package/dist/slices/create-flow/index.js +0 -183
  123. package/dist/slices/create-state-change-slice/index.d.ts +0 -2
  124. package/dist/slices/create-state-change-slice/index.js +0 -263
  125. package/dist/slices/create-state-view-slice/index.d.ts +0 -2
  126. package/dist/slices/create-state-view-slice/index.js +0 -128
  127. package/dist/slices/diff/index.d.ts +0 -11
  128. package/dist/slices/diff/index.js +0 -293
  129. package/dist/slices/export-eventmodel-to-json/index.d.ts +0 -2
  130. package/dist/slices/export-eventmodel-to-json/index.js +0 -355
  131. package/dist/slices/git/index.d.ts +0 -2
  132. package/dist/slices/git/index.js +0 -125
  133. package/dist/slices/guide/guides/codegen.d.ts +0 -5
  134. package/dist/slices/guide/guides/connect-slices.d.ts +0 -5
  135. package/dist/slices/guide/guides/create-slices.d.ts +0 -5
  136. package/dist/slices/guide/guides/explore.d.ts +0 -5
  137. package/dist/slices/guide/guides/information-flow.d.ts +0 -5
  138. package/dist/slices/guide/guides/scenarios.d.ts +0 -5
  139. package/dist/slices/guide/index.d.ts +0 -1
  140. package/dist/slices/import/index.d.ts +0 -8
  141. package/dist/slices/import/index.js +0 -63
  142. package/dist/slices/init/index.d.ts +0 -5
  143. package/dist/slices/list-chapters/index.d.ts +0 -3
  144. package/dist/slices/list-chapters/index.js +0 -21
  145. package/dist/slices/list-commands/index.d.ts +0 -3
  146. package/dist/slices/list-commands/index.js +0 -20
  147. package/dist/slices/list-events/index.d.ts +0 -3
  148. package/dist/slices/list-events/index.js +0 -98
  149. package/dist/slices/list-processors/index.d.ts +0 -3
  150. package/dist/slices/list-processors/index.js +0 -20
  151. package/dist/slices/list-readmodels/index.d.ts +0 -3
  152. package/dist/slices/list-readmodels/index.js +0 -21
  153. package/dist/slices/list-scenarios/index.d.ts +0 -3
  154. package/dist/slices/list-scenarios/index.js +0 -35
  155. package/dist/slices/list-screens/index.d.ts +0 -3
  156. package/dist/slices/list-screens/index.js +0 -47
  157. package/dist/slices/list-slices/index.d.ts +0 -3
  158. package/dist/slices/list-slices/index.js +0 -35
  159. package/dist/slices/login/index.d.ts +0 -1
  160. package/dist/slices/logout/index.d.ts +0 -1
  161. package/dist/slices/map-fields/index.d.ts +0 -2
  162. package/dist/slices/map-fields/index.js +0 -269
  163. package/dist/slices/mark-slice-status/index.d.ts +0 -2
  164. package/dist/slices/mark-slice-status/index.js +0 -31
  165. package/dist/slices/merge/index.d.ts +0 -19
  166. package/dist/slices/merge/index.js +0 -147
  167. package/dist/slices/open-app/index.d.ts +0 -1
  168. package/dist/slices/remove-field/index.d.ts +0 -8
  169. package/dist/slices/remove-field/index.js +0 -167
  170. package/dist/slices/remove-scenario/index.d.ts +0 -2
  171. package/dist/slices/remove-scenario/index.js +0 -77
  172. package/dist/slices/search/index.d.ts +0 -3
  173. package/dist/slices/search/index.js +0 -302
  174. package/dist/slices/show-actor/index.d.ts +0 -4
  175. package/dist/slices/show-actor/index.js +0 -115
  176. package/dist/slices/show-aggregate/index.d.ts +0 -3
  177. package/dist/slices/show-aggregate/index.js +0 -108
  178. package/dist/slices/show-aggregate-completeness/index.d.ts +0 -4
  179. package/dist/slices/show-aggregate-completeness/index.js +0 -181
  180. package/dist/slices/show-chapter/index.d.ts +0 -3
  181. package/dist/slices/show-chapter/index.js +0 -195
  182. package/dist/slices/show-command/index.d.ts +0 -3
  183. package/dist/slices/show-command/index.js +0 -133
  184. package/dist/slices/show-completeness/index.d.ts +0 -4
  185. package/dist/slices/show-completeness/index.js +0 -731
  186. package/dist/slices/show-event/index.d.ts +0 -3
  187. package/dist/slices/show-event/index.js +0 -118
  188. package/dist/slices/show-model-summary/index.d.ts +0 -3
  189. package/dist/slices/show-model-summary/index.js +0 -31
  190. package/dist/slices/show-processor/index.d.ts +0 -3
  191. package/dist/slices/show-processor/index.js +0 -111
  192. package/dist/slices/show-readmodel/index.d.ts +0 -3
  193. package/dist/slices/show-readmodel/index.js +0 -158
  194. package/dist/slices/show-scenario/index.d.ts +0 -3
  195. package/dist/slices/show-scenario/index.js +0 -196
  196. package/dist/slices/show-screen/index.d.ts +0 -3
  197. package/dist/slices/show-screen/index.js +0 -139
  198. package/dist/slices/show-slice/index.d.ts +0 -3
  199. package/dist/slices/show-slice/index.js +0 -696
  200. package/dist/slices/update-field/index.d.ts +0 -15
  201. package/dist/slices/update-field/index.js +0 -208
  202. package/dist/slices/whoami/index.d.ts +0 -2
  203. package/dist/types.d.ts +0 -195
  204. package/dist/types.js +0 -1
@@ -0,0 +1,21 @@
1
+ import { init } from '../slices/init/index';
2
+ import { initLoop } from '../slices/init/loop';
3
+ export function registerInitCommands(program) {
4
+ const cmd = program.command('init')
5
+ .description('Initialize project and link to an event model')
6
+ .action(() => init());
7
+ cmd.command('loop')
8
+ .description('Scaffold a loop config and sample generate.sh script')
9
+ .addHelpText('after', `
10
+ Writes a default "loop" block to .eventmodeler.json:
11
+ { "loop": { "command": "./generate.sh", "interval": 30 } }
12
+
13
+ And creates generate.sh — a script skeleton that marks the slice
14
+ in-progress, exports it as JSON, runs your codegen, and marks
15
+ done/blocked. Edit generate.sh to plug in your own logic.
16
+
17
+ Run the loop with:
18
+ eventmodeler loop
19
+ `)
20
+ .action(() => initLoop());
21
+ }
@@ -0,0 +1,177 @@
1
+ // Response shapes for list/summary/search commands, pulled from the backend ReadModels.
2
+ // Attached to each command's --help so agents can consume without out-of-band docs.
3
+ const envelope = (itemShape) => `Response (JSON on stdout):
4
+
5
+ {
6
+ "items": [
7
+ ${itemShape.split('\n').map((l) => ` ${l}`).join('\n')}
8
+ ]
9
+ }`;
10
+ export const LIST_SLICES_HELP = `
11
+ ${envelope(`{
12
+ "sliceId": "<uuid>",
13
+ "modelId": "<uuid>",
14
+ "name": "Place Order",
15
+ "status": "created" | "planned" | "in-progress" | "blocked" | "done",
16
+ "chapterName": "User Onboarding" | null,
17
+ "x": 0, "y": 0, "width": 0, "height": 0
18
+ }`)}
19
+
20
+ Filter locally with jq:
21
+ eventmodeler list slices | jq '[.items[] | select(.status=="planned")]'
22
+ `;
23
+ export const LIST_EVENTS_HELP = `
24
+ ${envelope(`{
25
+ "eventStickyId": "<uuid>",
26
+ "modelId": "<uuid>",
27
+ "name": "OrderPlaced",
28
+ "aggregateName": "Order" | null,
29
+ "fieldCount": 0,
30
+ "copyCount": 0,
31
+ "isLinkedCopy": false,
32
+ "originalId": "<uuid>" | null,
33
+ "originSlice": "Place Order" | null,
34
+ "x": 0, "y": 0, "width": 0, "height": 0
35
+ }`)}
36
+ `;
37
+ export const LIST_COMMANDS_HELP = `
38
+ ${envelope(`{
39
+ "commandStickyId": "<uuid>",
40
+ "modelId": "<uuid>",
41
+ "name": "PlaceOrder",
42
+ "fieldCount": 0,
43
+ "x": 0, "y": 0
44
+ }`)}
45
+ `;
46
+ export const LIST_READMODELS_HELP = `
47
+ ${envelope(`{
48
+ "readModelStickyId": "<uuid>",
49
+ "modelId": "<uuid>",
50
+ "name": "OrderSummary",
51
+ "fieldCount": 0,
52
+ "isLinkedCopy": false,
53
+ "originalId": "<uuid>" | null,
54
+ "x": 0, "y": 0
55
+ }`)}
56
+ `;
57
+ export const LIST_SCREENS_HELP = `
58
+ ${envelope(`{
59
+ "screenId": "<uuid>",
60
+ "modelId": "<uuid>",
61
+ "name": "OrderForm",
62
+ "actorId": "<uuid>" | null,
63
+ "actorName": "Customer" | null,
64
+ "fieldCount": 0,
65
+ "x": 0, "y": 0, "width": 0, "height": 0
66
+ }`)}
67
+ `;
68
+ export const LIST_PROCESSORS_HELP = `
69
+ ${envelope(`{
70
+ "processorId": "<uuid>",
71
+ "modelId": "<uuid>",
72
+ "name": "PaymentProcessor",
73
+ "fieldCount": 0,
74
+ "x": 0, "y": 0
75
+ }`)}
76
+ `;
77
+ export const LIST_EXTERNAL_EVENTS_HELP = `
78
+ ${envelope(`{
79
+ "externalEventId": "<uuid>",
80
+ "modelId": "<uuid>",
81
+ "name": "StripeChargeSucceeded",
82
+ "fieldCount": 0,
83
+ "isLinkedCopy": false,
84
+ "originalId": "<uuid>" | null,
85
+ "x": 0, "y": 0, "width": 0, "height": 0
86
+ }`)}
87
+ `;
88
+ export const LIST_AGGREGATES_HELP = `
89
+ ${envelope(`{
90
+ "aggregateId": "<uuid>",
91
+ "modelId": "<uuid>",
92
+ "name": "Order",
93
+ "eventCount": 0,
94
+ "idFieldName": "orderId" | null,
95
+ "idFieldType": "UUID" | null,
96
+ "x": 0, "y": 0, "width": 0, "height": 0
97
+ }`)}
98
+ `;
99
+ export const LIST_ACTORS_HELP = `
100
+ ${envelope(`{
101
+ "actorId": "<uuid>",
102
+ "modelId": "<uuid>",
103
+ "name": "Customer",
104
+ "screenCount": 0,
105
+ "x": 0, "y": 0, "width": 0, "height": 0
106
+ }`)}
107
+ `;
108
+ export const LIST_CHAPTERS_HELP = `
109
+ ${envelope(`{
110
+ "chapterId": "<uuid>",
111
+ "modelId": "<uuid>",
112
+ "name": "User Onboarding",
113
+ "x": 0, "y": 0, "width": 0, "height": 0
114
+ }`)}
115
+ `;
116
+ export const LIST_CONTEXTS_HELP = `
117
+ ${envelope(`{
118
+ "contextId": "<uuid>",
119
+ "modelId": "<uuid>",
120
+ "name": "Orders",
121
+ "x": 0, "y": 0, "width": 0, "height": 0
122
+ }`)}
123
+ `;
124
+ export const LIST_SWIMLANES_HELP = `
125
+ ${envelope(`{
126
+ "swimLaneId": "<uuid>",
127
+ "modelId": "<uuid>",
128
+ "name": "Finance",
129
+ "x": 0, "y": 0, "width": 0, "height": 0
130
+ }`)}
131
+ `;
132
+ export const LIST_NOTES_HELP = `
133
+ ${envelope(`{
134
+ "noteId": "<uuid>",
135
+ "modelId": "<uuid>",
136
+ "name": "Reminder",
137
+ "description": "Handle retries",
138
+ "x": 0, "y": 0, "width": 0, "height": 0
139
+ }`)}
140
+ `;
141
+ export const LIST_SCENARIOS_HELP = `
142
+ ${envelope(`{
143
+ "scenarioId": "<uuid>",
144
+ "modelId": "<uuid>",
145
+ "name": "happy path",
146
+ "sliceId": "<uuid>" | null,
147
+ "sliceName": "Place Order" | null
148
+ }`)}
149
+ `;
150
+ export const SUMMARY_HELP = `
151
+ Response (JSON on stdout):
152
+
153
+ {
154
+ "modelId": "<uuid>",
155
+ "actorCount": 0,
156
+ "aggregateCount": 0,
157
+ "chapterCount": 0,
158
+ "commandCount": 0,
159
+ "eventCount": 0,
160
+ "flowCount": 0,
161
+ "processorCount": 0,
162
+ "readModelCount": 0,
163
+ "scenarioCount": 0,
164
+ "screenCount": 0,
165
+ "sliceCount": 0
166
+ }
167
+ `;
168
+ export const SEARCH_HELP = `
169
+ ${envelope(`{
170
+ "elementId": "<uuid>",
171
+ "modelId": "<uuid>",
172
+ "elementType": "event" | "command" | "readmodel" | "screen"
173
+ | "processor" | "external-event" | "slice"
174
+ | "chapter" | "context" | "aggregate" | "actor",
175
+ "name": "OrderPlaced"
176
+ }`)}
177
+ `;
@@ -0,0 +1,39 @@
1
+ import { requireModelId } from '../lib/model';
2
+ import { unwrap, out } from '../lib/resolve';
3
+ import * as sdk from '../api/generated/sdk.gen';
4
+ import { LIST_SLICES_HELP, LIST_EVENTS_HELP, LIST_COMMANDS_HELP, LIST_READMODELS_HELP, LIST_SCREENS_HELP, LIST_PROCESSORS_HELP, LIST_EXTERNAL_EVENTS_HELP, LIST_AGGREGATES_HELP, LIST_ACTORS_HELP, LIST_CHAPTERS_HELP, LIST_CONTEXTS_HELP, LIST_SWIMLANES_HELP, LIST_NOTES_HELP, LIST_SCENARIOS_HELP, } from './list-schemas';
5
+ export function registerListCommands(program) {
6
+ const list = program.command('list').description('List entities in the model');
7
+ list.command('slices')
8
+ .description('List all slices')
9
+ .option('--chapter <name>', 'Filter by chapter')
10
+ .addHelpText('after', LIST_SLICES_HELP)
11
+ .action(async (opts) => {
12
+ const modelId = requireModelId();
13
+ out(unwrap(await sdk.listSlices({ path: { modelId }, query: { search: opts.chapter } })));
14
+ });
15
+ const entries = [
16
+ ['events', sdk.listEvents, LIST_EVENTS_HELP],
17
+ ['commands', sdk.listCommands, LIST_COMMANDS_HELP],
18
+ ['chapters', sdk.listChapters, LIST_CHAPTERS_HELP],
19
+ ['aggregates', sdk.listAggregates, LIST_AGGREGATES_HELP],
20
+ ['actors', sdk.listActors, LIST_ACTORS_HELP],
21
+ ['readmodels', sdk.listReadModels, LIST_READMODELS_HELP],
22
+ ['screens', sdk.listScreens, LIST_SCREENS_HELP],
23
+ ['processors', sdk.listProcessors, LIST_PROCESSORS_HELP],
24
+ ['scenarios', sdk.listScenarios, LIST_SCENARIOS_HELP],
25
+ ['contexts', sdk.listContexts, LIST_CONTEXTS_HELP],
26
+ ['swimlanes', sdk.listSwimLanes, LIST_SWIMLANES_HELP],
27
+ ['notes', sdk.listNotes, LIST_NOTES_HELP],
28
+ ['external-events', sdk.listExternalEvents, LIST_EXTERNAL_EVENTS_HELP],
29
+ ];
30
+ for (const [name, fn, help] of entries) {
31
+ list.command(name)
32
+ .description(`List all ${name}`)
33
+ .addHelpText('after', help)
34
+ .action(async () => {
35
+ const modelId = requireModelId();
36
+ out(unwrap(await fn({ path: { modelId } })));
37
+ });
38
+ }
39
+ }
@@ -0,0 +1,101 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { requireModelId } from '../lib/model';
3
+ import { loadLoopConfig } from '../lib/project-config';
4
+ import { unwrap } from '../lib/resolve';
5
+ import * as sdk from '../api/generated/sdk.gen';
6
+ export function registerLoopCommands(program) {
7
+ const loop = program.command('loop')
8
+ .description('Poll the model for planned slices and run a command against each')
9
+ .addHelpText('after', `
10
+ Config (.eventmodeler.json):
11
+ {
12
+ "loop": {
13
+ "command": "./run-agent.sh",
14
+ "interval": 30
15
+ }
16
+ }
17
+
18
+ How it works:
19
+ 1. Every <interval> seconds, fetch all slices
20
+ 2. For each slice with status "planned", run: <command> <sliceName>
21
+ 3. Repeat
22
+
23
+ Script contract:
24
+ Your script owns every status transition.
25
+ - Mark the slice "in-progress" at the start so the next poll skips it.
26
+ - Mark "done" on success or "blocked" on failure before exiting.
27
+ - If the script crashes without marking, the slice stays "planned"
28
+ and the next poll retries it (self-healing).
29
+
30
+ Inside your script:
31
+ SLICE="$1"
32
+ eventmodeler mark "$SLICE" in-progress
33
+ eventmodeler show slice "$SLICE" > slice.json
34
+ # ... do codegen / call an AI / run tests ...
35
+ eventmodeler mark "$SLICE" done # or: mark "$SLICE" blocked
36
+
37
+ Other valid commands: any shell-runnable invocation (python run.py,
38
+ node handler.js, claude -p '...'). The slice name is appended as the
39
+ final argument.
40
+
41
+ Stop the loop with Ctrl+C.
42
+ `);
43
+ loop.action(async () => {
44
+ const modelId = requireModelId();
45
+ const config = loadLoopConfig();
46
+ if (!config) {
47
+ console.error('Error: No "loop" config in .eventmodeler.json.');
48
+ console.error('Add: { "loop": { "command": "./your-script.sh", "interval": 30 } }');
49
+ process.exit(1);
50
+ }
51
+ const { command, interval } = config;
52
+ console.log(`Loop started. Polling every ${interval}s. Command: ${command}`);
53
+ console.log('Press Ctrl+C to stop.');
54
+ let stopping = false;
55
+ process.on('SIGINT', () => {
56
+ if (stopping)
57
+ process.exit(1);
58
+ stopping = true;
59
+ console.log('\nStopping after current iteration...');
60
+ });
61
+ while (!stopping) {
62
+ await tick(modelId, command);
63
+ if (stopping)
64
+ break;
65
+ await sleep(interval * 1000);
66
+ }
67
+ process.exit(0);
68
+ });
69
+ }
70
+ async function tick(modelId, command) {
71
+ const stamp = new Date().toISOString();
72
+ try {
73
+ const result = unwrap(await sdk.listSlices({ path: { modelId }, query: {} }));
74
+ const planned = result.items.filter((s) => s.status === 'planned');
75
+ if (planned.length === 0) {
76
+ console.log(`[${stamp}] No planned slices.`);
77
+ return;
78
+ }
79
+ console.log(`[${stamp}] ${planned.length} planned slice(s).`);
80
+ for (const slice of planned) {
81
+ console.log(` -> ${slice.name}`);
82
+ await runScript(command, slice.name);
83
+ }
84
+ }
85
+ catch (err) {
86
+ console.error(`[${stamp}] Poll error: ${err.message ?? err}`);
87
+ }
88
+ }
89
+ function runScript(command, sliceName) {
90
+ return new Promise((resolve) => {
91
+ const child = spawn(command, [sliceName], { stdio: 'inherit', shell: true });
92
+ child.on('close', () => resolve());
93
+ child.on('error', (err) => {
94
+ console.error(`Script error: ${err.message}`);
95
+ resolve();
96
+ });
97
+ });
98
+ }
99
+ function sleep(ms) {
100
+ return new Promise((resolve) => setTimeout(resolve, ms));
101
+ }
@@ -0,0 +1,40 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { requireModelId } from '../lib/model';
3
+ import { resolveAnyElement, unwrap } from '../lib/resolve';
4
+ import * as sdk from '../api/generated/sdk.gen';
5
+ export function registerMapCommands(program) {
6
+ program.command('map')
7
+ .description('Map fields between elements')
8
+ .command('fields <json>')
9
+ .description('Add field mappings to a flow')
10
+ .requiredOption('--from <source>', 'Source element name')
11
+ .requiredOption('--to <target>', 'Target element name')
12
+ .action(async (json, opts) => {
13
+ const modelId = requireModelId();
14
+ const { elementId: sourceId } = await resolveAnyElement(modelId, opts.from);
15
+ const { elementId: targetId } = await resolveAnyElement(modelId, opts.to);
16
+ const flowResult = unwrap(await sdk.resolveFlow({
17
+ query: { modelId, sourceId, targetId }
18
+ }));
19
+ const flowId = flowResult.flowId;
20
+ const mappings = JSON.parse(json);
21
+ for (const m of mappings) {
22
+ const sourceResolve = unwrap(await sdk.resolveField({
23
+ query: { modelId, elementId: sourceId, fieldName: m.source }
24
+ }));
25
+ const targetResolve = unwrap(await sdk.resolveField({
26
+ query: { modelId, elementId: targetId, fieldName: m.target }
27
+ }));
28
+ unwrap(await sdk.addFieldMapping({
29
+ body: {
30
+ modelId,
31
+ flowId,
32
+ mappingId: randomUUID(),
33
+ sourceFieldId: sourceResolve.fieldId,
34
+ targetFieldId: targetResolve.fieldId,
35
+ }
36
+ }));
37
+ }
38
+ console.log(`Added ${mappings.length} field mapping(s).`);
39
+ });
40
+ }
@@ -0,0 +1,27 @@
1
+ import { getGlobalId } from '../lib/globals';
2
+ import { requireModelId } from '../lib/model';
3
+ import { resolve, unwrap } from '../lib/resolve';
4
+ import * as sdk from '../api/generated/sdk.gen';
5
+ const STATUS_MAP = {
6
+ planned: sdk.markSliceAsPlanned,
7
+ created: sdk.markSliceAsCreated,
8
+ 'in-progress': sdk.markSliceAsInProgress,
9
+ blocked: sdk.markSliceAsBlocked,
10
+ done: sdk.markSliceAsDone,
11
+ };
12
+ export function registerMarkCommands(program) {
13
+ program.command('mark [sliceName] <status>')
14
+ .description('Mark a slice status (planned|created|in-progress|blocked|done)')
15
+ .action(async (sliceNameOrStatus, statusOrUndefined, cmd) => {
16
+ const modelId = requireModelId();
17
+ const hasId = getGlobalId();
18
+ const sliceName = statusOrUndefined ? sliceNameOrStatus : '';
19
+ const status = statusOrUndefined ?? sliceNameOrStatus;
20
+ const fn = STATUS_MAP[status];
21
+ if (!fn)
22
+ throw new Error(`Unknown status: ${status}. Valid: ${Object.keys(STATUS_MAP).join(', ')}`);
23
+ const sliceId = await resolve(modelId, 'slice', sliceName, hasId);
24
+ unwrap(await fn({ body: { modelId, sliceId } }));
25
+ console.log(`Marked slice as ${status}.`);
26
+ });
27
+ }
@@ -0,0 +1,35 @@
1
+ import { getGlobalId } from '../lib/globals';
2
+ import { requireModelId } from '../lib/model';
3
+ import { resolve, unwrap, elementIdKey } from '../lib/resolve';
4
+ import * as sdk from '../api/generated/sdk.gen';
5
+ const MOVE_MAP = {
6
+ slice: sdk.moveSlice,
7
+ command: sdk.moveCommandSticky,
8
+ event: sdk.moveEventSticky,
9
+ readmodel: sdk.moveReadModelSticky,
10
+ screen: sdk.moveScreen,
11
+ processor: sdk.moveProcessor,
12
+ aggregate: sdk.moveAggregate,
13
+ actor: sdk.moveActor,
14
+ chapter: sdk.moveChapter,
15
+ context: sdk.moveContext,
16
+ 'external-event': sdk.moveExternalEvent,
17
+ note: sdk.moveNote,
18
+ swimlane: sdk.moveSwimLane,
19
+ };
20
+ export function registerMoveCommands(program) {
21
+ program.command('move <type> [name]')
22
+ .description('Move an element to a new position')
23
+ .requiredOption('--x <n>', 'X coordinate', Number)
24
+ .requiredOption('--y <n>', 'Y coordinate', Number)
25
+ .action(async (type, name, opts, cmd) => {
26
+ const modelId = requireModelId();
27
+ const fn = MOVE_MAP[type];
28
+ if (!fn)
29
+ throw new Error(`Unknown type: ${type}. Valid types: ${Object.keys(MOVE_MAP).join(', ')}`);
30
+ const id = await resolve(modelId, type, name ?? '', getGlobalId());
31
+ const key = elementIdKey(type);
32
+ unwrap(await fn({ body: { modelId, [key]: id, x: opts.x, y: opts.y } }));
33
+ console.log(`Moved ${type} to (${opts.x}, ${opts.y}).`);
34
+ });
35
+ }
@@ -0,0 +1,170 @@
1
+ import { getGlobalId } from '../lib/globals';
2
+ import { requireModelId } from '../lib/model';
3
+ import { resolve, resolveAnyElement, unwrap, elementIdKey } from '../lib/resolve';
4
+ import { resolveScenarioId } from '../lib/scenario';
5
+ import * as sdk from '../api/generated/sdk.gen';
6
+ const REMOVE_MAP = {
7
+ slice: sdk.removeSlice,
8
+ command: sdk.removeCommandSticky,
9
+ event: sdk.removeEventSticky,
10
+ readmodel: sdk.removeReadModelSticky,
11
+ screen: sdk.removeScreen,
12
+ processor: sdk.removeProcessor,
13
+ aggregate: sdk.removeAggregate,
14
+ actor: sdk.removeActor,
15
+ chapter: sdk.removeChapter,
16
+ context: sdk.removeContext,
17
+ 'external-event': sdk.removeExternalEvent,
18
+ note: sdk.removeNote,
19
+ swimlane: sdk.removeSwimLane,
20
+ };
21
+ const REMOVE_FIELD_MAP = {
22
+ command: sdk.removeCommandField,
23
+ event: sdk.removeEventField,
24
+ readmodel: sdk.removeReadModelField,
25
+ screen: sdk.removeScreenField,
26
+ processor: sdk.removeProcessorField,
27
+ 'external-event': sdk.removeExternalEventField,
28
+ };
29
+ const REMOVE_SUBFIELD_MAP = {
30
+ command: sdk.removeCommandSubfield,
31
+ event: sdk.removeEventSubfield,
32
+ readmodel: sdk.removeReadModelSubfield,
33
+ screen: sdk.removeScreenSubfield,
34
+ processor: sdk.removeProcessorSubfield,
35
+ 'external-event': sdk.removeExternalEventSubfield,
36
+ };
37
+ export function registerRemoveCommands(program) {
38
+ const remove = program.command('remove').description('Remove elements from the model');
39
+ // remove <type> [name] — generic element removal
40
+ for (const [type, fn] of Object.entries(REMOVE_MAP)) {
41
+ if (type === 'scenario')
42
+ continue; // handled separately below
43
+ remove.command(`${type} [name]`)
44
+ .description(`Remove a ${type}`)
45
+ .action(async (name, cmd) => {
46
+ const modelId = requireModelId();
47
+ const id = await resolve(modelId, type, name ?? '', getGlobalId());
48
+ const key = elementIdKey(type);
49
+ unwrap(await fn({ body: { modelId, [key]: id } }));
50
+ console.log(`Removed ${type}.`);
51
+ });
52
+ }
53
+ // remove scenario [name]
54
+ remove.command('scenario [name]')
55
+ .description('Remove a scenario')
56
+ .action(async (name) => {
57
+ const modelId = requireModelId();
58
+ const scenarioId = await resolveScenarioId(modelId, name ?? '', getGlobalId());
59
+ unwrap(await sdk.removeScenario({ body: { modelId, scenarioId } }));
60
+ console.log('Removed scenario.');
61
+ });
62
+ // remove field <elementName> --field <name>
63
+ remove.command('field [elementName]')
64
+ .description('Remove a field from an element')
65
+ .requiredOption('--field <name>', 'Field name to remove')
66
+ .action(async (elementName, opts, cmd) => {
67
+ const modelId = requireModelId();
68
+ const { elementId, elementType } = await resolveAnyElement(modelId, elementName ?? '', getGlobalId());
69
+ const fn = REMOVE_FIELD_MAP[elementType];
70
+ if (!fn)
71
+ throw new Error(`Cannot remove fields from type: ${elementType}`);
72
+ const fieldResult = unwrap(await sdk.resolveField({
73
+ query: { modelId, elementId, fieldName: opts.field }
74
+ }));
75
+ const fieldId = fieldResult.fieldId;
76
+ const key = elementIdKey(elementType);
77
+ unwrap(await fn({ body: { modelId, [key]: elementId, fieldId } }));
78
+ console.log(`Removed field "${opts.field}".`);
79
+ });
80
+ // remove subfield [elementName] --subfield <subfieldId>
81
+ remove.command('subfield [elementName]')
82
+ .description('Remove a subfield from an element')
83
+ .requiredOption('--subfield <id>', 'Subfield ID (from show output)')
84
+ .action(async (elementName, opts, cmd) => {
85
+ const modelId = requireModelId();
86
+ const { elementId, elementType } = await resolveAnyElement(modelId, elementName ?? '', getGlobalId());
87
+ const fn = REMOVE_SUBFIELD_MAP[elementType];
88
+ if (!fn)
89
+ throw new Error(`Cannot remove subfields from type: ${elementType}`);
90
+ const key = elementIdKey(elementType);
91
+ unwrap(await fn({ body: { modelId, [key]: elementId, subfieldId: opts.subfield } }));
92
+ console.log('Removed subfield.');
93
+ });
94
+ // remove mapping --from <source> --to <target> --mapping <mappingId>
95
+ remove.command('mapping')
96
+ .description('Remove a field mapping from a flow')
97
+ .requiredOption('--from <source>', 'Source element name')
98
+ .requiredOption('--to <target>', 'Target element name')
99
+ .requiredOption('--mapping <id>', 'Mapping ID (from show output)')
100
+ .action(async (opts) => {
101
+ const modelId = requireModelId();
102
+ const { elementId: sourceId } = await resolveAnyElement(modelId, opts.from);
103
+ const { elementId: targetId } = await resolveAnyElement(modelId, opts.to);
104
+ const flowResult = unwrap(await sdk.resolveFlow({
105
+ query: { modelId, sourceId, targetId }
106
+ }));
107
+ const flowId = flowResult.flowId;
108
+ unwrap(await sdk.removeFieldMapping({ body: { modelId, flowId, mappingId: opts.mapping } }));
109
+ console.log('Removed field mapping.');
110
+ });
111
+ // remove entry --scenario <name> --section given|when|then --entry <entryId>
112
+ const REMOVE_ENTRY_MAP = {
113
+ given: sdk.removeScenarioGivenEntry,
114
+ when: sdk.removeScenarioWhenEntry,
115
+ then: sdk.removeScenarioThenEntry,
116
+ };
117
+ remove.command('entry')
118
+ .description('Remove a GWT entry from a scenario')
119
+ .requiredOption('--scenario <name>', 'Scenario name')
120
+ .requiredOption('--section <section>', 'Section: given, when, or then')
121
+ .requiredOption('--entry <entryId>', 'Entry ID (from show output)')
122
+ .action(async (opts) => {
123
+ const modelId = requireModelId();
124
+ const scenarioId = await resolveScenarioId(modelId, opts.scenario, getGlobalId());
125
+ const fn = REMOVE_ENTRY_MAP[opts.section];
126
+ if (!fn)
127
+ throw new Error(`Unknown section: ${opts.section}. Use given, when, or then.`);
128
+ unwrap(await fn({ body: { modelId, scenarioId, entryId: opts.entry } }));
129
+ console.log(`Removed ${opts.section} entry.`);
130
+ });
131
+ // remove example --scenario <name> --entry <entryId> --type event|command|readmodel --field <name>
132
+ const REMOVE_FIELD_VALUE_MAP = {
133
+ event: sdk.removeScenarioEventFieldValue,
134
+ command: sdk.removeScenarioCommandFieldValue,
135
+ readmodel: sdk.removeScenarioReadModelFieldValue,
136
+ };
137
+ remove.command('example')
138
+ .description('Remove a field example value from a scenario entry')
139
+ .requiredOption('--scenario <name>', 'Scenario name')
140
+ .requiredOption('--entry <entryId>', 'Entry ID (from show output)')
141
+ .requiredOption('--type <type>', 'Entry type: event, command, or readmodel')
142
+ .requiredOption('--field <name>', 'Field name to clear')
143
+ .action(async (opts) => {
144
+ const modelId = requireModelId();
145
+ const scenarioId = await resolveScenarioId(modelId, opts.scenario, getGlobalId());
146
+ const fn = REMOVE_FIELD_VALUE_MAP[opts.type];
147
+ if (!fn)
148
+ throw new Error(`Cannot remove examples from type: ${opts.type}. Use event, command, or readmodel.`);
149
+ unwrap(await fn({
150
+ body: { modelId, scenarioId, entryId: opts.entry, fieldName: opts.field }
151
+ }));
152
+ console.log(`Removed example "${opts.field}".`);
153
+ });
154
+ // remove flow --from <source> --to <target>
155
+ remove.command('flow')
156
+ .description('Remove a flow between two elements')
157
+ .requiredOption('--from <source>', 'Source element name')
158
+ .requiredOption('--to <target>', 'Target element name')
159
+ .action(async (opts) => {
160
+ const modelId = requireModelId();
161
+ const { elementId: sourceId } = await resolveAnyElement(modelId, opts.from);
162
+ const { elementId: targetId } = await resolveAnyElement(modelId, opts.to);
163
+ const flowResult = unwrap(await sdk.resolveFlow({
164
+ query: { modelId, sourceId, targetId }
165
+ }));
166
+ const flowId = flowResult.flowId;
167
+ unwrap(await sdk.removeFlow({ body: { modelId, flowId } }));
168
+ console.log('Removed flow.');
169
+ });
170
+ }
@@ -0,0 +1,53 @@
1
+ import { getGlobalId } from '../lib/globals';
2
+ import { requireModelId } from '../lib/model';
3
+ import { resolve, unwrap, elementIdKey } from '../lib/resolve';
4
+ import * as sdk from '../api/generated/sdk.gen';
5
+ const RENAME_MAP = {
6
+ slice: sdk.renameSlice,
7
+ command: sdk.renameCommandSticky,
8
+ event: sdk.renameEventSticky,
9
+ readmodel: sdk.renameReadModelSticky,
10
+ screen: sdk.renameScreen,
11
+ processor: sdk.renameProcessor,
12
+ aggregate: sdk.renameAggregate,
13
+ actor: sdk.renameActor,
14
+ chapter: sdk.renameChapter,
15
+ context: sdk.renameContext,
16
+ scenario: sdk.renameScenario,
17
+ 'external-event': sdk.renameExternalEvent,
18
+ note: sdk.renameNote,
19
+ swimlane: sdk.renameSwimLane,
20
+ };
21
+ export function registerRenameCommands(program) {
22
+ program.command('rename')
23
+ .description('Rename an element')
24
+ .argument('<type>', `Element type (${Object.keys(RENAME_MAP).join(', ')})`)
25
+ .argument('<names...>', 'Old name and new name (or just new name with --id)')
26
+ .action(async (type, names, _opts, cmd) => {
27
+ const modelId = requireModelId();
28
+ const fn = RENAME_MAP[type];
29
+ if (!fn)
30
+ throw new Error(`Unknown type: ${type}. Valid: ${Object.keys(RENAME_MAP).join(', ')}`);
31
+ const idOverride = getGlobalId();
32
+ let oldName;
33
+ let newName;
34
+ if (idOverride) {
35
+ // With --id, all positional args are the new name
36
+ newName = names.join(' ');
37
+ oldName = '';
38
+ }
39
+ else if (names.length >= 2) {
40
+ // Last arg is new name, rest is old name
41
+ newName = names[names.length - 1];
42
+ oldName = names.slice(0, -1).join(' ');
43
+ }
44
+ else {
45
+ console.error('Usage: eventmodeler rename <type> "Old Name" "New Name"');
46
+ console.error(' or: eventmodeler --id <uuid> rename <type> "New Name"');
47
+ process.exit(1);
48
+ }
49
+ const id = await resolve(modelId, type, oldName, idOverride);
50
+ unwrap(await fn({ body: { modelId, [elementIdKey(type)]: id, name: newName } }));
51
+ console.log(`Renamed ${type} to "${newName}"`);
52
+ });
53
+ }